PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/libxml - libxml.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 547 610 89.7 %
Date: 2022-01-18 Functions: 51 52 98.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2018 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Shane Caraveo <shane@php.net>                               |
      16             :    |          Wez Furlong <wez@thebrainroom.com>                          |
      17             :    +----------------------------------------------------------------------+
      18             :  */
      19             : 
      20             : #define IS_EXT_MODULE
      21             : 
      22             : #ifdef HAVE_CONFIG_H
      23             : #include "config.h"
      24             : #endif
      25             : 
      26             : #include "php.h"
      27             : #include "SAPI.h"
      28             : 
      29             : #define PHP_XML_INTERNAL
      30             : #include "zend_variables.h"
      31             : #include "ext/standard/php_string.h"
      32             : #include "ext/standard/info.h"
      33             : #include "ext/standard/file.h"
      34             : 
      35             : #if HAVE_LIBXML
      36             : 
      37             : #include <libxml/parser.h>
      38             : #include <libxml/parserInternals.h>
      39             : #include <libxml/tree.h>
      40             : #include <libxml/uri.h>
      41             : #include <libxml/xmlerror.h>
      42             : #include <libxml/xmlsave.h>
      43             : #ifdef LIBXML_SCHEMAS_ENABLED
      44             : #include <libxml/relaxng.h>
      45             : #include <libxml/xmlschemas.h>
      46             : #endif
      47             : 
      48             : #include "php_libxml.h"
      49             : 
      50             : #define PHP_LIBXML_ERROR 0
      51             : #define PHP_LIBXML_CTX_ERROR 1
      52             : #define PHP_LIBXML_CTX_WARNING 2
      53             : 
      54             : /* a true global for initialization */
      55             : static int _php_libxml_initialized = 0;
      56             : static int _php_libxml_per_request_initialization = 1;
      57             : static xmlExternalEntityLoader _php_libxml_default_entity_loader;
      58             : 
      59             : typedef struct _php_libxml_func_handler {
      60             :         php_libxml_export_node export_func;
      61             : } php_libxml_func_handler;
      62             : 
      63             : static HashTable php_libxml_exports;
      64             : 
      65             : static ZEND_DECLARE_MODULE_GLOBALS(libxml)
      66             : static PHP_GINIT_FUNCTION(libxml);
      67             : 
      68             : static PHP_FUNCTION(libxml_set_streams_context);
      69             : static PHP_FUNCTION(libxml_use_internal_errors);
      70             : static PHP_FUNCTION(libxml_get_last_error);
      71             : static PHP_FUNCTION(libxml_clear_errors);
      72             : static PHP_FUNCTION(libxml_get_errors);
      73             : static PHP_FUNCTION(libxml_set_external_entity_loader);
      74             : static PHP_FUNCTION(libxml_disable_entity_loader);
      75             : 
      76             : static zend_class_entry *libxmlerror_class_entry;
      77             : 
      78             : /* {{{ dynamically loadable module stuff */
      79             : #ifdef COMPILE_DL_LIBXML
      80             : #ifdef ZTS
      81             : ZEND_TSRMLS_CACHE_DEFINE()
      82             : #endif
      83             : ZEND_GET_MODULE(libxml)
      84             : #endif /* COMPILE_DL_LIBXML */
      85             : /* }}} */
      86             : 
      87             : /* {{{ function prototypes */
      88             : static PHP_MINIT_FUNCTION(libxml);
      89             : static PHP_RINIT_FUNCTION(libxml);
      90             : static PHP_RSHUTDOWN_FUNCTION(libxml);
      91             : static PHP_MSHUTDOWN_FUNCTION(libxml);
      92             : static PHP_MINFO_FUNCTION(libxml);
      93             : static int php_libxml_post_deactivate(void);
      94             : 
      95             : /* }}} */
      96             : 
      97             : /* {{{ arginfo */
      98             : ZEND_BEGIN_ARG_INFO(arginfo_libxml_set_streams_context, 0)
      99             :         ZEND_ARG_INFO(0, context)
     100             : ZEND_END_ARG_INFO()
     101             : 
     102             : ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_use_internal_errors, 0, 0, 0)
     103             :         ZEND_ARG_INFO(0, use_errors)
     104             : ZEND_END_ARG_INFO()
     105             : 
     106             : ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_last_error, 0)
     107             : ZEND_END_ARG_INFO()
     108             : 
     109             : ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_errors, 0)
     110             : ZEND_END_ARG_INFO()
     111             : 
     112             : ZEND_BEGIN_ARG_INFO(arginfo_libxml_clear_errors, 0)
     113             : ZEND_END_ARG_INFO()
     114             : 
     115             : ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_disable_entity_loader, 0, 0, 0)
     116             :         ZEND_ARG_INFO(0, disable)
     117             : ZEND_END_ARG_INFO()
     118             : 
     119             : ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_set_external_entity_loader, 0, 0, 1)
     120             :         ZEND_ARG_INFO(0, resolver_function)
     121             : ZEND_END_ARG_INFO()
     122             : /* }}} */
     123             : 
     124             : /* {{{ extension definition structures */
     125             : static const zend_function_entry libxml_functions[] = {
     126             :         PHP_FE(libxml_set_streams_context, arginfo_libxml_set_streams_context)
     127             :         PHP_FE(libxml_use_internal_errors, arginfo_libxml_use_internal_errors)
     128             :         PHP_FE(libxml_get_last_error, arginfo_libxml_get_last_error)
     129             :         PHP_FE(libxml_clear_errors, arginfo_libxml_clear_errors)
     130             :         PHP_FE(libxml_get_errors, arginfo_libxml_get_errors)
     131             :         PHP_FE(libxml_disable_entity_loader, arginfo_libxml_disable_entity_loader)
     132             :         PHP_FE(libxml_set_external_entity_loader, arginfo_libxml_set_external_entity_loader)
     133             :         PHP_FE_END
     134             : };
     135             : 
     136             : zend_module_entry libxml_module_entry = {
     137             :         STANDARD_MODULE_HEADER,
     138             :         "libxml",                /* extension name */
     139             :         libxml_functions,        /* extension function list */
     140             :         PHP_MINIT(libxml),       /* extension-wide startup function */
     141             :         PHP_MSHUTDOWN(libxml),   /* extension-wide shutdown function */
     142             :         PHP_RINIT(libxml),       /* per-request startup function */
     143             :         PHP_RSHUTDOWN(libxml),   /* per-request shutdown function */
     144             :         PHP_MINFO(libxml),       /* information function */
     145             :         PHP_LIBXML_VERSION,
     146             :         PHP_MODULE_GLOBALS(libxml), /* globals descriptor */
     147             :         PHP_GINIT(libxml),          /* globals ctor */
     148             :         NULL,                       /* globals dtor */
     149             :         php_libxml_post_deactivate, /* post deactivate */
     150             :         STANDARD_MODULE_PROPERTIES_EX
     151             : };
     152             : 
     153             : /* }}} */
     154             : 
     155             : /* {{{ internal functions for interoperability */
     156          30 : static int php_libxml_clear_object(php_libxml_node_object *object)
     157             : {
     158          30 :         if (object->properties) {
     159          28 :                 object->properties = NULL;
     160             :         }
     161          30 :         php_libxml_decrement_node_ptr(object);
     162          30 :         return php_libxml_decrement_doc_ref(object);
     163             : }
     164             : 
     165      561071 : static int php_libxml_unregister_node(xmlNodePtr nodep)
     166             : {
     167             :         php_libxml_node_object *wrapper;
     168             : 
     169      561071 :         php_libxml_node_ptr *nodeptr = nodep->_private;
     170             : 
     171      561071 :         if (nodeptr != NULL) {
     172          33 :                 wrapper = nodeptr->_private;
     173          33 :                 if (wrapper) {
     174          30 :                         php_libxml_clear_object(wrapper);
     175             :                 } else {
     176           3 :                         if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) {
     177           3 :                                 nodeptr->node->_private = NULL;
     178             :                         }
     179           3 :                         nodeptr->node = NULL;
     180             :                 }
     181             :         }
     182             : 
     183      561071 :         return -1;
     184             : }
     185             : 
     186      235104 : static void php_libxml_node_free(xmlNodePtr node)
     187             : {
     188      235104 :         if(node) {
     189      235104 :                 if (node->_private != NULL) {
     190           0 :                         ((php_libxml_node_ptr *) node->_private)->node = NULL;
     191             :                 }
     192      235104 :                 switch (node->type) {
     193          32 :                         case XML_ATTRIBUTE_NODE:
     194          32 :                                 xmlFreeProp((xmlAttrPtr) node);
     195          32 :                                 break;
     196           2 :                         case XML_ENTITY_DECL:
     197             :                         case XML_ELEMENT_DECL:
     198             :                         case XML_ATTRIBUTE_DECL:
     199           2 :                                 break;
     200           5 :                         case XML_NOTATION_NODE:
     201             :                                 /* These require special handling */
     202           5 :                                 if (node->name != NULL) {
     203           5 :                                         xmlFree((char *) node->name);
     204             :                                 }
     205           5 :                                 if (((xmlEntityPtr) node)->ExternalID != NULL) {
     206           5 :                                         xmlFree((char *) ((xmlEntityPtr) node)->ExternalID);
     207             :                                 }
     208           5 :                                 if (((xmlEntityPtr) node)->SystemID != NULL) {
     209           4 :                                         xmlFree((char *) ((xmlEntityPtr) node)->SystemID);
     210             :                                 }
     211           5 :                                 xmlFree(node);
     212           5 :                                 break;
     213           1 :                         case XML_NAMESPACE_DECL:
     214           1 :                                 if (node->ns) {
     215           1 :                                         xmlFreeNs(node->ns);
     216           1 :                                         node->ns = NULL;
     217             :                                 }
     218           1 :                                 node->type = XML_ELEMENT_NODE;
     219      235065 :                         default:
     220      235065 :                                 xmlFreeNode(node);
     221             :                 }
     222           0 :         }
     223      235104 : }
     224             : 
     225      357829 : PHP_LIBXML_API void php_libxml_node_free_list(xmlNodePtr node)
     226             : {
     227             :         xmlNodePtr curnode;
     228             : 
     229      357829 :         if (node != NULL) {
     230      122632 :                 curnode = node;
     231      480076 :                 while (curnode != NULL) {
     232      234812 :                         node = curnode;
     233      234812 :                         switch (node->type) {
     234             :                                 /* Skip property freeing for the following types */
     235           2 :                                 case XML_NOTATION_NODE:
     236             :                                 case XML_ENTITY_DECL:
     237           2 :                                         break;
     238           0 :                                 case XML_ENTITY_REF_NODE:
     239           0 :                                         php_libxml_node_free_list((xmlNodePtr) node->properties);
     240           0 :                                         break;
     241          18 :                                 case XML_ATTRIBUTE_NODE:
     242          18 :                                                 if ((node->doc != NULL) && (((xmlAttrPtr) node)->atype == XML_ATTRIBUTE_ID)) {
     243           1 :                                                         xmlRemoveID(node->doc, (xmlAttrPtr) node);
     244             :                                                 }
     245             :                                 case XML_ATTRIBUTE_DECL:
     246             :                                 case XML_DTD_NODE:
     247             :                                 case XML_DOCUMENT_TYPE_NODE:
     248             :                                 case XML_NAMESPACE_DECL:
     249             :                                 case XML_TEXT_NODE:
     250      112338 :                                         php_libxml_node_free_list(node->children);
     251      112338 :                                         break;
     252      122472 :                                 default:
     253      122472 :                                         php_libxml_node_free_list(node->children);
     254      122472 :                                         php_libxml_node_free_list((xmlNodePtr) node->properties);
     255             :                         }
     256             : 
     257      234812 :                         curnode = node->next;
     258      234812 :                         xmlUnlinkNode(node);
     259      234812 :                         if (php_libxml_unregister_node(node) == 0) {
     260           0 :                                 node->doc = NULL;
     261             :                         }
     262      234812 :                         php_libxml_node_free(node);
     263             :                 }
     264             :         }
     265      357829 : }
     266             : 
     267             : /* }}} */
     268             : 
     269             : /* {{{ startup, shutdown and info functions */
     270       26000 : static PHP_GINIT_FUNCTION(libxml)
     271             : {
     272             : #if defined(COMPILE_DL_LIBXML) && defined(ZTS)
     273             :         ZEND_TSRMLS_CACHE_UPDATE();
     274             : #endif
     275       26000 :         ZVAL_UNDEF(&libxml_globals->stream_context);
     276       26000 :         libxml_globals->error_buffer.s = NULL;
     277       26000 :         libxml_globals->error_list = NULL;
     278       26000 :         ZVAL_UNDEF(&libxml_globals->entity_loader.object);
     279       26000 :         libxml_globals->entity_loader.fci.size = 0;
     280       26000 :         libxml_globals->entity_loader_disabled = 0;
     281       26000 : }
     282             : 
     283       26006 : static void _php_libxml_destroy_fci(zend_fcall_info *fci, zval *object)
     284             : {
     285       26006 :         if (fci->size > 0) {
     286           5 :                 zval_ptr_dtor(&fci->function_name);
     287           5 :                 fci->size = 0;
     288             :         }
     289       26006 :         if (!Z_ISUNDEF_P(object)) {
     290           0 :                 zval_ptr_dtor(object);
     291           0 :                 ZVAL_UNDEF(object);
     292             :         }
     293       26006 : }
     294             : 
     295             : /* Channel libxml file io layer through the PHP streams subsystem.
     296             :  * This allows use of ftps:// and https:// urls */
     297             : 
     298        1015 : static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char *mode, const int read_only)
     299             : {
     300             :         php_stream_statbuf ssbuf;
     301        1015 :         php_stream_context *context = NULL;
     302        1015 :         php_stream_wrapper *wrapper = NULL;
     303             :         char *resolved_path;
     304        1015 :         const char *path_to_open = NULL;
     305        1015 :         void *ret_val = NULL;
     306        1015 :         int isescaped=0;
     307             :         xmlURI *uri;
     308             : 
     309             : 
     310        1015 :         uri = xmlParseURI(filename);
     311        1058 :         if (uri && (uri->scheme == NULL ||
     312          43 :                         (xmlStrncmp(BAD_CAST uri->scheme, BAD_CAST "file", 4) == 0))) {
     313         992 :                 resolved_path = xmlURIUnescapeString(filename, 0, NULL);
     314         992 :                 isescaped = 1;
     315             : #if LIBXML_VERSION >= 20902 && defined(PHP_WIN32)
     316             :                 /* Libxml 2.9.2 prefixes local paths with file:/ instead of file://,
     317             :                         thus the php stream wrapper will fail on a valid case. For this
     318             :                         reason the prefix is rather better cut off. */
     319             :                 {
     320             :                         size_t pre_len = sizeof("file:/") - 1;
     321             : 
     322             :                         if (strncasecmp(resolved_path, "file:/", pre_len) == 0
     323             :                                 && '/' != resolved_path[pre_len]) {
     324             :                                 xmlChar *tmp = xmlStrdup(resolved_path + pre_len);
     325             :                                 xmlFree(resolved_path);
     326             :                                 resolved_path = tmp;
     327             :                         }
     328             :                 }
     329             : #endif
     330             :         } else {
     331          23 :                 resolved_path = (char *)filename;
     332             :         }
     333             : 
     334        1015 :         if (uri) {
     335        1011 :                 xmlFreeURI(uri);
     336             :         }
     337             : 
     338        1015 :         if (resolved_path == NULL) {
     339           0 :                 return NULL;
     340             :         }
     341             : 
     342             :         /* logic copied from _php_stream_stat, but we only want to fail
     343             :            if the wrapper supports stat, otherwise, figure it out from
     344             :            the open.  This logic is only to support hiding warnings
     345             :            that the streams layer puts out at times, but for libxml we
     346             :            may try to open files that don't exist, but it is not a failure
     347             :            in xml processing (eg. DTD files)  */
     348        1015 :         wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, 0);
     349        1015 :         if (wrapper && read_only && wrapper->wops->url_stat) {
     350         975 :                 if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL) == -1) {
     351          27 :                         if (isescaped) {
     352          26 :                                 xmlFree(resolved_path);
     353             :                         }
     354          27 :                         return NULL;
     355             :                 }
     356             :         }
     357             : 
     358        1736 :         context = php_stream_context_from_zval(Z_ISUNDEF(LIBXML(stream_context))? NULL : &LIBXML(stream_context), 0);
     359             : 
     360         988 :         ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, REPORT_ERRORS, NULL, context);
     361         988 :         if (ret_val) {
     362             :                 /* Prevent from closing this by fclose() */
     363         982 :                 ((php_stream*)ret_val)->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
     364             :         }
     365         988 :         if (isescaped) {
     366         966 :                 xmlFree(resolved_path);
     367             :         }
     368         988 :         return ret_val;
     369             : }
     370             : 
     371         989 : static void *php_libxml_streams_IO_open_read_wrapper(const char *filename)
     372             : {
     373         989 :         return php_libxml_streams_IO_open_wrapper(filename, "rb", 1);
     374             : }
     375             : 
     376          26 : static void *php_libxml_streams_IO_open_write_wrapper(const char *filename)
     377             : {
     378          26 :         return php_libxml_streams_IO_open_wrapper(filename, "wb", 0);
     379             : }
     380             : 
     381        3790 : static int php_libxml_streams_IO_read(void *context, char *buffer, int len)
     382             : {
     383        3790 :         return php_stream_read((php_stream*)context, buffer, len);
     384             : }
     385             : 
     386          46 : static int php_libxml_streams_IO_write(void *context, const char *buffer, int len)
     387             : {
     388          46 :         return php_stream_write((php_stream*)context, buffer, len);
     389             : }
     390             : 
     391         985 : static int php_libxml_streams_IO_close(void *context)
     392             : {
     393         985 :         return php_stream_close((php_stream*)context);
     394             : }
     395             : 
     396             : static xmlParserInputBufferPtr
     397         990 : php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
     398             : {
     399             :         xmlParserInputBufferPtr ret;
     400         990 :         void *context = NULL;
     401             : 
     402         990 :         if (LIBXML(entity_loader_disabled)) {
     403           1 :                 return NULL;
     404             :         }
     405             : 
     406         989 :         if (URI == NULL)
     407           0 :                 return(NULL);
     408             : 
     409         989 :         context = php_libxml_streams_IO_open_read_wrapper(URI);
     410             : 
     411         989 :         if (context == NULL) {
     412          32 :                 return(NULL);
     413             :         }
     414             : 
     415             :         /* Allocate the Input buffer front-end. */
     416         957 :         ret = xmlAllocParserInputBuffer(enc);
     417         957 :         if (ret != NULL) {
     418         957 :                 ret->context = context;
     419         957 :                 ret->readcallback = php_libxml_streams_IO_read;
     420         957 :                 ret->closecallback = php_libxml_streams_IO_close;
     421             :         } else
     422           0 :                 php_libxml_streams_IO_close(context);
     423             : 
     424         957 :         return(ret);
     425             : }
     426             : 
     427             : static xmlOutputBufferPtr
     428          26 : php_libxml_output_buffer_create_filename(const char *URI,
     429             :                               xmlCharEncodingHandlerPtr encoder,
     430             :                               int compression ATTRIBUTE_UNUSED)
     431             : {
     432             :         xmlOutputBufferPtr ret;
     433             :         xmlURIPtr puri;
     434          26 :         void *context = NULL;
     435          26 :         char *unescaped = NULL;
     436             : 
     437          26 :         if (URI == NULL)
     438           0 :                 return(NULL);
     439             : 
     440          26 :         puri = xmlParseURI(URI);
     441          26 :         if (puri != NULL) {
     442          25 :                 if (puri->scheme != NULL)
     443           3 :                         unescaped = xmlURIUnescapeString(URI, 0, NULL);
     444          25 :                 xmlFreeURI(puri);
     445             :         }
     446             : 
     447          26 :         if (unescaped != NULL) {
     448           3 :                 context = php_libxml_streams_IO_open_write_wrapper(unescaped);
     449           3 :                 xmlFree(unescaped);
     450             :         }
     451             : 
     452             :         /* try with a non-escaped URI this may be a strange filename */
     453          26 :         if (context == NULL) {
     454          23 :                 context = php_libxml_streams_IO_open_write_wrapper(URI);
     455             :         }
     456             : 
     457          26 :         if (context == NULL) {
     458           1 :                 return(NULL);
     459             :         }
     460             : 
     461             :         /* Allocate the Output buffer front-end. */
     462          25 :         ret = xmlAllocOutputBuffer(encoder);
     463          25 :         if (ret != NULL) {
     464          25 :                 ret->context = context;
     465          25 :                 ret->writecallback = php_libxml_streams_IO_write;
     466          25 :                 ret->closecallback = php_libxml_streams_IO_close;
     467             :         }
     468             : 
     469          25 :         return(ret);
     470             : }
     471             : 
     472           3 : static int _php_libxml_free_error(xmlErrorPtr error)
     473             : {
     474             :         /* This will free the libxml alloc'd memory */
     475           3 :         xmlResetError(error);
     476           3 :         return 1;
     477             : }
     478             : 
     479           3 : static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
     480             : {
     481             :         xmlError error_copy;
     482             :         int ret;
     483             : 
     484             : 
     485           3 :         memset(&error_copy, 0, sizeof(xmlError));
     486             : 
     487           3 :         if (error) {
     488           3 :                 ret = xmlCopyError(error, &error_copy);
     489             :         } else {
     490           0 :                 error_copy.domain = 0;
     491           0 :                 error_copy.code = XML_ERR_INTERNAL_ERROR;
     492           0 :                 error_copy.level = XML_ERR_ERROR;
     493           0 :                 error_copy.line = 0;
     494           0 :                 error_copy.node = NULL;
     495           0 :                 error_copy.int1 = 0;
     496           0 :                 error_copy.int2 = 0;
     497           0 :                 error_copy.ctxt = NULL;
     498           0 :                 error_copy.message = (char*)xmlStrdup((xmlChar*)msg);
     499           0 :                 error_copy.file = NULL;
     500           0 :                 error_copy.str1 = NULL;
     501           0 :                 error_copy.str2 = NULL;
     502           0 :                 error_copy.str3 = NULL;
     503           0 :                 ret = 0;
     504             :         }
     505             : 
     506           3 :         if (ret == 0) {
     507           3 :                 zend_llist_add_element(LIBXML(error_list), &error_copy);
     508             :         }
     509           3 : }
     510             : 
     511          36 : static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg)
     512             : {
     513             :         xmlParserCtxtPtr parser;
     514             : 
     515          36 :         parser = (xmlParserCtxtPtr) ctx;
     516             : 
     517          36 :         if (parser != NULL && parser->input != NULL) {
     518          34 :                 if (parser->input->filename) {
     519          13 :                         php_error_docref(NULL, level, "%s in %s, line: %d", msg, parser->input->filename, parser->input->line);
     520             :                 } else {
     521          21 :                         php_error_docref(NULL, level, "%s in Entity, line: %d", msg, parser->input->line);
     522             :                 }
     523             :         }
     524          36 : }
     525             : 
     526           9 : void php_libxml_issue_error(int level, const char *msg)
     527             : {
     528           9 :         if (LIBXML(error_list)) {
     529           0 :                 _php_list_set_error_structure(NULL, msg);
     530             :         } else {
     531           9 :                 php_error_docref(NULL, level, "%s", msg);
     532             :         }
     533           9 : }
     534             : 
     535         182 : static void php_libxml_internal_error_handler(int error_type, void *ctx, const char **msg, va_list ap)
     536             : {
     537             :         char *buf;
     538         182 :         int len, len_iter, output = 0;
     539             : 
     540             : 
     541         182 :         len = vspprintf(&buf, 0, *msg, ap);
     542         182 :         len_iter = len;
     543             : 
     544             :         /* remove any trailing \n */
     545         497 :         while (len_iter && buf[--len_iter] == '\n') {
     546         133 :                 buf[len_iter] = '\0';
     547         133 :                 output = 1;
     548             :         }
     549             : 
     550         182 :         smart_str_appendl(&LIBXML(error_buffer), buf, len);
     551             : 
     552         182 :         efree(buf);
     553             : 
     554         182 :         if (output == 1) {
     555         133 :                 if (LIBXML(error_list)) {
     556           0 :                         _php_list_set_error_structure(NULL, ZSTR_VAL(LIBXML(error_buffer).s));
     557             :                 } else {
     558         133 :                         switch (error_type) {
     559          36 :                                 case PHP_LIBXML_CTX_ERROR:
     560          36 :                                         php_libxml_ctx_error_level(E_WARNING, ctx, ZSTR_VAL(LIBXML(error_buffer).s));
     561          36 :                                         break;
     562           0 :                                 case PHP_LIBXML_CTX_WARNING:
     563           0 :                                         php_libxml_ctx_error_level(E_NOTICE, ctx, ZSTR_VAL(LIBXML(error_buffer).s));
     564           0 :                                         break;
     565          97 :                                 default:
     566          97 :                                         php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(LIBXML(error_buffer).s));
     567             :                         }
     568             :                 }
     569             :                 smart_str_free(&LIBXML(error_buffer));
     570             :         }
     571         182 : }
     572             : 
     573         962 : static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL,
     574             :                 const char *ID, xmlParserCtxtPtr context)
     575             : {
     576         962 :         xmlParserInputPtr       ret                     = NULL;
     577         962 :         const char                      *resource       = NULL;
     578             :         zval                            *ctxzv, retval;
     579             :         zval                            params[3];
     580             :         int                                     status;
     581             :         zend_fcall_info         *fci;
     582             : 
     583         962 :         fci = &LIBXML(entity_loader).fci;
     584             : 
     585         962 :         if (fci->size == 0) {
     586             :                 /* no custom user-land callback set up; delegate to original loader */
     587         956 :                 return _php_libxml_default_entity_loader(URL, ID, context);
     588             :         }
     589             : 
     590           6 :         if (ID != NULL) {
     591          10 :                 ZVAL_STRING(&params[0], ID);
     592             :         } else {
     593           1 :                 ZVAL_NULL(&params[0]);
     594             :         }
     595           6 :         if (URL != NULL) {
     596          12 :                 ZVAL_STRING(&params[1], URL);
     597             :         } else {
     598           0 :                 ZVAL_NULL(&params[1]);
     599             :         }
     600           6 :         ctxzv = &params[2];
     601           6 :         array_init_size(ctxzv, 4);
     602             : 
     603             : #define ADD_NULL_OR_STRING_KEY(memb) \
     604             :         if (context->memb == NULL) { \
     605             :                 add_assoc_null_ex(ctxzv, #memb, sizeof(#memb) - 1); \
     606             :         } else { \
     607             :                 add_assoc_string_ex(ctxzv, #memb, sizeof(#memb) - 1, \
     608             :                                 (char *)context->memb); \
     609             :         }
     610             : 
     611           6 :         ADD_NULL_OR_STRING_KEY(directory)
     612           6 :         ADD_NULL_OR_STRING_KEY(intSubName)
     613           6 :         ADD_NULL_OR_STRING_KEY(extSubURI)
     614           6 :         ADD_NULL_OR_STRING_KEY(extSubSystem)
     615             : 
     616             : #undef ADD_NULL_OR_STRING_KEY
     617             : 
     618           6 :         fci->retval  = &retval;
     619           6 :         fci->params  = params;
     620           6 :         fci->param_count = sizeof(params)/sizeof(*params);
     621           6 :         fci->no_separation   = 1;
     622             : 
     623           6 :         status = zend_call_function(fci, &LIBXML(entity_loader).fcc);
     624          10 :         if (status != SUCCESS || Z_ISUNDEF(retval)) {
     625           1 :                 php_libxml_ctx_error(context,
     626             :                                 "Call to user entity loader callback '%s' has failed",
     627           1 :                                 Z_STRVAL(fci->function_name));
     628             :         } else {
     629             :                 /*
     630             :                 retval_ptr = *fci->retval_ptr_ptr;
     631             :                 if (retval_ptr == NULL) {
     632             :                         php_libxml_ctx_error(context,
     633             :                                         "Call to user entity loader callback '%s' has failed; "
     634             :                                         "probably it has thrown an exception",
     635             :                                         fci->function_name);
     636           4 :                 } else */ if (Z_TYPE(retval) == IS_STRING) {
     637           0 : is_string:
     638           0 :                         resource = Z_STRVAL(retval);
     639           4 :                 } else if (Z_TYPE(retval) == IS_RESOURCE) {
     640             :                         php_stream *stream;
     641           3 :                         php_stream_from_zval_no_verify(stream, &retval);
     642           3 :                         if (stream == NULL) {
     643           0 :                                 php_libxml_ctx_error(context,
     644             :                                                 "The user entity loader callback '%s' has returned a "
     645             :                                                 "resource, but it is not a stream",
     646           0 :                                                 Z_STRVAL(fci->function_name));
     647             :                         } else {
     648             :                                 /* TODO: allow storing the encoding in the stream context? */
     649           3 :                                 xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
     650           3 :                                 xmlParserInputBufferPtr pib = xmlAllocParserInputBuffer(enc);
     651           3 :                                 if (pib == NULL) {
     652           0 :                                         php_libxml_ctx_error(context, "Could not allocate parser "
     653             :                                                         "input buffer");
     654             :                                 } else {
     655             :                                         /* make stream not being closed when the zval is freed */
     656           3 :                                         GC_ADDREF(stream->res);
     657           3 :                                         pib->context = stream;
     658           3 :                                         pib->readcallback = php_libxml_streams_IO_read;
     659           3 :                                         pib->closecallback = php_libxml_streams_IO_close;
     660             : 
     661           3 :                                         ret = xmlNewIOInputStream(context, pib, enc);
     662           3 :                                         if (ret == NULL) {
     663           0 :                                                 xmlFreeParserInputBuffer(pib);
     664             :                                         }
     665             :                                 }
     666             :                         }
     667           1 :                 } else if (Z_TYPE(retval) != IS_NULL) {
     668             :                         /* retval not string nor resource nor null; convert to string */
     669           0 :                         convert_to_string(&retval);
     670           0 :                         goto is_string;
     671             :                 } /* else is null; don't try anything */
     672             :         }
     673             : 
     674           5 :         if (ret == NULL) {
     675           2 :                 if (resource == NULL) {
     676           2 :                         if (ID == NULL) {
     677           0 :                                 ID = "NULL";
     678             :                         }
     679           2 :                         php_libxml_ctx_error(context,
     680             :                                         "Failed to load external entity \"%s\"\n", ID);
     681             :                 } else {
     682             :                         /* we got the resource in the form of a string; open it */
     683           0 :                         ret = xmlNewInputFromFile(context, resource);
     684             :                 }
     685             :         }
     686             : 
     687           5 :         zval_ptr_dtor(&params[0]);
     688           5 :         zval_ptr_dtor(&params[1]);
     689           5 :         zval_ptr_dtor(&params[2]);
     690           5 :         zval_ptr_dtor(&retval);
     691           5 :         return ret;
     692             : }
     693             : 
     694         962 : static xmlParserInputPtr _php_libxml_pre_ext_ent_loader(const char *URL,
     695             :                 const char *ID, xmlParserCtxtPtr context)
     696             : {
     697             : 
     698             :         /* Check whether we're running in a PHP context, since the entity loader
     699             :          * we've defined is an application level (true global) setting.
     700             :          * If we are, we also want to check whether we've finished activating
     701             :          * the modules (RINIT phase). Using our external entity loader during a
     702             :          * RINIT should not be problem per se (though during MINIT it is, because
     703             :          * we don't even have a resource list by then), but then whether one
     704             :          * extension would be using the custom external entity loader or not
     705             :          * could depend on extension loading order
     706             :          * (if _php_libxml_per_request_initialization */
     707         962 :         if (xmlGenericError == php_libxml_error_handler && PG(modules_activated)) {
     708         962 :                 return _php_libxml_external_entity_loader(URL, ID, context);
     709             :         } else {
     710           0 :                 return _php_libxml_default_entity_loader(URL, ID, context);
     711             :         }
     712             : }
     713             : 
     714          37 : PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...)
     715             : {
     716             :         va_list args;
     717          37 :         va_start(args, msg);
     718          37 :         php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args);
     719          37 :         va_end(args);
     720          37 : }
     721             : 
     722           0 : PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
     723             : {
     724             :         va_list args;
     725           0 :         va_start(args, msg);
     726           0 :         php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args);
     727           0 :         va_end(args);
     728           0 : }
     729             : 
     730           3 : PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
     731             : {
     732           3 :         _php_list_set_error_structure(error, NULL);
     733             : 
     734           3 :         return;
     735             : }
     736             : 
     737         145 : PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...)
     738             : {
     739             :         va_list args;
     740         145 :         va_start(args, msg);
     741         145 :         php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args);
     742         145 :         va_end(args);
     743         145 : }
     744             : 
     745       52122 : static void php_libxml_exports_dtor(zval *zv)
     746             : {
     747       52122 :         free(Z_PTR_P(zv));
     748       52122 : }
     749             : 
     750       78000 : PHP_LIBXML_API void php_libxml_initialize(void)
     751             : {
     752       78000 :         if (!_php_libxml_initialized) {
     753             :                 /* we should be the only one's to ever init!! */
     754       26000 :                 xmlInitParser();
     755             : 
     756       26000 :                 _php_libxml_default_entity_loader = xmlGetExternalEntityLoader();
     757       26000 :                 xmlSetExternalEntityLoader(_php_libxml_pre_ext_ent_loader);
     758             : 
     759       26000 :                 zend_hash_init(&php_libxml_exports, 0, NULL, php_libxml_exports_dtor, 1);
     760             : 
     761       26000 :                 _php_libxml_initialized = 1;
     762             :         }
     763       78000 : }
     764             : 
     765       26061 : PHP_LIBXML_API void php_libxml_shutdown(void)
     766             : {
     767       26061 :         if (_php_libxml_initialized) {
     768             : #if defined(LIBXML_SCHEMAS_ENABLED)
     769       26061 :                 xmlRelaxNGCleanupTypes();
     770             : #endif
     771             :                 /* xmlCleanupParser(); */
     772       26061 :                 zend_hash_destroy(&php_libxml_exports);
     773             : 
     774       26061 :                 xmlSetExternalEntityLoader(_php_libxml_default_entity_loader);
     775       26061 :                 _php_libxml_initialized = 0;
     776             :         }
     777       26061 : }
     778             : 
     779        1431 : PHP_LIBXML_API void php_libxml_switch_context(zval *context, zval *oldcontext)
     780             : {
     781        1431 :         if (oldcontext) {
     782         720 :                 ZVAL_COPY_VALUE(oldcontext, &LIBXML(stream_context));
     783             :         }
     784        1431 :         if (context) {
     785        1431 :                 ZVAL_COPY_VALUE(&LIBXML(stream_context), context);
     786             :         }
     787        1431 : }
     788             : 
     789       26000 : static PHP_MINIT_FUNCTION(libxml)
     790             : {
     791             :         zend_class_entry ce;
     792             : 
     793       26000 :         php_libxml_initialize();
     794             : 
     795       26000 :         REGISTER_LONG_CONSTANT("LIBXML_VERSION",                      LIBXML_VERSION,                 CONST_CS | CONST_PERSISTENT);
     796       26000 :         REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION",     LIBXML_DOTTED_VERSION,  CONST_CS | CONST_PERSISTENT);
     797       26000 :         REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION",     (char *)xmlParserVersion,               CONST_CS | CONST_PERSISTENT);
     798             : 
     799             :         /* For use with loading xml */
     800       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NOENT",                XML_PARSE_NOENT,                CONST_CS | CONST_PERSISTENT);
     801       26000 :         REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD",      XML_PARSE_DTDLOAD,              CONST_CS | CONST_PERSISTENT);
     802       26000 :         REGISTER_LONG_CONSTANT("LIBXML_DTDATTR",      XML_PARSE_DTDATTR,              CONST_CS | CONST_PERSISTENT);
     803       26000 :         REGISTER_LONG_CONSTANT("LIBXML_DTDVALID",     XML_PARSE_DTDVALID,             CONST_CS | CONST_PERSISTENT);
     804       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NOERROR",      XML_PARSE_NOERROR,              CONST_CS | CONST_PERSISTENT);
     805       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NOWARNING",    XML_PARSE_NOWARNING,    CONST_CS | CONST_PERSISTENT);
     806       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS",     XML_PARSE_NOBLANKS,             CONST_CS | CONST_PERSISTENT);
     807       26000 :         REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE",     XML_PARSE_XINCLUDE,             CONST_CS | CONST_PERSISTENT);
     808       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN",      XML_PARSE_NSCLEAN,              CONST_CS | CONST_PERSISTENT);
     809       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NOCDATA",      XML_PARSE_NOCDATA,              CONST_CS | CONST_PERSISTENT);
     810       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NONET",                XML_PARSE_NONET,                CONST_CS | CONST_PERSISTENT);
     811       26000 :         REGISTER_LONG_CONSTANT("LIBXML_PEDANTIC",     XML_PARSE_PEDANTIC,             CONST_CS | CONST_PERSISTENT);
     812             : #if LIBXML_VERSION >= 20621
     813       26000 :         REGISTER_LONG_CONSTANT("LIBXML_COMPACT",      XML_PARSE_COMPACT,              CONST_CS | CONST_PERSISTENT);
     814       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL",    XML_SAVE_NO_DECL,               CONST_CS | CONST_PERSISTENT);
     815             : #endif
     816             : #if LIBXML_VERSION >= 20703
     817       26000 :         REGISTER_LONG_CONSTANT("LIBXML_PARSEHUGE",    XML_PARSE_HUGE,                 CONST_CS | CONST_PERSISTENT);
     818             : #endif
     819             : #if LIBXML_VERSION >= 20900
     820             :         REGISTER_LONG_CONSTANT("LIBXML_BIGLINES",     XML_PARSE_BIG_LINES,    CONST_CS | CONST_PERSISTENT);
     821             : #endif
     822       26000 :         REGISTER_LONG_CONSTANT("LIBXML_NOEMPTYTAG",   LIBXML_SAVE_NOEMPTYTAG, CONST_CS | CONST_PERSISTENT);
     823             : 
     824             :         /* Schema validation options */
     825             : #if defined(LIBXML_SCHEMAS_ENABLED) && LIBXML_VERSION >= 20614
     826       26000 :         REGISTER_LONG_CONSTANT("LIBXML_SCHEMA_CREATE",        XML_SCHEMA_VAL_VC_I_CREATE,     CONST_CS | CONST_PERSISTENT);
     827             : #endif
     828             : 
     829             :         /* Additional constants for use with loading html */
     830             : #if LIBXML_VERSION >= 20707
     831             :         REGISTER_LONG_CONSTANT("LIBXML_HTML_NOIMPLIED",       HTML_PARSE_NOIMPLIED,           CONST_CS | CONST_PERSISTENT);
     832             : #endif
     833             : 
     834             : #if LIBXML_VERSION >= 20708
     835             :         REGISTER_LONG_CONSTANT("LIBXML_HTML_NODEFDTD",        HTML_PARSE_NODEFDTD,            CONST_CS | CONST_PERSISTENT);
     836             : #endif
     837             : 
     838             :         /* Error levels */
     839       26000 :         REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE",             XML_ERR_NONE,           CONST_CS | CONST_PERSISTENT);
     840       26000 :         REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING",  XML_ERR_WARNING,        CONST_CS | CONST_PERSISTENT);
     841       26000 :         REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR",            XML_ERR_ERROR,          CONST_CS | CONST_PERSISTENT);
     842       26000 :         REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL",            XML_ERR_FATAL,          CONST_CS | CONST_PERSISTENT);
     843             : 
     844       26000 :         INIT_CLASS_ENTRY(ce, "LibXMLError", NULL);
     845       26000 :         libxmlerror_class_entry = zend_register_internal_class(&ce);
     846             : 
     847       26000 :         if (sapi_module.name) {
     848             :                 static const char * const supported_sapis[] = {
     849             :                         "cgi-fcgi",
     850             :                         "litespeed",
     851             :                         NULL
     852             :                 };
     853             :                 const char * const *sapi_name;
     854             : 
     855       77160 :                 for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
     856       51580 :                         if (strcmp(sapi_module.name, *sapi_name) == 0) {
     857         420 :                                 _php_libxml_per_request_initialization = 0;
     858         420 :                                 break;
     859             :                         }
     860             :                 }
     861             :         }
     862             : 
     863       26000 :         if (!_php_libxml_per_request_initialization) {
     864             :                 /* report errors via handler rather than stderr */
     865         420 :                 xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
     866         420 :                 xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
     867         420 :                 xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
     868             :         }
     869             : 
     870       26000 :         return SUCCESS;
     871             : }
     872             : 
     873             : 
     874       25936 : static PHP_RINIT_FUNCTION(libxml)
     875             : {
     876       25936 :         if (_php_libxml_per_request_initialization) {
     877             :                 /* report errors via handler rather than stderr */
     878       25517 :                 xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
     879       25517 :                 xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
     880       25517 :                 xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
     881             :         }
     882             : 
     883             :         /* Enable the entity loader by default. This ensures that
     884             :          * other threads/requests that might have disabled the loader
     885             :          * do not affect the current request.
     886             :          */
     887       25936 :         LIBXML(entity_loader_disabled) = 0;
     888             : 
     889       25936 :         return SUCCESS;
     890             : }
     891             : 
     892       26000 : static PHP_RSHUTDOWN_FUNCTION(libxml)
     893             : {
     894       26000 :         _php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
     895             : 
     896       26000 :         return SUCCESS;
     897             : }
     898             : 
     899       26061 : static PHP_MSHUTDOWN_FUNCTION(libxml)
     900             : {
     901       26061 :         if (!_php_libxml_per_request_initialization) {
     902         417 :                 xmlSetGenericErrorFunc(NULL, NULL);
     903             : 
     904         417 :                 xmlParserInputBufferCreateFilenameDefault(NULL);
     905         417 :                 xmlOutputBufferCreateFilenameDefault(NULL);
     906             :         }
     907       26061 :         php_libxml_shutdown();
     908             : 
     909       26061 :         return SUCCESS;
     910             : }
     911             : 
     912       26000 : static int php_libxml_post_deactivate(void)
     913             : {
     914             :         /* reset libxml generic error handling */
     915       26000 :         if (_php_libxml_per_request_initialization) {
     916       25584 :                 xmlSetGenericErrorFunc(NULL, NULL);
     917             : 
     918       25584 :                 xmlParserInputBufferCreateFilenameDefault(NULL);
     919       25584 :                 xmlOutputBufferCreateFilenameDefault(NULL);
     920             :         }
     921       26000 :         xmlSetStructuredErrorFunc(NULL, NULL);
     922             : 
     923             :         /* the steam_context resource will be released by resource list destructor */
     924       26000 :         ZVAL_UNDEF(&LIBXML(stream_context));
     925             :         smart_str_free(&LIBXML(error_buffer));
     926       26000 :         if (LIBXML(error_list)) {
     927           2 :                 zend_llist_destroy(LIBXML(error_list));
     928           2 :                 efree(LIBXML(error_list));
     929           2 :                 LIBXML(error_list) = NULL;
     930             :         }
     931       26000 :         xmlResetLastError();
     932             : 
     933       26000 :         return SUCCESS;
     934             : }
     935             : 
     936             : 
     937         149 : static PHP_MINFO_FUNCTION(libxml)
     938             : {
     939         149 :         php_info_print_table_start();
     940         149 :         php_info_print_table_row(2, "libXML support", "active");
     941         149 :         php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION);
     942         149 :         php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion);
     943         149 :         php_info_print_table_row(2, "libXML streams", "enabled");
     944         149 :         php_info_print_table_end();
     945         149 : }
     946             : /* }}} */
     947             : 
     948             : /* {{{ proto void libxml_set_streams_context(resource streams_context)
     949             :    Set the streams context for the next libxml document load or write */
     950          11 : static PHP_FUNCTION(libxml_set_streams_context)
     951             : {
     952             :         zval *arg;
     953             : 
     954          11 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     955          22 :                 Z_PARAM_RESOURCE(arg)
     956          17 :         ZEND_PARSE_PARAMETERS_END();
     957             : 
     958           5 :         if (!Z_ISUNDEF(LIBXML(stream_context))) {
     959           2 :                 zval_ptr_dtor(&LIBXML(stream_context));
     960           2 :                 ZVAL_UNDEF(&LIBXML(stream_context));
     961             :         }
     962           5 :         ZVAL_COPY(&LIBXML(stream_context), arg);
     963             : }
     964             : /* }}} */
     965             : 
     966             : /* {{{ proto bool libxml_use_internal_errors([boolean use_errors])
     967             :    Disable libxml errors and allow user to fetch error information as needed */
     968          15 : static PHP_FUNCTION(libxml_use_internal_errors)
     969             : {
     970             :         xmlStructuredErrorFunc current_handler;
     971          15 :         zend_bool use_errors=0, retval;
     972             : 
     973          15 :         ZEND_PARSE_PARAMETERS_START(0, 1)
     974          15 :                 Z_PARAM_OPTIONAL
     975          29 :                 Z_PARAM_BOOL(use_errors)
     976          15 :         ZEND_PARSE_PARAMETERS_END();
     977             : 
     978          14 :         current_handler = xmlStructuredError;
     979          14 :         if (current_handler && current_handler == php_libxml_structured_error_handler) {
     980           6 :                 retval = 1;
     981             :         } else {
     982           8 :                 retval = 0;
     983             :         }
     984             : 
     985          14 :         if (ZEND_NUM_ARGS() == 0) {
     986           1 :                 RETURN_BOOL(retval);
     987             :         }
     988             : 
     989          13 :         if (use_errors == 0) {
     990           6 :                 xmlSetStructuredErrorFunc(NULL, NULL);
     991           6 :                 if (LIBXML(error_list)) {
     992           5 :                         zend_llist_destroy(LIBXML(error_list));
     993           5 :                         efree(LIBXML(error_list));
     994           5 :                         LIBXML(error_list) = NULL;
     995             :                 }
     996             :         } else {
     997           7 :                 xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
     998           7 :                 if (LIBXML(error_list) == NULL) {
     999           7 :                         LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist));
    1000           7 :                         zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0);
    1001             :                 }
    1002             :         }
    1003          13 :         RETURN_BOOL(retval);
    1004             : }
    1005             : /* }}} */
    1006             : 
    1007             : /* {{{ proto object libxml_get_last_error()
    1008             :    Retrieve last error from libxml */
    1009           2 : static PHP_FUNCTION(libxml_get_last_error)
    1010             : {
    1011             :         xmlErrorPtr error;
    1012             : 
    1013           2 :         error = xmlGetLastError();
    1014             : 
    1015           2 :         if (error) {
    1016           1 :                 object_init_ex(return_value, libxmlerror_class_entry);
    1017           1 :                 add_property_long(return_value, "level", error->level);
    1018           1 :                 add_property_long(return_value, "code", error->code);
    1019           1 :                 add_property_long(return_value, "column", error->int2);
    1020           1 :                 if (error->message) {
    1021           1 :                         add_property_string(return_value, "message", error->message);
    1022             :                 } else {
    1023           0 :                         add_property_stringl(return_value, "message", "", 0);
    1024             :                 }
    1025           1 :                 if (error->file) {
    1026           0 :                         add_property_string(return_value, "file", error->file);
    1027             :                 } else {
    1028           1 :                         add_property_stringl(return_value, "file", "", 0);
    1029             :                 }
    1030           1 :                 add_property_long(return_value, "line", error->line);
    1031             :         } else {
    1032           1 :                 RETURN_FALSE;
    1033             :         }
    1034             : }
    1035             : /* }}} */
    1036             : 
    1037             : /* {{{ proto object libxml_get_errors()
    1038             :    Retrieve array of errors */
    1039           4 : static PHP_FUNCTION(libxml_get_errors)
    1040             : {
    1041             : 
    1042             :         xmlErrorPtr error;
    1043             : 
    1044           4 :         if (LIBXML(error_list)) {
    1045             : 
    1046           3 :                 array_init(return_value);
    1047           3 :                 error = zend_llist_get_first(LIBXML(error_list));
    1048             : 
    1049           8 :                 while (error != NULL) {
    1050             :                         zval z_error;
    1051             : 
    1052           2 :                         object_init_ex(&z_error, libxmlerror_class_entry);
    1053           2 :                         add_property_long_ex(&z_error, "level", sizeof("level") - 1, error->level);
    1054           2 :                         add_property_long_ex(&z_error, "code", sizeof("code") - 1, error->code);
    1055           2 :                         add_property_long_ex(&z_error, "column", sizeof("column") - 1, error->int2 );
    1056           2 :                         if (error->message) {
    1057           2 :                                 add_property_string_ex(&z_error, "message", sizeof("message") - 1, error->message);
    1058             :                         } else {
    1059           0 :                                 add_property_stringl_ex(&z_error, "message", sizeof("message") - 1, "", 0);
    1060             :                         }
    1061           2 :                         if (error->file) {
    1062           1 :                                 add_property_string_ex(&z_error, "file", sizeof("file") - 1, error->file);
    1063             :                         } else {
    1064           1 :                                 add_property_stringl_ex(&z_error, "file", sizeof("file") - 1, "", 0);
    1065             :                         }
    1066           2 :                         add_property_long_ex(&z_error, "line", sizeof("line") - 1, error->line);
    1067           2 :                         add_next_index_zval(return_value, &z_error);
    1068             : 
    1069           2 :                         error = zend_llist_get_next(LIBXML(error_list));
    1070             :                 }
    1071             :         } else {
    1072           1 :                 ZVAL_EMPTY_ARRAY(return_value);
    1073             :         }
    1074           4 : }
    1075             : /* }}} */
    1076             : 
    1077             : /* {{{ proto void libxml_clear_errors()
    1078             :    Clear last error from libxml */
    1079           6 : static PHP_FUNCTION(libxml_clear_errors)
    1080             : {
    1081           6 :         xmlResetLastError();
    1082           6 :         if (LIBXML(error_list)) {
    1083           5 :                 zend_llist_clean(LIBXML(error_list));
    1084             :         }
    1085           6 : }
    1086             : /* }}} */
    1087             : 
    1088        2593 : PHP_LIBXML_API zend_bool php_libxml_disable_entity_loader(zend_bool disable) /* {{{ */
    1089             : {
    1090        2593 :         zend_bool old = LIBXML(entity_loader_disabled);
    1091             : 
    1092        2593 :         LIBXML(entity_loader_disabled) = disable;
    1093        2593 :         return old;
    1094             : } /* }}} */
    1095             : 
    1096             : /* {{{ proto bool libxml_disable_entity_loader([boolean disable])
    1097             :    Disable/Enable ability to load external entities */
    1098           1 : static PHP_FUNCTION(libxml_disable_entity_loader)
    1099             : {
    1100           1 :         zend_bool disable = 1;
    1101             : 
    1102           1 :         ZEND_PARSE_PARAMETERS_START(0, 1)
    1103           1 :                 Z_PARAM_OPTIONAL
    1104           2 :                 Z_PARAM_BOOL(disable)
    1105           1 :         ZEND_PARSE_PARAMETERS_END();
    1106             : 
    1107           1 :         RETURN_BOOL(php_libxml_disable_entity_loader(disable));
    1108             : }
    1109             : /* }}} */
    1110             : 
    1111             : /* {{{ proto void libxml_set_external_entity_loader(callback resolver_function)
    1112             :    Changes the default external entity loader */
    1113           9 : static PHP_FUNCTION(libxml_set_external_entity_loader)
    1114             : {
    1115             :         zend_fcall_info                 fci;
    1116             :         zend_fcall_info_cache   fcc;
    1117             : 
    1118           9 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1119          14 :                 Z_PARAM_FUNC_EX(fci, fcc, 1, 0)
    1120           9 :         ZEND_PARSE_PARAMETERS_END();
    1121             : 
    1122           6 :         _php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
    1123             : 
    1124           6 :         if (fci.size > 0) { /* argument not null */
    1125           5 :                 LIBXML(entity_loader).fci = fci;
    1126             :                 Z_ADDREF(fci.function_name);
    1127           5 :                 if (fci.object != NULL) {
    1128           0 :                         ZVAL_OBJ(&LIBXML(entity_loader).object, fci.object);
    1129             :                         Z_ADDREF(LIBXML(entity_loader).object);
    1130             :                 }
    1131           5 :                 LIBXML(entity_loader).fcc = fcc;
    1132             :         }
    1133             : 
    1134           6 :         RETURN_TRUE;
    1135             : }
    1136             : /* }}} */
    1137             : 
    1138             : /* {{{ Common functions shared by extensions */
    1139         814 : int php_libxml_xmlCheckUTF8(const unsigned char *s)
    1140             : {
    1141             :         int i;
    1142             :         unsigned char c;
    1143             : 
    1144        9372 :         for (i = 0; (c = s[i++]);) {
    1145        7745 :                 if ((c & 0x80) == 0) {
    1146         157 :                 } else if ((c & 0xe0) == 0xc0) {
    1147         156 :                         if ((s[i++] & 0xc0) != 0x80) {
    1148           0 :                                 return 0;
    1149             :                         }
    1150           1 :                 } else if ((c & 0xf0) == 0xe0) {
    1151           0 :                         if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
    1152           0 :                                 return 0;
    1153             :                         }
    1154           1 :                 } else if ((c & 0xf8) == 0xf0) {
    1155           0 :                         if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
    1156           0 :                                 return 0;
    1157             :                         }
    1158             :                 } else {
    1159           1 :                         return 0;
    1160             :                 }
    1161             :         }
    1162         813 :         return 1;
    1163             : }
    1164             : 
    1165       52000 : zval *php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function)
    1166             : {
    1167             :         php_libxml_func_handler export_hnd;
    1168             : 
    1169             :         /* Initialize in case this module hasn't been loaded yet */
    1170       52000 :         php_libxml_initialize();
    1171       52000 :         export_hnd.export_func = export_function;
    1172             : 
    1173      104000 :         return zend_hash_add_mem(&php_libxml_exports, ce->name, &export_hnd, sizeof(export_hnd));
    1174             : }
    1175             : 
    1176         119 : PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object)
    1177             : {
    1178         119 :         zend_class_entry *ce = NULL;
    1179         119 :         xmlNodePtr node = NULL;
    1180             :         php_libxml_func_handler *export_hnd;
    1181             : 
    1182         119 :         if (Z_TYPE_P(object) == IS_OBJECT) {
    1183         119 :                 ce = Z_OBJCE_P(object);
    1184         355 :                 while (ce->parent != NULL) {
    1185         117 :                         ce = ce->parent;
    1186             :                 }
    1187         238 :                 if ((export_hnd = zend_hash_find_ptr(&php_libxml_exports, ce->name))) {
    1188         119 :                         node = export_hnd->export_func(object);
    1189             :                 }
    1190             :         }
    1191         119 :         return node;
    1192             : }
    1193             : 
    1194      527632 : PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data)
    1195             : {
    1196      527632 :         int ret_refcount = -1;
    1197             : 
    1198      527632 :         if (object != NULL && node != NULL) {
    1199      527629 :                 if (object->node != NULL) {
    1200           0 :                         if (object->node->node == node) {
    1201           0 :                                 return object->node->refcount;
    1202             :                         } else {
    1203           0 :                                 php_libxml_decrement_node_ptr(object);
    1204             :                         }
    1205             :                 }
    1206      527629 :                 if (node->_private != NULL) {
    1207      200669 :                         object->node = node->_private;
    1208      200669 :                         ret_refcount = ++object->node->refcount;
    1209             :                         /* Only dom uses _private */
    1210      200669 :                         if (object->node->_private == NULL) {
    1211      200669 :                                 object->node->_private = private_data;
    1212             :                         }
    1213             :                 } else {
    1214      326960 :                         ret_refcount = 1;
    1215      326960 :                         object->node = emalloc(sizeof(php_libxml_node_ptr));
    1216      326960 :                         object->node->node = node;
    1217      326960 :                         object->node->refcount = 1;
    1218      326960 :                         object->node->_private = private_data;
    1219      326960 :                         node->_private = object->node;
    1220             :                 }
    1221             :         }
    1222             : 
    1223      527632 :         return ret_refcount;
    1224             : }
    1225             : 
    1226      527629 : PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object)
    1227             : {
    1228      527629 :         int ret_refcount = -1;
    1229             :         php_libxml_node_ptr *obj_node;
    1230             : 
    1231      527629 :         if (object != NULL && object->node != NULL) {
    1232      527629 :                 obj_node = (php_libxml_node_ptr *) object->node;
    1233      527629 :                 ret_refcount = --obj_node->refcount;
    1234      527629 :                 if (ret_refcount == 0) {
    1235      326960 :                         if (obj_node->node != NULL) {
    1236      326957 :                                 obj_node->node->_private = NULL;
    1237             :                         }
    1238      326960 :                         efree(obj_node);
    1239             :                 }
    1240      527629 :                 object->node = NULL;
    1241             :         }
    1242             : 
    1243      527629 :         return ret_refcount;
    1244             : }
    1245             : 
    1246      126288 : PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp)
    1247             : {
    1248      126288 :         int ret_refcount = -1;
    1249             : 
    1250      126288 :         if (object->document != NULL) {
    1251      123403 :                 object->document->refcount++;
    1252      123403 :                 ret_refcount = object->document->refcount;
    1253        2885 :         } else if (docp != NULL) {
    1254        2885 :                 ret_refcount = 1;
    1255        2885 :                 object->document = emalloc(sizeof(php_libxml_ref_obj));
    1256        2885 :                 object->document->ptr = docp;
    1257        2885 :                 object->document->refcount = ret_refcount;
    1258        2885 :                 object->document->doc_props = NULL;
    1259             :         }
    1260             : 
    1261      126288 :         return ret_refcount;
    1262             : }
    1263             : 
    1264      527912 : PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object)
    1265             : {
    1266      527912 :         int ret_refcount = -1;
    1267             : 
    1268      527912 :         if (object != NULL && object->document != NULL) {
    1269      527685 :                 ret_refcount = --object->document->refcount;
    1270      527685 :                 if (ret_refcount == 0) {
    1271        2885 :                         if (object->document->ptr != NULL) {
    1272        2885 :                                 xmlFreeDoc((xmlDoc *) object->document->ptr);
    1273             :                         }
    1274        2885 :                         if (object->document->doc_props != NULL) {
    1275         378 :                                 if (object->document->doc_props->classmap) {
    1276           2 :                                         zend_hash_destroy(object->document->doc_props->classmap);
    1277           2 :                                         FREE_HASHTABLE(object->document->doc_props->classmap);
    1278             :                                 }
    1279         378 :                                 efree(object->document->doc_props);
    1280             :                         }
    1281        2885 :                         efree(object->document);
    1282             :                 }
    1283      527685 :                 object->document = NULL;
    1284             :         }
    1285             : 
    1286      527912 :         return ret_refcount;
    1287             : }
    1288             : 
    1289      326262 : PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node)
    1290             : {
    1291      326262 :         if (!node) {
    1292           3 :                 return;
    1293             :         }
    1294             : 
    1295      326259 :         switch (node->type) {
    1296           0 :                 case XML_DOCUMENT_NODE:
    1297             :                 case XML_HTML_DOCUMENT_NODE:
    1298           0 :                         break;
    1299      326259 :                 default:
    1300      326259 :                         if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) {
    1301         292 :                                 php_libxml_node_free_list((xmlNodePtr) node->children);
    1302         292 :                                 switch (node->type) {
    1303             :                                         /* Skip property freeing for the following types */
    1304          58 :                                         case XML_ATTRIBUTE_DECL:
    1305             :                                         case XML_DTD_NODE:
    1306             :                                         case XML_DOCUMENT_TYPE_NODE:
    1307             :                                         case XML_ENTITY_DECL:
    1308             :                                         case XML_ATTRIBUTE_NODE:
    1309             :                                         case XML_NAMESPACE_DECL:
    1310             :                                         case XML_TEXT_NODE:
    1311          58 :                                                 break;
    1312         234 :                                         default:
    1313         234 :                                                 php_libxml_node_free_list((xmlNodePtr) node->properties);
    1314             :                                 }
    1315         292 :                                 if (php_libxml_unregister_node(node) == 0) {
    1316           0 :                                         node->doc = NULL;
    1317             :                                 }
    1318         292 :                                 php_libxml_node_free(node);
    1319             :                         } else {
    1320      325967 :                                 php_libxml_unregister_node(node);
    1321             :                         }
    1322             :         }
    1323             : }
    1324             : 
    1325      526888 : PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object)
    1326             : {
    1327      526888 :         int ret_refcount = -1;
    1328             :         xmlNodePtr nodep;
    1329             :         php_libxml_node_ptr *obj_node;
    1330             : 
    1331      526888 :         if (object != NULL && object->node != NULL) {
    1332      526884 :                 obj_node = (php_libxml_node_ptr *) object->node;
    1333      526884 :                 nodep = object->node->node;
    1334      526884 :                 ret_refcount = php_libxml_decrement_node_ptr(object);
    1335      526884 :                 if (ret_refcount == 0) {
    1336      326215 :                         php_libxml_node_free_resource(nodep);
    1337             :                 } else {
    1338      200669 :                         if (obj_node && object == obj_node->_private) {
    1339           1 :                                 obj_node->_private = NULL;
    1340             :                         }
    1341             :                 }
    1342             :         }
    1343      526888 :         if (object != NULL && object->document != NULL) {
    1344             :                 /* Safe to call as if the resource were freed then doc pointer is NULL */
    1345      526860 :                 php_libxml_decrement_doc_ref(object);
    1346             :         }
    1347      526888 : }
    1348             : /* }}} */
    1349             : 
    1350             : #if defined(PHP_WIN32) && defined(COMPILE_DL_LIBXML)
    1351             : PHP_LIBXML_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    1352             : {
    1353             :         return xmlDllMain(hinstDLL, fdwReason, lpvReserved);
    1354             : }
    1355             : #endif
    1356             : 
    1357             : #endif
    1358             : 
    1359             : /*
    1360             :  * Local variables:
    1361             :  * tab-width: 4
    1362             :  * c-basic-offset: 4
    1363             :  * End:
    1364             :  * vim600: sw=4 ts=4 fdm=marker
    1365             :  * vim<600: sw=4 ts=4
    1366             :  */

Generated by: LCOV version 1.10

Generated at Wed, 19 Jan 2022 00:14:13 +0000 (3 days ago)

Copyright © 2005-2022 The PHP Group
All rights reserved.