root/ext/libxml/libxml.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_libxml_clear_object
  2. php_libxml_unregister_node
  3. php_libxml_node_free
  4. php_libxml_node_free_list
  5. PHP_GINIT_FUNCTION
  6. _php_libxml_destroy_fci
  7. php_libxml_streams_IO_open_wrapper
  8. php_libxml_streams_IO_open_read_wrapper
  9. php_libxml_streams_IO_open_write_wrapper
  10. php_libxml_streams_IO_read
  11. php_libxml_streams_IO_write
  12. php_libxml_streams_IO_close
  13. php_libxml_input_buffer_create_filename
  14. php_libxml_output_buffer_create_filename
  15. _php_libxml_free_error
  16. _php_list_set_error_structure
  17. php_libxml_ctx_error_level
  18. php_libxml_issue_error
  19. php_libxml_internal_error_handler
  20. _php_libxml_external_entity_loader
  21. _php_libxml_pre_ext_ent_loader
  22. php_libxml_ctx_error
  23. php_libxml_ctx_warning
  24. php_libxml_structured_error_handler
  25. php_libxml_error_handler
  26. php_libxml_exports_dtor
  27. php_libxml_initialize
  28. php_libxml_shutdown
  29. php_libxml_switch_context
  30. PHP_MINIT_FUNCTION
  31. PHP_RINIT_FUNCTION
  32. PHP_RSHUTDOWN_FUNCTION
  33. PHP_MSHUTDOWN_FUNCTION
  34. php_libxml_post_deactivate
  35. PHP_MINFO_FUNCTION
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. PHP_FUNCTION
  41. php_libxml_disable_entity_loader
  42. PHP_FUNCTION
  43. PHP_FUNCTION
  44. php_libxml_xmlCheckUTF8
  45. php_libxml_register_export
  46. php_libxml_import_node
  47. php_libxml_increment_node_ptr
  48. php_libxml_decrement_node_ptr
  49. php_libxml_increment_doc_ref
  50. php_libxml_decrement_doc_ref
  51. php_libxml_node_free_resource
  52. php_libxml_node_decrement_resource
  53. DllMain

   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 static int php_libxml_clear_object(php_libxml_node_object *object)
 159 {
 160         if (object->properties) {
 161                 object->properties = NULL;
 162         }
 163         php_libxml_decrement_node_ptr(object);
 164         return php_libxml_decrement_doc_ref(object);
 165 }
 166 
 167 static int php_libxml_unregister_node(xmlNodePtr nodep)
 168 {
 169         php_libxml_node_object *wrapper;
 170 
 171         php_libxml_node_ptr *nodeptr = nodep->_private;
 172 
 173         if (nodeptr != NULL) {
 174                 wrapper = nodeptr->_private;
 175                 if (wrapper) {
 176                         php_libxml_clear_object(wrapper);
 177                 } else {
 178                         if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) {
 179                                 nodeptr->node->_private = NULL;
 180                         }
 181                         nodeptr->node = NULL;
 182                 }
 183         }
 184 
 185         return -1;
 186 }
 187 
 188 static void php_libxml_node_free(xmlNodePtr node)
 189 {
 190         if(node) {
 191                 if (node->_private != NULL) {
 192                         ((php_libxml_node_ptr *) node->_private)->node = NULL;
 193                 }
 194                 switch (node->type) {
 195                         case XML_ATTRIBUTE_NODE:
 196                                 xmlFreeProp((xmlAttrPtr) node);
 197                                 break;
 198                         case XML_ENTITY_DECL:
 199                         case XML_ELEMENT_DECL:
 200                         case XML_ATTRIBUTE_DECL:
 201                                 break;
 202                         case XML_NOTATION_NODE:
 203                                 /* These require special handling */
 204                                 if (node->name != NULL) {
 205                                         xmlFree((char *) node->name);
 206                                 }
 207                                 if (((xmlEntityPtr) node)->ExternalID != NULL) {
 208                                         xmlFree((char *) ((xmlEntityPtr) node)->ExternalID);
 209                                 }
 210                                 if (((xmlEntityPtr) node)->SystemID != NULL) {
 211                                         xmlFree((char *) ((xmlEntityPtr) node)->SystemID);
 212                                 }
 213                                 xmlFree(node);
 214                                 break;
 215                         case XML_NAMESPACE_DECL:
 216                                 if (node->ns) {
 217                                         xmlFreeNs(node->ns);
 218                                         node->ns = NULL;
 219                                 }
 220                                 node->type = XML_ELEMENT_NODE;
 221                         default:
 222                                 xmlFreeNode(node);
 223                 }
 224         }
 225 }
 226 
 227 static void php_libxml_node_free_list(xmlNodePtr node)
 228 {
 229         xmlNodePtr curnode;
 230 
 231         if (node != NULL) {
 232                 curnode = node;
 233                 while (curnode != NULL) {
 234                         node = curnode;
 235                         switch (node->type) {
 236                                 /* Skip property freeing for the following types */
 237                                 case XML_NOTATION_NODE:
 238                                 case XML_ENTITY_DECL:
 239                                         break;
 240                                 case XML_ENTITY_REF_NODE:
 241                                         php_libxml_node_free_list((xmlNodePtr) node->properties);
 242                                         break;
 243                                 case XML_ATTRIBUTE_NODE:
 244                                                 if ((node->doc != NULL) && (((xmlAttrPtr) node)->atype == XML_ATTRIBUTE_ID)) {
 245                                                         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                                         php_libxml_node_free_list(node->children);
 253                                         break;
 254                                 default:
 255                                         php_libxml_node_free_list(node->children);
 256                                         php_libxml_node_free_list((xmlNodePtr) node->properties);
 257                         }
 258 
 259                         curnode = node->next;
 260                         xmlUnlinkNode(node);
 261                         if (php_libxml_unregister_node(node) == 0) {
 262                                 node->doc = NULL;
 263                         }
 264                         php_libxml_node_free(node);
 265                 }
 266         }
 267 }
 268 
 269 /* }}} */
 270 
 271 /* {{{ startup, shutdown and info functions */
 272 static PHP_GINIT_FUNCTION(libxml)
 273 {
 274 #if defined(COMPILE_DL_LIBXML) && defined(ZTS)
 275         ZEND_TSRMLS_CACHE_UPDATE();
 276 #endif
 277         ZVAL_UNDEF(&libxml_globals->stream_context);
 278         libxml_globals->error_buffer.s = NULL;
 279         libxml_globals->error_list = NULL;
 280         ZVAL_UNDEF(&libxml_globals->entity_loader.object);
 281         libxml_globals->entity_loader.fci.size = 0;
 282         libxml_globals->entity_loader_disabled = 0;
 283 }
 284 
 285 static void _php_libxml_destroy_fci(zend_fcall_info *fci, zval *object)
 286 {
 287         if (fci->size > 0) {
 288                 zval_ptr_dtor(&fci->function_name);
 289                 fci->size = 0;
 290         }
 291         if (!Z_ISUNDEF_P(object)) {
 292                 zval_ptr_dtor(object);
 293                 ZVAL_UNDEF(object);
 294         }
 295 }
 296 
 297 /* Channel libxml file io layer through the PHP streams subsystem.
 298  * This allows use of ftps:// and https:// urls */
 299 
 300 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         php_stream_context *context = NULL;
 304         php_stream_wrapper *wrapper = NULL;
 305         char *resolved_path;
 306         const char *path_to_open = NULL;
 307         void *ret_val = NULL;
 308         int isescaped=0;
 309         xmlURI *uri;
 310 
 311 
 312         uri = xmlParseURI(filename);
 313         if (uri && (uri->scheme == NULL ||
 314                         (xmlStrncmp(BAD_CAST uri->scheme, BAD_CAST "file", 4) == 0))) {
 315                 resolved_path = xmlURIUnescapeString(filename, 0, NULL);
 316                 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                 resolved_path = (char *)filename;
 334         }
 335 
 336         if (uri) {
 337                 xmlFreeURI(uri);
 338         }
 339 
 340         if (resolved_path == NULL) {
 341                 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         wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, 0);
 351         if (wrapper && read_only && wrapper->wops->url_stat) {
 352                 if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL) == -1) {
 353                         if (isescaped) {
 354                                 xmlFree(resolved_path);
 355                         }
 356                         return NULL;
 357                 }
 358         }
 359 
 360         context = php_stream_context_from_zval(Z_ISUNDEF(LIBXML(stream_context))? NULL : &LIBXML(stream_context), 0);
 361 
 362         ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, REPORT_ERRORS, NULL, context);
 363         if (isescaped) {
 364                 xmlFree(resolved_path);
 365         }
 366         return ret_val;
 367 }
 368 
 369 static void *php_libxml_streams_IO_open_read_wrapper(const char *filename)
 370 {
 371         return php_libxml_streams_IO_open_wrapper(filename, "rb", 1);
 372 }
 373 
 374 static void *php_libxml_streams_IO_open_write_wrapper(const char *filename)
 375 {
 376         return php_libxml_streams_IO_open_wrapper(filename, "wb", 0);
 377 }
 378 
 379 static int php_libxml_streams_IO_read(void *context, char *buffer, int len)
 380 {
 381         return php_stream_read((php_stream*)context, buffer, len);
 382 }
 383 
 384 static int php_libxml_streams_IO_write(void *context, const char *buffer, int len)
 385 {
 386         if (CG(unclean_shutdown)) {
 387                 return -1;
 388         }
 389         return php_stream_write((php_stream*)context, buffer, len);
 390 }
 391 
 392 static int php_libxml_streams_IO_close(void *context)
 393 {
 394         return php_stream_close((php_stream*)context);
 395 }
 396 
 397 static xmlParserInputBufferPtr
 398 php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
 399 {
 400         xmlParserInputBufferPtr ret;
 401         void *context = NULL;
 402 
 403         if (LIBXML(entity_loader_disabled)) {
 404                 return NULL;
 405         }
 406 
 407         if (URI == NULL)
 408                 return(NULL);
 409 
 410         context = php_libxml_streams_IO_open_read_wrapper(URI);
 411 
 412         if (context == NULL) {
 413                 return(NULL);
 414         }
 415 
 416         /* Allocate the Input buffer front-end. */
 417         ret = xmlAllocParserInputBuffer(enc);
 418         if (ret != NULL) {
 419                 ret->context = context;
 420                 ret->readcallback = php_libxml_streams_IO_read;
 421                 ret->closecallback = php_libxml_streams_IO_close;
 422         } else
 423                 php_libxml_streams_IO_close(context);
 424 
 425         return(ret);
 426 }
 427 
 428 static xmlOutputBufferPtr
 429 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         void *context = NULL;
 436         char *unescaped = NULL;
 437 
 438         if (URI == NULL)
 439                 return(NULL);
 440 
 441         puri = xmlParseURI(URI);
 442         if (puri != NULL) {
 443                 if (puri->scheme != NULL)
 444                         unescaped = xmlURIUnescapeString(URI, 0, NULL);
 445                 xmlFreeURI(puri);
 446         }
 447 
 448         if (unescaped != NULL) {
 449                 context = php_libxml_streams_IO_open_write_wrapper(unescaped);
 450                 xmlFree(unescaped);
 451         }
 452 
 453         /* try with a non-escaped URI this may be a strange filename */
 454         if (context == NULL) {
 455                 context = php_libxml_streams_IO_open_write_wrapper(URI);
 456         }
 457 
 458         if (context == NULL) {
 459                 return(NULL);
 460         }
 461 
 462         /* Allocate the Output buffer front-end. */
 463         ret = xmlAllocOutputBuffer(encoder);
 464         if (ret != NULL) {
 465                 ret->context = context;
 466                 ret->writecallback = php_libxml_streams_IO_write;
 467                 ret->closecallback = php_libxml_streams_IO_close;
 468         }
 469 
 470         return(ret);
 471 }
 472 
 473 static int _php_libxml_free_error(xmlErrorPtr error)
 474 {
 475         /* This will free the libxml alloc'd memory */
 476         xmlResetError(error);
 477         return 1;
 478 }
 479 
 480 static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
 481 {
 482         xmlError error_copy;
 483         int ret;
 484 
 485 
 486         memset(&error_copy, 0, sizeof(xmlError));
 487 
 488         if (error) {
 489                 ret = xmlCopyError(error, &error_copy);
 490         } else {
 491                 error_copy.domain = 0;
 492                 error_copy.code = XML_ERR_INTERNAL_ERROR;
 493                 error_copy.level = XML_ERR_ERROR;
 494                 error_copy.line = 0;
 495                 error_copy.node = NULL;
 496                 error_copy.int1 = 0;
 497                 error_copy.int2 = 0;
 498                 error_copy.ctxt = NULL;
 499                 error_copy.message = (char*)xmlStrdup((xmlChar*)msg);
 500                 error_copy.file = NULL;
 501                 error_copy.str1 = NULL;
 502                 error_copy.str2 = NULL;
 503                 error_copy.str3 = NULL;
 504                 ret = 0;
 505         }
 506 
 507         if (ret == 0) {
 508                 zend_llist_add_element(LIBXML(error_list), &error_copy);
 509         }
 510 }
 511 
 512 static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg)
 513 {
 514         xmlParserCtxtPtr parser;
 515 
 516         parser = (xmlParserCtxtPtr) ctx;
 517 
 518         if (parser != NULL && parser->input != NULL) {
 519                 if (parser->input->filename) {
 520                         php_error_docref(NULL, level, "%s in %s, line: %d", msg, parser->input->filename, parser->input->line);
 521                 } else {
 522                         php_error_docref(NULL, level, "%s in Entity, line: %d", msg, parser->input->line);
 523                 }
 524         }
 525 }
 526 
 527 void php_libxml_issue_error(int level, const char *msg)
 528 {
 529         if (LIBXML(error_list)) {
 530                 _php_list_set_error_structure(NULL, msg);
 531         } else {
 532                 php_error_docref(NULL, level, "%s", msg);
 533         }
 534 }
 535 
 536 static void php_libxml_internal_error_handler(int error_type, void *ctx, const char **msg, va_list ap)
 537 {
 538         char *buf;
 539         int len, len_iter, output = 0;
 540 
 541 
 542         len = vspprintf(&buf, 0, *msg, ap);
 543         len_iter = len;
 544 
 545         /* remove any trailing \n */
 546         while (len_iter && buf[--len_iter] == '\n') {
 547                 buf[len_iter] = '\0';
 548                 output = 1;
 549         }
 550 
 551         smart_str_appendl(&LIBXML(error_buffer), buf, len);
 552 
 553         efree(buf);
 554 
 555         if (output == 1) {
 556                 if (LIBXML(error_list)) {
 557                         _php_list_set_error_structure(NULL, ZSTR_VAL(LIBXML(error_buffer).s));
 558                 } else {
 559                         switch (error_type) {
 560                                 case PHP_LIBXML_CTX_ERROR:
 561                                         php_libxml_ctx_error_level(E_WARNING, ctx, ZSTR_VAL(LIBXML(error_buffer).s));
 562                                         break;
 563                                 case PHP_LIBXML_CTX_WARNING:
 564                                         php_libxml_ctx_error_level(E_NOTICE, ctx, ZSTR_VAL(LIBXML(error_buffer).s));
 565                                         break;
 566                                 default:
 567                                         php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(LIBXML(error_buffer).s));
 568                         }
 569                 }
 570                 smart_str_free(&LIBXML(error_buffer));
 571         }
 572 }
 573 
 574 static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL,
 575                 const char *ID, xmlParserCtxtPtr context)
 576 {
 577         xmlParserInputPtr       ret                     = NULL;
 578         const char                      *resource       = NULL;
 579         zval                            *ctxzv, retval;
 580         zval                            params[3];
 581         int                                     status;
 582         zend_fcall_info         *fci;
 583 
 584         fci = &LIBXML(entity_loader).fci;
 585 
 586         if (fci->size == 0) {
 587                 /* no custom user-land callback set up; delegate to original loader */
 588                 return _php_libxml_default_entity_loader(URL, ID, context);
 589         }
 590 
 591         if (ID != NULL) {
 592                 ZVAL_STRING(&params[0], ID);
 593         } else {
 594                 ZVAL_UNDEF(&params[0]);
 595         }
 596         if (URL != NULL) {
 597                 ZVAL_STRING(&params[1], URL);
 598         } else {
 599                 ZVAL_UNDEF(&params[1]);
 600         }
 601         ctxzv = &params[2];
 602         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         ADD_NULL_OR_STRING_KEY(directory)
 613         ADD_NULL_OR_STRING_KEY(intSubName)
 614         ADD_NULL_OR_STRING_KEY(extSubURI)
 615         ADD_NULL_OR_STRING_KEY(extSubSystem)
 616 
 617 #undef ADD_NULL_OR_STRING_KEY
 618 
 619         fci->retval     = &retval;
 620         fci->params     = params;
 621         fci->param_count = sizeof(params)/sizeof(*params);
 622         fci->no_separation      = 1;
 623 
 624         status = zend_call_function(fci, &LIBXML(entity_loader).fcc);
 625         if (status != SUCCESS || Z_ISUNDEF(retval)) {
 626                 php_libxml_ctx_error(context,
 627                                 "Call to user entity loader callback '%s' has failed",
 628                                 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                 } else */ if (Z_TYPE(retval) == IS_STRING) {
 638 is_string:
 639                         resource = Z_STRVAL(retval);
 640                 } else if (Z_TYPE(retval) == IS_RESOURCE) {
 641                         php_stream *stream;
 642                         php_stream_from_zval_no_verify(stream, &retval);
 643                         if (stream == NULL) {
 644                                 php_libxml_ctx_error(context,
 645                                                 "The user entity loader callback '%s' has returned a "
 646                                                 "resource, but it is not a stream",
 647                                                 Z_STRVAL(fci->function_name));
 648                         } else {
 649                                 /* TODO: allow storing the encoding in the stream context? */
 650                                 xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
 651                                 xmlParserInputBufferPtr pib = xmlAllocParserInputBuffer(enc);
 652                                 if (pib == NULL) {
 653                                         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                                         ++GC_REFCOUNT(stream->res);
 658                                         pib->context = stream;
 659                                         pib->readcallback = php_libxml_streams_IO_read;
 660                                         pib->closecallback = php_libxml_streams_IO_close;
 661 
 662                                         ret = xmlNewIOInputStream(context, pib, enc);
 663                                         if (ret == NULL) {
 664                                                 xmlFreeParserInputBuffer(pib);
 665                                         }
 666                                 }
 667                         }
 668                 } else if (Z_TYPE(retval) != IS_NULL) {
 669                         /* retval not string nor resource nor null; convert to string */
 670                         convert_to_string(&retval);
 671                         goto is_string;
 672                 } /* else is null; don't try anything */
 673         }
 674 
 675         if (ret == NULL) {
 676                 if (resource == NULL) {
 677                         if (ID == NULL) {
 678                                 ID = "NULL";
 679                         }
 680                         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                         ret = xmlNewInputFromFile(context, resource);
 685                 }
 686         }
 687 
 688         zval_ptr_dtor(&params[0]);
 689         zval_ptr_dtor(&params[1]);
 690         zval_ptr_dtor(&params[2]);
 691         zval_ptr_dtor(&retval);
 692         return ret;
 693 }
 694 
 695 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         if (xmlGenericError == php_libxml_error_handler && PG(modules_activated)) {
 709                 return _php_libxml_external_entity_loader(URL, ID, context);
 710         } else {
 711                 return _php_libxml_default_entity_loader(URL, ID, context);
 712         }
 713 }
 714 
 715 PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...)
 716 {
 717         va_list args;
 718         va_start(args, msg);
 719         php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args);
 720         va_end(args);
 721 }
 722 
 723 PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
 724 {
 725         va_list args;
 726         va_start(args, msg);
 727         php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args);
 728         va_end(args);
 729 }
 730 
 731 PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
 732 {
 733         _php_list_set_error_structure(error, NULL);
 734 
 735         return;
 736 }
 737 
 738 PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...)
 739 {
 740         va_list args;
 741         va_start(args, msg);
 742         php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args);
 743         va_end(args);
 744 }
 745 
 746 static void php_libxml_exports_dtor(zval *zv)
 747 {
 748         free(Z_PTR_P(zv));
 749 }
 750 
 751 PHP_LIBXML_API void php_libxml_initialize(void)
 752 {
 753         if (!_php_libxml_initialized) {
 754                 /* we should be the only one's to ever init!! */
 755                 xmlInitParser();
 756 
 757                 _php_libxml_default_entity_loader = xmlGetExternalEntityLoader();
 758                 xmlSetExternalEntityLoader(_php_libxml_pre_ext_ent_loader);
 759 
 760                 zend_hash_init(&php_libxml_exports, 0, NULL, php_libxml_exports_dtor, 1);
 761 
 762                 _php_libxml_initialized = 1;
 763         }
 764 }
 765 
 766 PHP_LIBXML_API void php_libxml_shutdown(void)
 767 {
 768         if (_php_libxml_initialized) {
 769 #if defined(LIBXML_SCHEMAS_ENABLED)
 770                 xmlRelaxNGCleanupTypes();
 771 #endif
 772                 /* xmlCleanupParser(); */
 773                 zend_hash_destroy(&php_libxml_exports);
 774 
 775                 xmlSetExternalEntityLoader(_php_libxml_default_entity_loader);
 776                 _php_libxml_initialized = 0;
 777         }
 778 }
 779 
 780 PHP_LIBXML_API void php_libxml_switch_context(zval *context, zval *oldcontext)
 781 {
 782         if (oldcontext) {
 783                 ZVAL_COPY_VALUE(oldcontext, &LIBXML(stream_context));
 784         }
 785         if (context) {
 786                 ZVAL_COPY_VALUE(&LIBXML(stream_context), context);
 787         }
 788 }
 789 
 790 static PHP_MINIT_FUNCTION(libxml)
 791 {
 792         zend_class_entry ce;
 793 
 794         php_libxml_initialize();
 795 
 796         REGISTER_LONG_CONSTANT("LIBXML_VERSION",                        LIBXML_VERSION,                 CONST_CS | CONST_PERSISTENT);
 797         REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION",       LIBXML_DOTTED_VERSION,  CONST_CS | CONST_PERSISTENT);
 798         REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION",       (char *)xmlParserVersion,               CONST_CS | CONST_PERSISTENT);
 799 
 800         /* For use with loading xml */
 801         REGISTER_LONG_CONSTANT("LIBXML_NOENT",          XML_PARSE_NOENT,                CONST_CS | CONST_PERSISTENT);
 802         REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD",        XML_PARSE_DTDLOAD,              CONST_CS | CONST_PERSISTENT);
 803         REGISTER_LONG_CONSTANT("LIBXML_DTDATTR",        XML_PARSE_DTDATTR,              CONST_CS | CONST_PERSISTENT);
 804         REGISTER_LONG_CONSTANT("LIBXML_DTDVALID",       XML_PARSE_DTDVALID,             CONST_CS | CONST_PERSISTENT);
 805         REGISTER_LONG_CONSTANT("LIBXML_NOERROR",        XML_PARSE_NOERROR,              CONST_CS | CONST_PERSISTENT);
 806         REGISTER_LONG_CONSTANT("LIBXML_NOWARNING",      XML_PARSE_NOWARNING,    CONST_CS | CONST_PERSISTENT);
 807         REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS",       XML_PARSE_NOBLANKS,             CONST_CS | CONST_PERSISTENT);
 808         REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE",       XML_PARSE_XINCLUDE,             CONST_CS | CONST_PERSISTENT);
 809         REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN",        XML_PARSE_NSCLEAN,              CONST_CS | CONST_PERSISTENT);
 810         REGISTER_LONG_CONSTANT("LIBXML_NOCDATA",        XML_PARSE_NOCDATA,              CONST_CS | CONST_PERSISTENT);
 811         REGISTER_LONG_CONSTANT("LIBXML_NONET",          XML_PARSE_NONET,                CONST_CS | CONST_PERSISTENT);
 812         REGISTER_LONG_CONSTANT("LIBXML_PEDANTIC",       XML_PARSE_PEDANTIC,             CONST_CS | CONST_PERSISTENT);
 813 #if LIBXML_VERSION >= 20621
 814         REGISTER_LONG_CONSTANT("LIBXML_COMPACT",        XML_PARSE_COMPACT,              CONST_CS | CONST_PERSISTENT);
 815         REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL",      XML_SAVE_NO_DECL,               CONST_CS | CONST_PERSISTENT);
 816 #endif
 817 #if LIBXML_VERSION >= 20703
 818         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         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         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         REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE",               XML_ERR_NONE,           CONST_CS | CONST_PERSISTENT);
 841         REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING",    XML_ERR_WARNING,        CONST_CS | CONST_PERSISTENT);
 842         REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR",              XML_ERR_ERROR,          CONST_CS | CONST_PERSISTENT);
 843         REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL",              XML_ERR_FATAL,          CONST_CS | CONST_PERSISTENT);
 844 
 845         INIT_CLASS_ENTRY(ce, "LibXMLError", NULL);
 846         libxmlerror_class_entry = zend_register_internal_class(&ce);
 847 
 848         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                 for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
 858                         if (strcmp(sapi_module.name, *sapi_name) == 0) {
 859                                 _php_libxml_per_request_initialization = 0;
 860                                 break;
 861                         }
 862                 }
 863         }
 864 
 865         if (!_php_libxml_per_request_initialization) {
 866                 /* report errors via handler rather than stderr */
 867                 xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
 868                 xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
 869                 xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
 870         }
 871 
 872         return SUCCESS;
 873 }
 874 
 875 
 876 static PHP_RINIT_FUNCTION(libxml)
 877 {
 878         if (_php_libxml_per_request_initialization) {
 879                 /* report errors via handler rather than stderr */
 880                 xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
 881                 xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
 882                 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                 LIBXML(entity_loader_disabled) = 0;
 889         }
 890         return SUCCESS;
 891 }
 892 
 893 static PHP_RSHUTDOWN_FUNCTION(libxml)
 894 {
 895         _php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
 896 
 897         return SUCCESS;
 898 }
 899 
 900 static PHP_MSHUTDOWN_FUNCTION(libxml)
 901 {
 902         if (!_php_libxml_per_request_initialization) {
 903                 xmlSetGenericErrorFunc(NULL, NULL);
 904 
 905                 xmlParserInputBufferCreateFilenameDefault(NULL);
 906                 xmlOutputBufferCreateFilenameDefault(NULL);
 907         }
 908         php_libxml_shutdown();
 909 
 910         return SUCCESS;
 911 }
 912 
 913 static int php_libxml_post_deactivate(void)
 914 {
 915         /* reset libxml generic error handling */
 916         if (_php_libxml_per_request_initialization) {
 917                 xmlSetGenericErrorFunc(NULL, NULL);
 918 
 919                 xmlParserInputBufferCreateFilenameDefault(NULL);
 920                 xmlOutputBufferCreateFilenameDefault(NULL);
 921         }
 922         xmlSetStructuredErrorFunc(NULL, NULL);
 923 
 924         /* the steam_context resource will be released by resource list destructor */
 925         ZVAL_UNDEF(&LIBXML(stream_context));
 926         smart_str_free(&LIBXML(error_buffer));
 927         if (LIBXML(error_list)) {
 928                 zend_llist_destroy(LIBXML(error_list));
 929                 efree(LIBXML(error_list));
 930                 LIBXML(error_list) = NULL;
 931         }
 932         xmlResetLastError();
 933 
 934         return SUCCESS;
 935 }
 936 
 937 
 938 static PHP_MINFO_FUNCTION(libxml)
 939 {
 940         php_info_print_table_start();
 941         php_info_print_table_row(2, "libXML support", "active");
 942         php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION);
 943         php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion);
 944         php_info_print_table_row(2, "libXML streams", "enabled");
 945         php_info_print_table_end();
 946 }
 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 static PHP_FUNCTION(libxml_set_streams_context)
 952 {
 953         zval *arg;
 954 
 955         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg) == FAILURE) {
 956                 return;
 957         }
 958         if (!Z_ISUNDEF(LIBXML(stream_context))) {
 959                 zval_ptr_dtor(&LIBXML(stream_context));
 960                 ZVAL_UNDEF(&LIBXML(stream_context));
 961         }
 962         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 static PHP_FUNCTION(libxml_use_internal_errors)
 969 {
 970         xmlStructuredErrorFunc current_handler;
 971         zend_bool use_errors=0, retval;
 972 
 973         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &use_errors) == FAILURE) {
 974                 return;
 975         }
 976 
 977         current_handler = xmlStructuredError;
 978         if (current_handler && current_handler == php_libxml_structured_error_handler) {
 979                 retval = 1;
 980         } else {
 981                 retval = 0;
 982         }
 983 
 984         if (ZEND_NUM_ARGS() == 0) {
 985                 RETURN_BOOL(retval);
 986         }
 987 
 988         if (use_errors == 0) {
 989                 xmlSetStructuredErrorFunc(NULL, NULL);
 990                 if (LIBXML(error_list)) {
 991                         zend_llist_destroy(LIBXML(error_list));
 992                         efree(LIBXML(error_list));
 993                         LIBXML(error_list) = NULL;
 994                 }
 995         } else {
 996                 xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
 997                 if (LIBXML(error_list) == NULL) {
 998                         LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist));
 999                         zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0);
