Return to libxml.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / libxml |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 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: libxml.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 21: ! 22: #define IS_EXT_MODULE ! 23: ! 24: #ifdef HAVE_CONFIG_H ! 25: #include "config.h" ! 26: #endif ! 27: ! 28: #include "php.h" ! 29: ! 30: #define PHP_XML_INTERNAL ! 31: #include "zend_variables.h" ! 32: #include "ext/standard/php_string.h" ! 33: #include "ext/standard/info.h" ! 34: #include "ext/standard/file.h" ! 35: ! 36: #if HAVE_LIBXML ! 37: ! 38: #include <libxml/parser.h> ! 39: #include <libxml/parserInternals.h> ! 40: #include <libxml/tree.h> ! 41: #include <libxml/uri.h> ! 42: #include <libxml/xmlerror.h> ! 43: #include <libxml/xmlsave.h> ! 44: #ifdef LIBXML_SCHEMAS_ENABLED ! 45: #include <libxml/relaxng.h> ! 46: #endif ! 47: ! 48: #include "php_libxml.h" ! 49: ! 50: #define PHP_LIBXML_ERROR 0 ! 51: #define PHP_LIBXML_CTX_ERROR 1 ! 52: #define PHP_LIBXML_CTX_WARNING 2 ! 53: ! 54: /* a true global for initialization */ ! 55: static int _php_libxml_initialized = 0; ! 56: ! 57: typedef struct _php_libxml_func_handler { ! 58: php_libxml_export_node export_func; ! 59: } php_libxml_func_handler; ! 60: ! 61: static HashTable php_libxml_exports; ! 62: ! 63: static ZEND_DECLARE_MODULE_GLOBALS(libxml) ! 64: static PHP_GINIT_FUNCTION(libxml); ! 65: ! 66: static PHP_FUNCTION(libxml_set_streams_context); ! 67: static PHP_FUNCTION(libxml_use_internal_errors); ! 68: static PHP_FUNCTION(libxml_get_last_error); ! 69: static PHP_FUNCTION(libxml_clear_errors); ! 70: static PHP_FUNCTION(libxml_get_errors); ! 71: static PHP_FUNCTION(libxml_disable_entity_loader); ! 72: ! 73: static zend_class_entry *libxmlerror_class_entry; ! 74: ! 75: /* {{{ dynamically loadable module stuff */ ! 76: #ifdef COMPILE_DL_LIBXML ! 77: ZEND_GET_MODULE(libxml) ! 78: #endif /* COMPILE_DL_LIBXML */ ! 79: /* }}} */ ! 80: ! 81: /* {{{ function prototypes */ ! 82: static PHP_MINIT_FUNCTION(libxml); ! 83: static PHP_RINIT_FUNCTION(libxml); ! 84: static PHP_MSHUTDOWN_FUNCTION(libxml); ! 85: static PHP_RSHUTDOWN_FUNCTION(libxml); ! 86: static PHP_MINFO_FUNCTION(libxml); ! 87: ! 88: /* }}} */ ! 89: ! 90: /* {{{ arginfo */ ! 91: ZEND_BEGIN_ARG_INFO(arginfo_libxml_set_streams_context, 0) ! 92: ZEND_ARG_INFO(0, context) ! 93: ZEND_END_ARG_INFO() ! 94: ! 95: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_use_internal_errors, 0, 0, 0) ! 96: ZEND_ARG_INFO(0, use_errors) ! 97: ZEND_END_ARG_INFO() ! 98: ! 99: ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_last_error, 0) ! 100: ZEND_END_ARG_INFO() ! 101: ! 102: ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_errors, 0) ! 103: ZEND_END_ARG_INFO() ! 104: ! 105: ZEND_BEGIN_ARG_INFO(arginfo_libxml_clear_errors, 0) ! 106: ZEND_END_ARG_INFO() ! 107: ! 108: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_disable_entity_loader, 0, 0, 0) ! 109: ZEND_ARG_INFO(0, disable) ! 110: ZEND_END_ARG_INFO() ! 111: ! 112: /* }}} */ ! 113: ! 114: /* {{{ extension definition structures */ ! 115: static const zend_function_entry libxml_functions[] = { ! 116: PHP_FE(libxml_set_streams_context, arginfo_libxml_set_streams_context) ! 117: PHP_FE(libxml_use_internal_errors, arginfo_libxml_use_internal_errors) ! 118: PHP_FE(libxml_get_last_error, arginfo_libxml_get_last_error) ! 119: PHP_FE(libxml_clear_errors, arginfo_libxml_clear_errors) ! 120: PHP_FE(libxml_get_errors, arginfo_libxml_get_errors) ! 121: PHP_FE(libxml_disable_entity_loader, arginfo_libxml_disable_entity_loader) ! 122: PHP_FE_END ! 123: }; ! 124: ! 125: zend_module_entry libxml_module_entry = { ! 126: STANDARD_MODULE_HEADER, ! 127: "libxml", /* extension name */ ! 128: libxml_functions, /* extension function list */ ! 129: PHP_MINIT(libxml), /* extension-wide startup function */ ! 130: PHP_MSHUTDOWN(libxml), /* extension-wide shutdown function */ ! 131: PHP_RINIT(libxml), /* per-request startup function */ ! 132: PHP_RSHUTDOWN(libxml), /* per-request shutdown function */ ! 133: PHP_MINFO(libxml), /* information function */ ! 134: NO_VERSION_YET, ! 135: PHP_MODULE_GLOBALS(libxml), /* globals descriptor */ ! 136: PHP_GINIT(libxml), /* globals ctor */ ! 137: NULL, /* globals dtor */ ! 138: NULL, /* post deactivate */ ! 139: STANDARD_MODULE_PROPERTIES_EX ! 140: }; ! 141: ! 142: /* }}} */ ! 143: ! 144: /* {{{ internal functions for interoperability */ ! 145: static int php_libxml_clear_object(php_libxml_node_object *object TSRMLS_DC) ! 146: { ! 147: if (object->properties) { ! 148: object->properties = NULL; ! 149: } ! 150: php_libxml_decrement_node_ptr(object TSRMLS_CC); ! 151: return php_libxml_decrement_doc_ref(object TSRMLS_CC); ! 152: } ! 153: ! 154: static int php_libxml_unregister_node(xmlNodePtr nodep TSRMLS_DC) ! 155: { ! 156: php_libxml_node_object *wrapper; ! 157: ! 158: php_libxml_node_ptr *nodeptr = nodep->_private; ! 159: ! 160: if (nodeptr != NULL) { ! 161: wrapper = nodeptr->_private; ! 162: if (wrapper) { ! 163: php_libxml_clear_object(wrapper TSRMLS_CC); ! 164: } else { ! 165: if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) { ! 166: nodeptr->node->_private = NULL; ! 167: } ! 168: nodeptr->node = NULL; ! 169: } ! 170: } ! 171: ! 172: return -1; ! 173: } ! 174: ! 175: static void php_libxml_node_free(xmlNodePtr node) ! 176: { ! 177: if(node) { ! 178: if (node->_private != NULL) { ! 179: ((php_libxml_node_ptr *) node->_private)->node = NULL; ! 180: } ! 181: switch (node->type) { ! 182: case XML_ATTRIBUTE_NODE: ! 183: xmlFreeProp((xmlAttrPtr) node); ! 184: break; ! 185: case XML_ENTITY_DECL: ! 186: case XML_ELEMENT_DECL: ! 187: case XML_ATTRIBUTE_DECL: ! 188: break; ! 189: case XML_NOTATION_NODE: ! 190: /* These require special handling */ ! 191: if (node->name != NULL) { ! 192: xmlFree((char *) node->name); ! 193: } ! 194: if (((xmlEntityPtr) node)->ExternalID != NULL) { ! 195: xmlFree((char *) ((xmlEntityPtr) node)->ExternalID); ! 196: } ! 197: if (((xmlEntityPtr) node)->SystemID != NULL) { ! 198: xmlFree((char *) ((xmlEntityPtr) node)->SystemID); ! 199: } ! 200: xmlFree(node); ! 201: break; ! 202: case XML_NAMESPACE_DECL: ! 203: if (node->ns) { ! 204: xmlFreeNs(node->ns); ! 205: node->ns = NULL; ! 206: } ! 207: node->type = XML_ELEMENT_NODE; ! 208: default: ! 209: xmlFreeNode(node); ! 210: } ! 211: } ! 212: } ! 213: ! 214: static void php_libxml_node_free_list(xmlNodePtr node TSRMLS_DC) ! 215: { ! 216: xmlNodePtr curnode; ! 217: ! 218: if (node != NULL) { ! 219: curnode = node; ! 220: while (curnode != NULL) { ! 221: node = curnode; ! 222: switch (node->type) { ! 223: /* Skip property freeing for the following types */ ! 224: case XML_NOTATION_NODE: ! 225: case XML_ENTITY_DECL: ! 226: break; ! 227: case XML_ENTITY_REF_NODE: ! 228: php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC); ! 229: break; ! 230: case XML_ATTRIBUTE_NODE: ! 231: if ((node->doc != NULL) && (((xmlAttrPtr) node)->atype == XML_ATTRIBUTE_ID)) { ! 232: xmlRemoveID(node->doc, (xmlAttrPtr) node); ! 233: } ! 234: case XML_ATTRIBUTE_DECL: ! 235: case XML_DTD_NODE: ! 236: case XML_DOCUMENT_TYPE_NODE: ! 237: case XML_NAMESPACE_DECL: ! 238: case XML_TEXT_NODE: ! 239: php_libxml_node_free_list(node->children TSRMLS_CC); ! 240: break; ! 241: default: ! 242: php_libxml_node_free_list(node->children TSRMLS_CC); ! 243: php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC); ! 244: } ! 245: ! 246: curnode = node->next; ! 247: xmlUnlinkNode(node); ! 248: if (php_libxml_unregister_node(node TSRMLS_CC) == 0) { ! 249: node->doc = NULL; ! 250: } ! 251: php_libxml_node_free(node); ! 252: } ! 253: } ! 254: } ! 255: ! 256: /* }}} */ ! 257: ! 258: /* {{{ startup, shutdown and info functions */ ! 259: static PHP_GINIT_FUNCTION(libxml) ! 260: { ! 261: libxml_globals->stream_context = NULL; ! 262: libxml_globals->error_buffer.c = NULL; ! 263: libxml_globals->error_list = NULL; ! 264: } ! 265: ! 266: /* Channel libxml file io layer through the PHP streams subsystem. ! 267: * This allows use of ftps:// and https:// urls */ ! 268: ! 269: static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char *mode, const int read_only) ! 270: { ! 271: php_stream_statbuf ssbuf; ! 272: php_stream_context *context = NULL; ! 273: php_stream_wrapper *wrapper = NULL; ! 274: char *resolved_path, *path_to_open = NULL; ! 275: void *ret_val = NULL; ! 276: int isescaped=0; ! 277: xmlURI *uri; ! 278: ! 279: TSRMLS_FETCH(); ! 280: ! 281: uri = xmlParseURI((xmlChar *)filename); ! 282: if (uri && (uri->scheme == NULL || (xmlStrncmp(uri->scheme, "file", 4) == 0))) { ! 283: resolved_path = xmlURIUnescapeString(filename, 0, NULL); ! 284: isescaped = 1; ! 285: } else { ! 286: resolved_path = (char *)filename; ! 287: } ! 288: ! 289: if (uri) { ! 290: xmlFreeURI(uri); ! 291: } ! 292: ! 293: if (resolved_path == NULL) { ! 294: return NULL; ! 295: } ! 296: ! 297: /* logic copied from _php_stream_stat, but we only want to fail ! 298: if the wrapper supports stat, otherwise, figure it out from ! 299: the open. This logic is only to support hiding warnings ! 300: that the streams layer puts out at times, but for libxml we ! 301: may try to open files that don't exist, but it is not a failure ! 302: in xml processing (eg. DTD files) */ ! 303: wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC); ! 304: if (wrapper && read_only && wrapper->wops->url_stat) { ! 305: if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL TSRMLS_CC) == -1) { ! 306: if (isescaped) { ! 307: xmlFree(resolved_path); ! 308: } ! 309: return NULL; ! 310: } ! 311: } ! 312: ! 313: context = php_stream_context_from_zval(LIBXML(stream_context), 0); ! 314: ! 315: ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL, context); ! 316: if (isescaped) { ! 317: xmlFree(resolved_path); ! 318: } ! 319: return ret_val; ! 320: } ! 321: ! 322: static void *php_libxml_streams_IO_open_read_wrapper(const char *filename) ! 323: { ! 324: return php_libxml_streams_IO_open_wrapper(filename, "rb", 1); ! 325: } ! 326: ! 327: static void *php_libxml_streams_IO_open_write_wrapper(const char *filename) ! 328: { ! 329: return php_libxml_streams_IO_open_wrapper(filename, "wb", 0); ! 330: } ! 331: ! 332: static int php_libxml_streams_IO_read(void *context, char *buffer, int len) ! 333: { ! 334: TSRMLS_FETCH(); ! 335: return php_stream_read((php_stream*)context, buffer, len); ! 336: } ! 337: ! 338: static int php_libxml_streams_IO_write(void *context, const char *buffer, int len) ! 339: { ! 340: TSRMLS_FETCH(); ! 341: return php_stream_write((php_stream*)context, buffer, len); ! 342: } ! 343: ! 344: static int php_libxml_streams_IO_close(void *context) ! 345: { ! 346: TSRMLS_FETCH(); ! 347: return php_stream_close((php_stream*)context); ! 348: } ! 349: ! 350: static xmlParserInputBufferPtr ! 351: php_libxml_input_buffer_noload(const char *URI, xmlCharEncoding enc) ! 352: { ! 353: return NULL; ! 354: } ! 355: ! 356: static xmlParserInputBufferPtr ! 357: php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc) ! 358: { ! 359: xmlParserInputBufferPtr ret; ! 360: void *context = NULL; ! 361: ! 362: if (URI == NULL) ! 363: return(NULL); ! 364: ! 365: context = php_libxml_streams_IO_open_read_wrapper(URI); ! 366: ! 367: if (context == NULL) { ! 368: return(NULL); ! 369: } ! 370: ! 371: /* Allocate the Input buffer front-end. */ ! 372: ret = xmlAllocParserInputBuffer(enc); ! 373: if (ret != NULL) { ! 374: ret->context = context; ! 375: ret->readcallback = php_libxml_streams_IO_read; ! 376: ret->closecallback = php_libxml_streams_IO_close; ! 377: } else ! 378: php_libxml_streams_IO_close(context); ! 379: ! 380: return(ret); ! 381: } ! 382: ! 383: static xmlOutputBufferPtr ! 384: php_libxml_output_buffer_create_filename(const char *URI, ! 385: xmlCharEncodingHandlerPtr encoder, ! 386: int compression ATTRIBUTE_UNUSED) ! 387: { ! 388: xmlOutputBufferPtr ret; ! 389: xmlURIPtr puri; ! 390: void *context = NULL; ! 391: char *unescaped = NULL; ! 392: ! 393: if (URI == NULL) ! 394: return(NULL); ! 395: ! 396: puri = xmlParseURI(URI); ! 397: if (puri != NULL) { ! 398: if (puri->scheme != NULL) ! 399: unescaped = xmlURIUnescapeString(URI, 0, NULL); ! 400: xmlFreeURI(puri); ! 401: } ! 402: ! 403: if (unescaped != NULL) { ! 404: context = php_libxml_streams_IO_open_write_wrapper(unescaped); ! 405: xmlFree(unescaped); ! 406: } ! 407: ! 408: /* try with a non-escaped URI this may be a strange filename */ ! 409: if (context == NULL) { ! 410: context = php_libxml_streams_IO_open_write_wrapper(URI); ! 411: } ! 412: ! 413: if (context == NULL) { ! 414: return(NULL); ! 415: } ! 416: ! 417: /* Allocate the Output buffer front-end. */ ! 418: ret = xmlAllocOutputBuffer(encoder); ! 419: if (ret != NULL) { ! 420: ret->context = context; ! 421: ret->writecallback = php_libxml_streams_IO_write; ! 422: ret->closecallback = php_libxml_streams_IO_close; ! 423: } ! 424: ! 425: return(ret); ! 426: } ! 427: ! 428: static int _php_libxml_free_error(xmlErrorPtr error) ! 429: { ! 430: /* This will free the libxml alloc'd memory */ ! 431: xmlResetError(error); ! 432: return 1; ! 433: } ! 434: ! 435: static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg) ! 436: { ! 437: xmlError error_copy; ! 438: int ret; ! 439: ! 440: TSRMLS_FETCH(); ! 441: ! 442: memset(&error_copy, 0, sizeof(xmlError)); ! 443: ! 444: if (error) { ! 445: ret = xmlCopyError(error, &error_copy); ! 446: } else { ! 447: error_copy.domain = 0; ! 448: error_copy.code = XML_ERR_INTERNAL_ERROR; ! 449: error_copy.level = XML_ERR_ERROR; ! 450: error_copy.line = 0; ! 451: error_copy.node = NULL; ! 452: error_copy.int1 = 0; ! 453: error_copy.int2 = 0; ! 454: error_copy.ctxt = NULL; ! 455: error_copy.message = xmlStrdup(msg); ! 456: error_copy.file = NULL; ! 457: error_copy.str1 = NULL; ! 458: error_copy.str2 = NULL; ! 459: error_copy.str3 = NULL; ! 460: ret = 0; ! 461: } ! 462: ! 463: if (ret == 0) { ! 464: zend_llist_add_element(LIBXML(error_list), &error_copy); ! 465: } ! 466: } ! 467: ! 468: static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg TSRMLS_DC) ! 469: { ! 470: xmlParserCtxtPtr parser; ! 471: ! 472: parser = (xmlParserCtxtPtr) ctx; ! 473: ! 474: if (parser != NULL && parser->input != NULL) { ! 475: if (parser->input->filename) { ! 476: php_error_docref(NULL TSRMLS_CC, level, "%s in %s, line: %d", msg, parser->input->filename, parser->input->line); ! 477: } else { ! 478: php_error_docref(NULL TSRMLS_CC, level, "%s in Entity, line: %d", msg, parser->input->line); ! 479: } ! 480: } ! 481: } ! 482: ! 483: void php_libxml_issue_error(int level, const char *msg TSRMLS_DC) ! 484: { ! 485: if (LIBXML(error_list)) { ! 486: _php_list_set_error_structure(NULL, msg); ! 487: } else { ! 488: php_error_docref(NULL TSRMLS_CC, level, "%s", msg); ! 489: } ! 490: } ! 491: ! 492: static void php_libxml_internal_error_handler(int error_type, void *ctx, const char **msg, va_list ap) ! 493: { ! 494: char *buf; ! 495: int len, len_iter, output = 0; ! 496: ! 497: TSRMLS_FETCH(); ! 498: ! 499: len = vspprintf(&buf, 0, *msg, ap); ! 500: len_iter = len; ! 501: ! 502: /* remove any trailing \n */ ! 503: while (len_iter && buf[--len_iter] == '\n') { ! 504: buf[len_iter] = '\0'; ! 505: output = 1; ! 506: } ! 507: ! 508: smart_str_appendl(&LIBXML(error_buffer), buf, len); ! 509: ! 510: efree(buf); ! 511: ! 512: if (output == 1) { ! 513: if (LIBXML(error_list)) { ! 514: _php_list_set_error_structure(NULL, LIBXML(error_buffer).c); ! 515: } else { ! 516: switch (error_type) { ! 517: case PHP_LIBXML_CTX_ERROR: ! 518: php_libxml_ctx_error_level(E_WARNING, ctx, LIBXML(error_buffer).c TSRMLS_CC); ! 519: break; ! 520: case PHP_LIBXML_CTX_WARNING: ! 521: php_libxml_ctx_error_level(E_NOTICE, ctx, LIBXML(error_buffer).c TSRMLS_CC); ! 522: break; ! 523: default: ! 524: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", LIBXML(error_buffer).c); ! 525: } ! 526: } ! 527: smart_str_free(&LIBXML(error_buffer)); ! 528: } ! 529: } ! 530: ! 531: PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...) ! 532: { ! 533: va_list args; ! 534: va_start(args, msg); ! 535: php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args); ! 536: va_end(args); ! 537: } ! 538: ! 539: PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...) ! 540: { ! 541: va_list args; ! 542: va_start(args, msg); ! 543: php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args); ! 544: va_end(args); ! 545: } ! 546: ! 547: PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error) ! 548: { ! 549: _php_list_set_error_structure(error, NULL); ! 550: ! 551: return; ! 552: } ! 553: ! 554: PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...) ! 555: { ! 556: va_list args; ! 557: va_start(args, msg); ! 558: php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args); ! 559: va_end(args); ! 560: } ! 561: ! 562: ! 563: PHP_LIBXML_API void php_libxml_initialize(void) ! 564: { ! 565: if (!_php_libxml_initialized) { ! 566: /* we should be the only one's to ever init!! */ ! 567: xmlInitParser(); ! 568: ! 569: zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1); ! 570: ! 571: _php_libxml_initialized = 1; ! 572: } ! 573: } ! 574: ! 575: PHP_LIBXML_API void php_libxml_shutdown(void) ! 576: { ! 577: if (_php_libxml_initialized) { ! 578: #if defined(LIBXML_SCHEMAS_ENABLED) ! 579: xmlRelaxNGCleanupTypes(); ! 580: #endif ! 581: xmlCleanupParser(); ! 582: zend_hash_destroy(&php_libxml_exports); ! 583: _php_libxml_initialized = 0; ! 584: } ! 585: } ! 586: ! 587: PHP_LIBXML_API zval *php_libxml_switch_context(zval *context TSRMLS_DC) ! 588: { ! 589: zval *oldcontext; ! 590: ! 591: oldcontext = LIBXML(stream_context); ! 592: LIBXML(stream_context) = context; ! 593: return oldcontext; ! 594: ! 595: } ! 596: ! 597: static PHP_MINIT_FUNCTION(libxml) ! 598: { ! 599: zend_class_entry ce; ! 600: ! 601: php_libxml_initialize(); ! 602: ! 603: REGISTER_LONG_CONSTANT("LIBXML_VERSION", LIBXML_VERSION, CONST_CS | CONST_PERSISTENT); ! 604: REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION", LIBXML_DOTTED_VERSION, CONST_CS | CONST_PERSISTENT); ! 605: REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION", (char *)xmlParserVersion, CONST_CS | CONST_PERSISTENT); ! 606: ! 607: /* For use with loading xml */ ! 608: REGISTER_LONG_CONSTANT("LIBXML_NOENT", XML_PARSE_NOENT, CONST_CS | CONST_PERSISTENT); ! 609: REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD", XML_PARSE_DTDLOAD, CONST_CS | CONST_PERSISTENT); ! 610: REGISTER_LONG_CONSTANT("LIBXML_DTDATTR", XML_PARSE_DTDATTR, CONST_CS | CONST_PERSISTENT); ! 611: REGISTER_LONG_CONSTANT("LIBXML_DTDVALID", XML_PARSE_DTDVALID, CONST_CS | CONST_PERSISTENT); ! 612: REGISTER_LONG_CONSTANT("LIBXML_NOERROR", XML_PARSE_NOERROR, CONST_CS | CONST_PERSISTENT); ! 613: REGISTER_LONG_CONSTANT("LIBXML_NOWARNING", XML_PARSE_NOWARNING, CONST_CS | CONST_PERSISTENT); ! 614: REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS", XML_PARSE_NOBLANKS, CONST_CS | CONST_PERSISTENT); ! 615: REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE", XML_PARSE_XINCLUDE, CONST_CS | CONST_PERSISTENT); ! 616: REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN", XML_PARSE_NSCLEAN, CONST_CS | CONST_PERSISTENT); ! 617: REGISTER_LONG_CONSTANT("LIBXML_NOCDATA", XML_PARSE_NOCDATA, CONST_CS | CONST_PERSISTENT); ! 618: REGISTER_LONG_CONSTANT("LIBXML_NONET", XML_PARSE_NONET, CONST_CS | CONST_PERSISTENT); ! 619: #if LIBXML_VERSION >= 20621 ! 620: REGISTER_LONG_CONSTANT("LIBXML_COMPACT", XML_PARSE_COMPACT, CONST_CS | CONST_PERSISTENT); ! 621: REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL", XML_SAVE_NO_DECL, CONST_CS | CONST_PERSISTENT); ! 622: #endif ! 623: #if LIBXML_VERSION >= 20703 ! 624: REGISTER_LONG_CONSTANT("LIBXML_PARSEHUGE", XML_PARSE_HUGE, CONST_CS | CONST_PERSISTENT); ! 625: #endif ! 626: REGISTER_LONG_CONSTANT("LIBXML_NOEMPTYTAG", LIBXML_SAVE_NOEMPTYTAG, CONST_CS | CONST_PERSISTENT); ! 627: ! 628: /* Error levels */ ! 629: REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE", XML_ERR_NONE, CONST_CS | CONST_PERSISTENT); ! 630: REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING", XML_ERR_WARNING, CONST_CS | CONST_PERSISTENT); ! 631: REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR", XML_ERR_ERROR, CONST_CS | CONST_PERSISTENT); ! 632: REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL", XML_ERR_FATAL, CONST_CS | CONST_PERSISTENT); ! 633: ! 634: INIT_CLASS_ENTRY(ce, "LibXMLError", NULL); ! 635: libxmlerror_class_entry = zend_register_internal_class(&ce TSRMLS_CC); ! 636: ! 637: return SUCCESS; ! 638: } ! 639: ! 640: ! 641: static PHP_RINIT_FUNCTION(libxml) ! 642: { ! 643: /* report errors via handler rather than stderr */ ! 644: xmlSetGenericErrorFunc(NULL, php_libxml_error_handler); ! 645: xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename); ! 646: xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename); ! 647: return SUCCESS; ! 648: } ! 649: ! 650: ! 651: static PHP_MSHUTDOWN_FUNCTION(libxml) ! 652: { ! 653: php_libxml_shutdown(); ! 654: ! 655: return SUCCESS; ! 656: } ! 657: ! 658: ! 659: static PHP_RSHUTDOWN_FUNCTION(libxml) ! 660: { ! 661: /* reset libxml generic error handling */ ! 662: xmlSetGenericErrorFunc(NULL, NULL); ! 663: xmlSetStructuredErrorFunc(NULL, NULL); ! 664: ! 665: xmlParserInputBufferCreateFilenameDefault(NULL); ! 666: xmlOutputBufferCreateFilenameDefault(NULL); ! 667: ! 668: if (LIBXML(stream_context)) { ! 669: zval_ptr_dtor(&LIBXML(stream_context)); ! 670: LIBXML(stream_context) = NULL; ! 671: } ! 672: smart_str_free(&LIBXML(error_buffer)); ! 673: if (LIBXML(error_list)) { ! 674: zend_llist_destroy(LIBXML(error_list)); ! 675: efree(LIBXML(error_list)); ! 676: LIBXML(error_list) = NULL; ! 677: } ! 678: xmlResetLastError(); ! 679: ! 680: return SUCCESS; ! 681: } ! 682: ! 683: ! 684: static PHP_MINFO_FUNCTION(libxml) ! 685: { ! 686: php_info_print_table_start(); ! 687: php_info_print_table_row(2, "libXML support", "active"); ! 688: php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION); ! 689: php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion); ! 690: php_info_print_table_row(2, "libXML streams", "enabled"); ! 691: php_info_print_table_end(); ! 692: } ! 693: /* }}} */ ! 694: ! 695: /* {{{ proto void libxml_set_streams_context(resource streams_context) ! 696: Set the streams context for the next libxml document load or write */ ! 697: static PHP_FUNCTION(libxml_set_streams_context) ! 698: { ! 699: zval *arg; ! 700: ! 701: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) { ! 702: return; ! 703: } ! 704: if (LIBXML(stream_context)) { ! 705: zval_ptr_dtor(&LIBXML(stream_context)); ! 706: LIBXML(stream_context) = NULL; ! 707: } ! 708: Z_ADDREF_P(arg); ! 709: LIBXML(stream_context) = arg; ! 710: } ! 711: /* }}} */ ! 712: ! 713: /* {{{ proto bool libxml_use_internal_errors([boolean use_errors]) ! 714: Disable libxml errors and allow user to fetch error information as needed */ ! 715: static PHP_FUNCTION(libxml_use_internal_errors) ! 716: { ! 717: xmlStructuredErrorFunc current_handler; ! 718: zend_bool use_errors=0, retval; ! 719: ! 720: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &use_errors) == FAILURE) { ! 721: return; ! 722: } ! 723: ! 724: current_handler = xmlStructuredError; ! 725: if (current_handler && current_handler == php_libxml_structured_error_handler) { ! 726: retval = 1; ! 727: } else { ! 728: retval = 0; ! 729: } ! 730: ! 731: if (ZEND_NUM_ARGS() == 0) { ! 732: RETURN_BOOL(retval); ! 733: } ! 734: ! 735: if (use_errors == 0) { ! 736: xmlSetStructuredErrorFunc(NULL, NULL); ! 737: if (LIBXML(error_list)) { ! 738: zend_llist_destroy(LIBXML(error_list)); ! 739: efree(LIBXML(error_list)); ! 740: LIBXML(error_list) = NULL; ! 741: } ! 742: } else { ! 743: xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler); ! 744: if (LIBXML(error_list) == NULL) { ! 745: LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist)); ! 746: zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0); ! 747: } ! 748: } ! 749: RETURN_BOOL(retval); ! 750: } ! 751: /* }}} */ ! 752: ! 753: /* {{{ proto object libxml_get_last_error() ! 754: Retrieve last error from libxml */ ! 755: static PHP_FUNCTION(libxml_get_last_error) ! 756: { ! 757: xmlErrorPtr error; ! 758: ! 759: error = xmlGetLastError(); ! 760: ! 761: if (error) { ! 762: object_init_ex(return_value, libxmlerror_class_entry); ! 763: add_property_long(return_value, "level", error->level); ! 764: add_property_long(return_value, "code", error->code); ! 765: add_property_long(return_value, "column", error->int2); ! 766: if (error->message) { ! 767: add_property_string(return_value, "message", error->message, 1); ! 768: } else { ! 769: add_property_stringl(return_value, "message", "", 0, 1); ! 770: } ! 771: if (error->file) { ! 772: add_property_string(return_value, "file", error->file, 1); ! 773: } else { ! 774: add_property_stringl(return_value, "file", "", 0, 1); ! 775: } ! 776: add_property_long(return_value, "line", error->line); ! 777: } else { ! 778: RETURN_FALSE; ! 779: } ! 780: } ! 781: /* }}} */ ! 782: ! 783: /* {{{ proto object libxml_get_errors() ! 784: Retrieve array of errors */ ! 785: static PHP_FUNCTION(libxml_get_errors) ! 786: { ! 787: ! 788: xmlErrorPtr error; ! 789: ! 790: if (array_init(return_value) == FAILURE) { ! 791: RETURN_FALSE; ! 792: } ! 793: ! 794: if (LIBXML(error_list)) { ! 795: ! 796: error = zend_llist_get_first(LIBXML(error_list)); ! 797: ! 798: while (error != NULL) { ! 799: zval *z_error; ! 800: MAKE_STD_ZVAL(z_error); ! 801: ! 802: object_init_ex(z_error, libxmlerror_class_entry); ! 803: add_property_long(z_error, "level", error->level); ! 804: add_property_long(z_error, "code", error->code); ! 805: add_property_long(z_error, "column", error->int2); ! 806: if (error->message) { ! 807: add_property_string(z_error, "message", error->message, 1); ! 808: } else { ! 809: add_property_stringl(z_error, "message", "", 0, 1); ! 810: } ! 811: if (error->file) { ! 812: add_property_string(z_error, "file", error->file, 1); ! 813: } else { ! 814: add_property_stringl(z_error, "file", "", 0, 1); ! 815: } ! 816: add_property_long(z_error, "line", error->line); ! 817: add_next_index_zval(return_value, z_error); ! 818: ! 819: error = zend_llist_get_next(LIBXML(error_list)); ! 820: } ! 821: } ! 822: } ! 823: /* }}} */ ! 824: ! 825: /* {{{ proto void libxml_clear_errors() ! 826: Clear last error from libxml */ ! 827: static PHP_FUNCTION(libxml_clear_errors) ! 828: { ! 829: xmlResetLastError(); ! 830: if (LIBXML(error_list)) { ! 831: zend_llist_clean(LIBXML(error_list)); ! 832: } ! 833: } ! 834: /* }}} */ ! 835: ! 836: /* {{{ proto bool libxml_disable_entity_loader([boolean disable]) ! 837: Disable/Enable ability to load external entities */ ! 838: static PHP_FUNCTION(libxml_disable_entity_loader) ! 839: { ! 840: zend_bool disable = 1; ! 841: xmlParserInputBufferCreateFilenameFunc old; ! 842: ! 843: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &disable) == FAILURE) { ! 844: return; ! 845: } ! 846: ! 847: if (disable == 0) { ! 848: old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename); ! 849: } else { ! 850: old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_noload); ! 851: } ! 852: ! 853: if (old == php_libxml_input_buffer_noload) { ! 854: RETURN_TRUE; ! 855: } ! 856: ! 857: RETURN_FALSE; ! 858: } ! 859: /* }}} */ ! 860: ! 861: /* {{{ Common functions shared by extensions */ ! 862: int php_libxml_xmlCheckUTF8(const unsigned char *s) ! 863: { ! 864: int i; ! 865: unsigned char c; ! 866: ! 867: for (i = 0; (c = s[i++]);) { ! 868: if ((c & 0x80) == 0) { ! 869: } else if ((c & 0xe0) == 0xc0) { ! 870: if ((s[i++] & 0xc0) != 0x80) { ! 871: return 0; ! 872: } ! 873: } else if ((c & 0xf0) == 0xe0) { ! 874: if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) { ! 875: return 0; ! 876: } ! 877: } else if ((c & 0xf8) == 0xf0) { ! 878: if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) { ! 879: return 0; ! 880: } ! 881: } else { ! 882: return 0; ! 883: } ! 884: } ! 885: return 1; ! 886: } ! 887: ! 888: int php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function) ! 889: { ! 890: php_libxml_func_handler export_hnd; ! 891: ! 892: /* Initialize in case this module hasnt been loaded yet */ ! 893: php_libxml_initialize(); ! 894: export_hnd.export_func = export_function; ! 895: ! 896: return zend_hash_add(&php_libxml_exports, ce->name, ce->name_length + 1, &export_hnd, sizeof(export_hnd), NULL); ! 897: } ! 898: ! 899: PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object TSRMLS_DC) ! 900: { ! 901: zend_class_entry *ce = NULL; ! 902: xmlNodePtr node = NULL; ! 903: php_libxml_func_handler *export_hnd; ! 904: ! 905: if (object->type == IS_OBJECT) { ! 906: ce = Z_OBJCE_P(object); ! 907: while (ce->parent != NULL) { ! 908: ce = ce->parent; ! 909: } ! 910: if (zend_hash_find(&php_libxml_exports, ce->name, ce->name_length + 1, (void **) &export_hnd) == SUCCESS) { ! 911: node = export_hnd->export_func(object TSRMLS_CC); ! 912: } ! 913: } ! 914: return node; ! 915: } ! 916: ! 917: PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC) ! 918: { ! 919: int ret_refcount = -1; ! 920: ! 921: if (object != NULL && node != NULL) { ! 922: if (object->node != NULL) { ! 923: if (object->node->node == node) { ! 924: return object->node->refcount; ! 925: } else { ! 926: php_libxml_decrement_node_ptr(object TSRMLS_CC); ! 927: } ! 928: } ! 929: if (node->_private != NULL) { ! 930: object->node = node->_private; ! 931: ret_refcount = ++object->node->refcount; ! 932: /* Only dom uses _private */ ! 933: if (object->node->_private == NULL) { ! 934: object->node->_private = private_data; ! 935: } ! 936: } else { ! 937: ret_refcount = 1; ! 938: object->node = emalloc(sizeof(php_libxml_node_ptr)); ! 939: object->node->node = node; ! 940: object->node->refcount = 1; ! 941: object->node->_private = private_data; ! 942: node->_private = object->node; ! 943: } ! 944: } ! 945: ! 946: return ret_refcount; ! 947: } ! 948: ! 949: PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC) ! 950: { ! 951: int ret_refcount = -1; ! 952: php_libxml_node_ptr *obj_node; ! 953: ! 954: if (object != NULL && object->node != NULL) { ! 955: obj_node = (php_libxml_node_ptr *) object->node; ! 956: ret_refcount = --obj_node->refcount; ! 957: if (ret_refcount == 0) { ! 958: if (obj_node->node != NULL) { ! 959: obj_node->node->_private = NULL; ! 960: } ! 961: efree(obj_node); ! 962: } ! 963: object->node = NULL; ! 964: } ! 965: ! 966: return ret_refcount; ! 967: } ! 968: ! 969: PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC) ! 970: { ! 971: int ret_refcount = -1; ! 972: ! 973: if (object->document != NULL) { ! 974: object->document->refcount++; ! 975: ret_refcount = object->document->refcount; ! 976: } else if (docp != NULL) { ! 977: ret_refcount = 1; ! 978: object->document = emalloc(sizeof(php_libxml_ref_obj)); ! 979: object->document->ptr = docp; ! 980: object->document->refcount = ret_refcount; ! 981: object->document->doc_props = NULL; ! 982: } ! 983: ! 984: return ret_refcount; ! 985: } ! 986: ! 987: PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC) ! 988: { ! 989: int ret_refcount = -1; ! 990: ! 991: if (object != NULL && object->document != NULL) { ! 992: ret_refcount = --object->document->refcount; ! 993: if (ret_refcount == 0) { ! 994: if (object->document->ptr != NULL) { ! 995: xmlFreeDoc((xmlDoc *) object->document->ptr); ! 996: } ! 997: if (object->document->doc_props != NULL) { ! 998: if (object->document->doc_props->classmap) { ! 999: zend_hash_destroy(object->document->doc_props->classmap); ! 1000: FREE_HASHTABLE(object->document->doc_props->classmap); ! 1001: } ! 1002: efree(object->document->doc_props); ! 1003: } ! 1004: efree(object->document); ! 1005: object->document = NULL; ! 1006: } ! 1007: } ! 1008: ! 1009: return ret_refcount; ! 1010: } ! 1011: ! 1012: PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC) ! 1013: { ! 1014: if (!node) { ! 1015: return; ! 1016: } ! 1017: ! 1018: switch (node->type) { ! 1019: case XML_DOCUMENT_NODE: ! 1020: case XML_HTML_DOCUMENT_NODE: ! 1021: break; ! 1022: default: ! 1023: if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) { ! 1024: php_libxml_node_free_list((xmlNodePtr) node->children TSRMLS_CC); ! 1025: switch (node->type) { ! 1026: /* Skip property freeing for the following types */ ! 1027: case XML_ATTRIBUTE_DECL: ! 1028: case XML_DTD_NODE: ! 1029: case XML_DOCUMENT_TYPE_NODE: ! 1030: case XML_ENTITY_DECL: ! 1031: case XML_ATTRIBUTE_NODE: ! 1032: case XML_NAMESPACE_DECL: ! 1033: case XML_TEXT_NODE: ! 1034: break; ! 1035: default: ! 1036: php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC); ! 1037: } ! 1038: if (php_libxml_unregister_node(node TSRMLS_CC) == 0) { ! 1039: node->doc = NULL; ! 1040: } ! 1041: php_libxml_node_free(node); ! 1042: } else { ! 1043: php_libxml_unregister_node(node TSRMLS_CC); ! 1044: } ! 1045: } ! 1046: } ! 1047: ! 1048: PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC) ! 1049: { ! 1050: int ret_refcount = -1; ! 1051: xmlNodePtr nodep; ! 1052: php_libxml_node_ptr *obj_node; ! 1053: ! 1054: if (object != NULL && object->node != NULL) { ! 1055: obj_node = (php_libxml_node_ptr *) object->node; ! 1056: nodep = object->node->node; ! 1057: ret_refcount = php_libxml_decrement_node_ptr(object TSRMLS_CC); ! 1058: if (ret_refcount == 0) { ! 1059: php_libxml_node_free_resource(nodep TSRMLS_CC); ! 1060: } else { ! 1061: if (obj_node && object == obj_node->_private) { ! 1062: obj_node->_private = NULL; ! 1063: } ! 1064: } ! 1065: } ! 1066: if (object != NULL && object->document != NULL) { ! 1067: /* Safe to call as if the resource were freed then doc pointer is NULL */ ! 1068: php_libxml_decrement_doc_ref(object TSRMLS_CC); ! 1069: } ! 1070: } ! 1071: /* }}} */ ! 1072: ! 1073: #ifdef PHP_WIN32 ! 1074: PHP_LIBXML_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) ! 1075: { ! 1076: return xmlDllMain(hinstDLL, fdwReason, lpvReserved); ! 1077: } ! 1078: #endif ! 1079: ! 1080: #endif ! 1081: ! 1082: /* ! 1083: * Local variables: ! 1084: * tab-width: 4 ! 1085: * c-basic-offset: 4 ! 1086: * End: ! 1087: * vim600: sw=4 ts=4 fdm=marker ! 1088: * vim<600: sw=4 ts=4 ! 1089: */