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

Generated by: LCOV version 1.10

Generated at Wed, 24 Aug 2016 12:20:22 +0000 (37 hours ago)

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