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: 546 610 89.5 %
Date: 2019-05-06 Functions: 51 52 98.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 06 May 2019 17:58:17 +0000 (992 days ago)

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