1000                 }
1001         }
1002         RETURN_BOOL(retval);
1003 }
1004 /* }}} */
1005 
1006 /* {{{ proto object libxml_get_last_error()
1007    Retrieve last error from libxml */
1008 static PHP_FUNCTION(libxml_get_last_error)
1009 {
1010         xmlErrorPtr error;
1011 
1012         error = xmlGetLastError();
1013 
1014         if (error) {
1015                 object_init_ex(return_value, libxmlerror_class_entry);
1016                 add_property_long(return_value, "level", error->level);
1017                 add_property_long(return_value, "code", error->code);
1018                 add_property_long(return_value, "column", error->int2);
1019                 if (error->message) {
1020                         add_property_string(return_value, "message", error->message);
1021                 } else {
1022                         add_property_stringl(return_value, "message", "", 0);
1023                 }
1024                 if (error->file) {
1025                         add_property_string(return_value, "file", error->file);
1026                 } else {
1027                         add_property_stringl(return_value, "file", "", 0);
1028                 }
1029                 add_property_long(return_value, "line", error->line);
1030         } else {
1031                 RETURN_FALSE;
1032         }
1033 }
1034 /* }}} */
1035 
1036 /* {{{ proto object libxml_get_errors()
1037    Retrieve array of errors */
1038 static PHP_FUNCTION(libxml_get_errors)
1039 {
1040 
1041         xmlErrorPtr error;
1042 
1043         if (array_init(return_value) == FAILURE) {
1044                 RETURN_FALSE;
1045         }
1046 
1047         if (LIBXML(error_list)) {
1048 
1049                 error = zend_llist_get_first(LIBXML(error_list));
1050 
1051                 while (error != NULL) {
1052                         zval z_error;
1053 
1054                         object_init_ex(&z_error, libxmlerror_class_entry);
1055                         add_property_long_ex(&z_error, "level", sizeof("level") - 1, error->level);
1056                         add_property_long_ex(&z_error, "code", sizeof("code") - 1, error->code);
1057                         add_property_long_ex(&z_error, "column", sizeof("column") - 1, error->int2 );
1058                         if (error->message) {
1059                                 add_property_string_ex(&z_error, "message", sizeof("message") - 1, error->message);
1060                         } else {
1061                                 add_property_stringl_ex(&z_error, "message", sizeof("message") - 1, "", 0);
1062                         }
1063                         if (error->file) {
1064                                 add_property_string_ex(&z_error, "file", sizeof("file") - 1, error->file);
1065                         } else {
1066                                 add_property_stringl_ex(&z_error, "file", sizeof("file") - 1, "", 0);
1067                         }
1068                         add_property_long_ex(&z_error, "line", sizeof("line") - 1, error->line);
1069                         add_next_index_zval(return_value, &z_error);
1070 
1071                         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 static PHP_FUNCTION(libxml_clear_errors)
1080 {
1081         xmlResetLastError();
1082         if (LIBXML(error_list)) {
1083                 zend_llist_clean(LIBXML(error_list));
1084         }
1085 }
1086 /* }}} */
1087 
1088 PHP_LIBXML_API zend_bool php_libxml_disable_entity_loader(zend_bool disable) /* {{{ */
1089 {
1090         zend_bool old = LIBXML(entity_loader_disabled);
1091 
1092         LIBXML(entity_loader_disabled) = disable;
1093         return old;
1094 } /* }}} */
1095 
1096 /* {{{ proto bool libxml_disable_entity_loader([boolean disable])
1097    Disable/Enable ability to load external entities */
1098 static PHP_FUNCTION(libxml_disable_entity_loader)
1099 {
1100         zend_bool disable = 1;
1101 
1102         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &disable) == FAILURE) {
1103                 return;
1104         }
1105 
1106         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 static PHP_FUNCTION(libxml_set_external_entity_loader)
1113 {
1114         zend_fcall_info                 fci;
1115         zend_fcall_info_cache   fcc;
1116         if (zend_parse_parameters(ZEND_NUM_ARGS(), "f!", &fci, &fcc)
1117                         == FAILURE) {
1118                 return;
1119         }
1120 
1121         _php_libxml_destroy_fci(&LIBXML(entity_loader).fci, &LIBXML(entity_loader).object);
1122 
1123         if (fci.size > 0) { /* argument not null */
1124                 LIBXML(entity_loader).fci = fci;
1125                 Z_ADDREF(fci.function_name);
1126                 if (fci.object != NULL) {
1127                         ZVAL_OBJ(&LIBXML(entity_loader).object, fci.object);
1128                         Z_ADDREF(LIBXML(entity_loader).object);
1129                 }
1130                 LIBXML(entity_loader).fcc = fcc;
1131         }
1132 
1133         RETURN_TRUE;
1134 }
1135 /* }}} */
1136 
1137 /* {{{ Common functions shared by extensions */
1138 int php_libxml_xmlCheckUTF8(const unsigned char *s)
1139 {
1140         int i;
1141         unsigned char c;
1142 
1143         for (i = 0; (c = s[i++]);) {
1144                 if ((c & 0x80) == 0) {
1145                 } else if ((c & 0xe0) == 0xc0) {
1146                         if ((s[i++] & 0xc0) != 0x80) {
1147                                 return 0;
1148                         }
1149                 } else if ((c & 0xf0) == 0xe0) {
1150                         if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
1151                                 return 0;
1152                         }
1153                 } else if ((c & 0xf8) == 0xf0) {
1154                         if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
1155                                 return 0;
1156                         }
1157                 } else {
1158                         return 0;
1159                 }
1160         }
1161         return 1;
1162 }
1163 
1164 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         php_libxml_initialize();
1170         export_hnd.export_func = export_function;
1171 
1172         return zend_hash_add_mem(&php_libxml_exports, ce->name, &export_hnd, sizeof(export_hnd));
1173 }
1174 
1175 PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object)
1176 {
1177         zend_class_entry *ce = NULL;
1178         xmlNodePtr node = NULL;
1179         php_libxml_func_handler *export_hnd;
1180 
1181         if (Z_TYPE_P(object) == IS_OBJECT) {
1182                 ce = Z_OBJCE_P(object);
1183                 while (ce->parent != NULL) {
1184                         ce = ce->parent;
1185                 }
1186                 if ((export_hnd = zend_hash_find_ptr(&php_libxml_exports, ce->name))) {
1187                         node = export_hnd->export_func(object);
1188                 }
1189         }
1190         return node;
1191 }
1192 
1193 PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data)
1194 {
1195         int ret_refcount = -1;
1196 
1197         if (object != NULL && node != NULL) {
1198                 if (object->node != NULL) {
1199                         if (object->node->node == node) {
1200                                 return object->node->refcount;
1201                         } else {
1202                                 php_libxml_decrement_node_ptr(object);
1203                         }
1204                 }
1205                 if (node->_private != NULL) {
1206                         object->node = node->_private;
1207                         ret_refcount = ++object->node->refcount;
1208                         /* Only dom uses _private */
1209                         if (object->node->_private == NULL) {
1210                                 object->node->_private = private_data;
1211                         }
1212                 } else {
1213                         ret_refcount = 1;
1214                         object->node = emalloc(sizeof(php_libxml_node_ptr));
1215                         object->node->node = node;
1216                         object->node->refcount = 1;
1217                         object->node->_private = private_data;
1218                         node->_private = object->node;
1219                 }
1220         }
1221 
1222         return ret_refcount;
1223 }
1224 
1225 PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object)
1226 {
1227         int ret_refcount = -1;
1228         php_libxml_node_ptr *obj_node;
1229 
1230         if (object != NULL && object->node != NULL) {
1231                 obj_node = (php_libxml_node_ptr *) object->node;
1232                 ret_refcount = --obj_node->refcount;
1233                 if (ret_refcount == 0) {
1234                         if (obj_node->node != NULL) {
1235                                 obj_node->node->_private = NULL;
1236                         }
1237                         efree(obj_node);
1238                 }
1239                 object->node = NULL;
1240         }
1241 
1242         return ret_refcount;
1243 }
1244 
1245 PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp)
1246 {
1247         int ret_refcount = -1;
1248 
1249         if (object->document != NULL) {
1250                 object->document->refcount++;
1251                 ret_refcount = object->document->refcount;
1252         } else if (docp != NULL) {
1253                 ret_refcount = 1;
1254                 object->document = emalloc(sizeof(php_libxml_ref_obj));
1255                 object->document->ptr = docp;
1256                 object->document->refcount = ret_refcount;
1257                 object->document->doc_props = NULL;
1258         }
1259 
1260         return ret_refcount;
1261 }
1262 
1263 PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object)
1264 {
1265         int ret_refcount = -1;
1266 
1267         if (object != NULL && object->document != NULL) {
1268                 ret_refcount = --object->document->refcount;
1269                 if (ret_refcount == 0) {
1270                         if (object->document->ptr != NULL) {
1271                                 xmlFreeDoc((xmlDoc *) object->document->ptr);
1272                         }
1273                         if (object->document->doc_props != NULL) {
1274                                 if (object->document->doc_props->classmap) {
1275                                         zend_hash_destroy(object->document->doc_props->classmap);
1276                                         FREE_HASHTABLE(object->document->doc_props->classmap);
1277                                 }
1278                                 efree(object->document->doc_props);
1279                         }
1280                         efree(object->document);
1281                         object->document = NULL;
1282                 }
1283         }
1284 
1285         return ret_refcount;
1286 }
1287 
1288 PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node)
1289 {
1290         if (!node) {
1291                 return;
1292         }
1293 
1294         switch (node->type) {
1295                 case XML_DOCUMENT_NODE:
1296                 case XML_HTML_DOCUMENT_NODE:
1297                         break;
1298                 default:
1299                         if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) {
1300                                 php_libxml_node_free_list((xmlNodePtr) node->children);
1301                                 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                                                 break;
1311                                         default:
1312                                                 php_libxml_node_free_list((xmlNodePtr) node->properties);
1313                                 }
1314                                 if (php_libxml_unregister_node(node) == 0) {
1315                                         node->doc = NULL;
1316                                 }
1317                                 php_libxml_node_free(node);
1318                         } else {
1319                                 php_libxml_unregister_node(node);
1320                         }
1321         }
1322 }
1323 
1324 PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object)
1325 {
1326         int ret_refcount = -1;
1327         xmlNodePtr nodep;
1328         php_libxml_node_ptr *obj_node;
1329 
1330         if (object != NULL && object->node != NULL) {
1331                 obj_node = (php_libxml_node_ptr *) object->node;
1332                 nodep = object->node->node;
1333                 ret_refcount = php_libxml_decrement_node_ptr(object);
1334                 if (ret_refcount == 0) {
1335                         php_libxml_node_free_resource(nodep);
1336                 } else {
1337                         if (obj_node && object == obj_node->_private) {
1338                                 obj_node->_private = NULL;
1339                         }
1340                 }
1341         }
1342         if (object != NULL && object->document != NULL) {
1343                 /* Safe to call as if the resource were freed then doc pointer is NULL */
1344                 php_libxml_decrement_doc_ref(object);
1345         }
1346 }
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  */

/* [<][>][^][v][top][bottom][index][help] */