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