Annotation of embedaddon/php/ext/libxml/libxml.c, revision 1.1.1.1
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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>