xref: /PHP-8.0/ext/dom/document.c (revision c283c3ab)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | http://www.php.net/license/3_01.txt                                  |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Christian Stocker <chregu@php.net>                          |
14    |          Rob Richards <rrichards@php.net>                            |
15    +----------------------------------------------------------------------+
16 */
17 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include "php.h"
23 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
24 #include "php_dom.h"
25 #include <libxml/SAX.h>
26 #ifdef LIBXML_SCHEMAS_ENABLED
27 #include <libxml/relaxng.h>
28 #include <libxml/xmlschemas.h>
29 #endif
30 
31 typedef struct _idsIterator idsIterator;
32 struct _idsIterator {
33 	xmlChar *elementId;
34 	xmlNode *element;
35 };
36 
37 #define DOM_LOAD_STRING 0
38 #define DOM_LOAD_FILE 1
39 
40 /*
41 * class DOMDocument extends DOMNode
42 *
43 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-i-Document
44 * Since:
45 */
46 
47 /* {{{ docType	DOMDocumentType
48 readonly=yes
49 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-B63ED1A31
50 Since:
51 */
dom_document_doctype_read(dom_object * obj,zval * retval)52 int dom_document_doctype_read(dom_object *obj, zval *retval)
53 {
54 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
55 	xmlDtdPtr dtdptr;
56 
57 	if (docp == NULL) {
58 		php_dom_throw_error(INVALID_STATE_ERR, 0);
59 		return FAILURE;
60 	}
61 
62 	dtdptr = xmlGetIntSubset(docp);
63 	if (!dtdptr) {
64 		ZVAL_NULL(retval);
65 		return SUCCESS;
66 	}
67 
68 	php_dom_create_object((xmlNodePtr) dtdptr, retval, obj);
69 	return SUCCESS;
70 }
71 
72 /* }}} */
73 
74 /* {{{ implementation	DOMImplementation
75 readonly=yes
76 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1B793EBA
77 Since:
78 */
dom_document_implementation_read(dom_object * obj,zval * retval)79 int dom_document_implementation_read(dom_object *obj, zval *retval)
80 {
81 	php_dom_create_implementation(retval);
82 	return SUCCESS;
83 }
84 
85 /* }}} */
86 
87 /* {{{ documentElement	DOMElement
88 readonly=yes
89 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-87CD092
90 Since:
91 */
dom_document_document_element_read(dom_object * obj,zval * retval)92 int dom_document_document_element_read(dom_object *obj, zval *retval)
93 {
94 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
95 	xmlNode *root;
96 
97 	if (docp == NULL) {
98 		php_dom_throw_error(INVALID_STATE_ERR, 0);
99 		return FAILURE;
100 	}
101 
102 	root = xmlDocGetRootElement(docp);
103 	if (!root) {
104 		ZVAL_NULL(retval);
105 		return SUCCESS;
106 	}
107 
108 	php_dom_create_object(root, retval, obj);
109 	return SUCCESS;
110 }
111 
112 /* }}} */
113 
114 /* {{{ encoding	string
115 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-encoding
116 Since: DOM Level 3
117 */
dom_document_encoding_read(dom_object * obj,zval * retval)118 int dom_document_encoding_read(dom_object *obj, zval *retval)
119 {
120 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
121 	char *encoding;
122 
123 	if (docp == NULL) {
124 		php_dom_throw_error(INVALID_STATE_ERR, 0);
125 		return FAILURE;
126 	}
127 
128 	encoding = (char *) docp->encoding;
129 
130 	if (encoding != NULL) {
131 		ZVAL_STRING(retval, encoding);
132 	} else {
133 		ZVAL_NULL(retval);
134 	}
135 
136 	return SUCCESS;
137 }
138 
dom_document_encoding_write(dom_object * obj,zval * newval)139 zend_result dom_document_encoding_write(dom_object *obj, zval *newval)
140 {
141 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
142 	zend_string *str;
143 	xmlCharEncodingHandlerPtr handler;
144 
145 	if (docp == NULL) {
146 		php_dom_throw_error(INVALID_STATE_ERR, 0);
147 		return FAILURE;
148 	}
149 
150 	str = zval_try_get_string(newval);
151 	if (UNEXPECTED(!str)) {
152 		return FAILURE;
153 	}
154 
155 	handler = xmlFindCharEncodingHandler(ZSTR_VAL(str));
156 
157     if (handler != NULL) {
158 		xmlCharEncCloseFunc(handler);
159 		if (docp->encoding != NULL) {
160 			xmlFree((xmlChar *)docp->encoding);
161 		}
162 		docp->encoding = xmlStrdup((const xmlChar *) ZSTR_VAL(str));
163     } else {
164 		zend_value_error("Invalid document encoding");
165 		return FAILURE;
166     }
167 
168 	zend_string_release_ex(str, 0);
169 	return SUCCESS;
170 }
171 
172 /* }}} */
173 
174 /* {{{ standalone	boolean
175 readonly=no
176 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-standalone
177 Since: DOM Level 3
178 */
dom_document_standalone_read(dom_object * obj,zval * retval)179 int dom_document_standalone_read(dom_object *obj, zval *retval)
180 {
181 	xmlDoc *docp;
182 
183 	docp = (xmlDocPtr) dom_object_get_node(obj);
184 
185 	if (docp == NULL) {
186 		php_dom_throw_error(INVALID_STATE_ERR, 0);
187 		return FAILURE;
188 	}
189 
190 	ZVAL_BOOL(retval, docp->standalone);
191 	return SUCCESS;
192 }
193 
dom_document_standalone_write(dom_object * obj,zval * newval)194 int dom_document_standalone_write(dom_object *obj, zval *newval)
195 {
196 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
197 	zend_long standalone;
198 
199 	if (docp == NULL) {
200 		php_dom_throw_error(INVALID_STATE_ERR, 0);
201 		return FAILURE;
202 	}
203 
204 	standalone = zval_get_long(newval);
205 	docp->standalone = ZEND_NORMALIZE_BOOL(standalone);
206 
207 	return SUCCESS;
208 }
209 
210 /* }}} */
211 
212 /* {{{ version	string
213 readonly=no
214 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-version
215 Since: DOM Level 3
216 */
dom_document_version_read(dom_object * obj,zval * retval)217 int dom_document_version_read(dom_object *obj, zval *retval)
218 {
219 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
220 	char *version;
221 
222 	if (docp == NULL) {
223 		php_dom_throw_error(INVALID_STATE_ERR, 0);
224 		return FAILURE;
225 	}
226 
227 	version = (char *) docp->version;
228 
229 	if (version != NULL) {
230 		ZVAL_STRING(retval, version);
231 	} else {
232 		ZVAL_NULL(retval);
233 	}
234 
235 	return SUCCESS;
236 }
237 
dom_document_version_write(dom_object * obj,zval * newval)238 int dom_document_version_write(dom_object *obj, zval *newval)
239 {
240 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
241 	zend_string *str;
242 
243 	if (docp == NULL) {
244 		php_dom_throw_error(INVALID_STATE_ERR, 0);
245 		return FAILURE;
246 	}
247 
248 	str = zval_try_get_string(newval);
249 	if (UNEXPECTED(!str)) {
250 		return FAILURE;
251 	}
252 
253 	if (docp->version != NULL) {
254 		xmlFree((xmlChar *) docp->version );
255 	}
256 
257 	docp->version = xmlStrdup((const xmlChar *) ZSTR_VAL(str));
258 
259 	zend_string_release_ex(str, 0);
260 	return SUCCESS;
261 }
262 
263 /* }}} */
264 
265 /* {{{ strictErrorChecking	boolean
266 readonly=no
267 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-strictErrorChecking
268 Since: DOM Level 3
269 */
dom_document_strict_error_checking_read(dom_object * obj,zval * retval)270 int dom_document_strict_error_checking_read(dom_object *obj, zval *retval)
271 {
272 	if (obj->document) {
273 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
274 		ZVAL_BOOL(retval, doc_prop->stricterror);
275 	} else {
276 		ZVAL_FALSE(retval);
277 	}
278 	return SUCCESS;
279 }
280 
dom_document_strict_error_checking_write(dom_object * obj,zval * newval)281 int dom_document_strict_error_checking_write(dom_object *obj, zval *newval)
282 {
283 
284 	if (obj->document) {
285 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
286 		doc_prop->stricterror = zend_is_true(newval);
287 	}
288 
289 	return SUCCESS;
290 }
291 
292 /* }}} */
293 
294 /* {{{ formatOutput	boolean
295 readonly=no
296 */
dom_document_format_output_read(dom_object * obj,zval * retval)297 int dom_document_format_output_read(dom_object *obj, zval *retval)
298 {
299 	if (obj->document) {
300 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
301 		ZVAL_BOOL(retval, doc_prop->formatoutput);
302 	} else {
303 		ZVAL_FALSE(retval);
304 	}
305 	return SUCCESS;
306 }
307 
dom_document_format_output_write(dom_object * obj,zval * newval)308 int dom_document_format_output_write(dom_object *obj, zval *newval)
309 {
310 	if (obj->document) {
311 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
312 		doc_prop->formatoutput = zend_is_true(newval);
313 	}
314 
315 	return SUCCESS;
316 }
317 /* }}} */
318 
319 /* {{{ validateOnParse	boolean
320 readonly=no
321 */
dom_document_validate_on_parse_read(dom_object * obj,zval * retval)322 int	dom_document_validate_on_parse_read(dom_object *obj, zval *retval)
323 {
324 	if (obj->document) {
325 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
326 		ZVAL_BOOL(retval, doc_prop->validateonparse);
327 	} else {
328 		ZVAL_FALSE(retval);
329 	}
330 	return SUCCESS;
331 }
332 
dom_document_validate_on_parse_write(dom_object * obj,zval * newval)333 int dom_document_validate_on_parse_write(dom_object *obj, zval *newval)
334 {
335 	if (obj->document) {
336 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
337 		doc_prop->validateonparse = zend_is_true(newval);
338 	}
339 
340 	return SUCCESS;
341 }
342 /* }}} */
343 
344 /* {{{ resolveExternals	boolean
345 readonly=no
346 */
dom_document_resolve_externals_read(dom_object * obj,zval * retval)347 int dom_document_resolve_externals_read(dom_object *obj, zval *retval)
348 {
349 	if (obj->document) {
350 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
351 		ZVAL_BOOL(retval, doc_prop->resolveexternals);
352 	} else {
353 		ZVAL_FALSE(retval);
354 	}
355 	return SUCCESS;
356 }
357 
dom_document_resolve_externals_write(dom_object * obj,zval * newval)358 int dom_document_resolve_externals_write(dom_object *obj, zval *newval)
359 {
360 	if (obj->document) {
361 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
362 		doc_prop->resolveexternals = zend_is_true(newval);
363 	}
364 
365 	return SUCCESS;
366 }
367 /* }}} */
368 
369 /* {{{ preserveWhiteSpace	boolean
370 readonly=no
371 */
dom_document_preserve_whitespace_read(dom_object * obj,zval * retval)372 int dom_document_preserve_whitespace_read(dom_object *obj, zval *retval)
373 {
374 	if (obj->document) {
375 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
376 		ZVAL_BOOL(retval, doc_prop->preservewhitespace);
377 	} else {
378 		ZVAL_FALSE(retval);
379 	}
380 	return SUCCESS;
381 }
382 
dom_document_preserve_whitespace_write(dom_object * obj,zval * newval)383 int dom_document_preserve_whitespace_write(dom_object *obj, zval *newval)
384 {
385 	if (obj->document) {
386 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
387 		doc_prop->preservewhitespace = zend_is_true(newval);
388 	}
389 
390 	return SUCCESS;
391 }
392 /* }}} */
393 
394 /* {{{ recover	boolean
395 readonly=no
396 */
dom_document_recover_read(dom_object * obj,zval * retval)397 int dom_document_recover_read(dom_object *obj, zval *retval)
398 {
399 	if (obj->document) {
400 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
401 		ZVAL_BOOL(retval, doc_prop->recover);
402 	} else {
403 		ZVAL_FALSE(retval);
404 	}
405 	return SUCCESS;
406 }
407 
dom_document_recover_write(dom_object * obj,zval * newval)408 int dom_document_recover_write(dom_object *obj, zval *newval)
409 {
410 	if (obj->document) {
411 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
412 		doc_prop->recover = zend_is_true(newval);
413 	}
414 
415 	return SUCCESS;
416 }
417 /* }}} */
418 
419 /* {{{ substituteEntities	boolean
420 readonly=no
421 */
dom_document_substitue_entities_read(dom_object * obj,zval * retval)422 int dom_document_substitue_entities_read(dom_object *obj, zval *retval)
423 {
424 	if (obj->document) {
425 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
426 		ZVAL_BOOL(retval, doc_prop->substituteentities);
427 	} else {
428 		ZVAL_FALSE(retval);
429 	}
430 	return SUCCESS;
431 }
432 
dom_document_substitue_entities_write(dom_object * obj,zval * newval)433 int dom_document_substitue_entities_write(dom_object *obj, zval *newval)
434 {
435 	if (obj->document) {
436 		dom_doc_propsptr doc_prop = dom_get_doc_props(obj->document);
437 		doc_prop->substituteentities = zend_is_true(newval);
438 	}
439 
440 	return SUCCESS;
441 }
442 /* }}} */
443 
444 /* {{{ documentURI	string
445 readonly=no
446 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-documentURI
447 Since: DOM Level 3
448 */
dom_document_document_uri_read(dom_object * obj,zval * retval)449 int dom_document_document_uri_read(dom_object *obj, zval *retval)
450 {
451 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
452 	char *url;
453 
454 	if (docp == NULL) {
455 		php_dom_throw_error(INVALID_STATE_ERR, 0);
456 		return FAILURE;
457 	}
458 
459 	url = (char *) docp->URL;
460 	if (url != NULL) {
461 		ZVAL_STRING(retval, url);
462 	} else {
463 		ZVAL_NULL(retval);
464 	}
465 
466 	return SUCCESS;
467 }
468 
dom_document_document_uri_write(dom_object * obj,zval * newval)469 int dom_document_document_uri_write(dom_object *obj, zval *newval)
470 {
471 	xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj);
472 	zend_string *str;
473 
474 	if (docp == NULL) {
475 		php_dom_throw_error(INVALID_STATE_ERR, 0);
476 		return FAILURE;
477 	}
478 
479 	str = zval_try_get_string(newval);
480 	if (UNEXPECTED(!str)) {
481 		return FAILURE;
482 	}
483 
484 	if (docp->URL != NULL) {
485 		xmlFree((xmlChar *) docp->URL);
486 	}
487 
488 	docp->URL = xmlStrdup((const xmlChar *) ZSTR_VAL(str));
489 
490 	zend_string_release_ex(str, 0);
491 	return SUCCESS;
492 }
493 
494 /* }}} */
495 
496 /* {{{ config	DOMConfiguration
497 readonly=yes
498 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-config
499 Since: DOM Level 3
500 */
dom_document_config_read(dom_object * obj,zval * retval)501 int dom_document_config_read(dom_object *obj, zval *retval)
502 {
503 	ZVAL_NULL(retval);
504 	return SUCCESS;
505 }
506 
507 /* }}} */
508 
509 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-2141741547
510 Since:
511 */
PHP_METHOD(DOMDocument,createElement)512 PHP_METHOD(DOMDocument, createElement)
513 {
514 	zval *id;
515 	xmlNode *node;
516 	xmlDocPtr docp;
517 	dom_object *intern;
518 	int ret;
519 	size_t name_len, value_len;
520 	char *name, *value = NULL;
521 
522 	id = ZEND_THIS;
523 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &name, &name_len, &value, &value_len) == FAILURE) {
524 		RETURN_THROWS();
525 	}
526 
527 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
528 
529 	if (xmlValidateName((xmlChar *) name, 0) != 0) {
530 		php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
531 		RETURN_FALSE;
532 	}
533 
534 	node = xmlNewDocNode(docp, NULL, (xmlChar *) name, (xmlChar *) value);
535 	if (!node) {
536 		RETURN_FALSE;
537 	}
538 
539 	DOM_RET_OBJ(node, &ret, intern);
540 }
541 /* }}} end dom_document_create_element */
542 
543 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-35CB04B5
544 Since:
545 */
PHP_METHOD(DOMDocument,createDocumentFragment)546 PHP_METHOD(DOMDocument, createDocumentFragment)
547 {
548 	zval *id;
549 	xmlNode *node;
550 	xmlDocPtr docp;
551 	dom_object *intern;
552 	int ret;
553 
554 	id = ZEND_THIS;
555 	if (zend_parse_parameters_none() == FAILURE) {
556 		RETURN_THROWS();
557 	}
558 
559 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
560 
561 	node =  xmlNewDocFragment(docp);
562 	if (!node) {
563 		RETURN_FALSE;
564 	}
565 
566 	DOM_RET_OBJ(node, &ret, intern);
567 }
568 /* }}} end dom_document_create_document_fragment */
569 
570 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1975348127
571 Since:
572 */
PHP_METHOD(DOMDocument,createTextNode)573 PHP_METHOD(DOMDocument, createTextNode)
574 {
575 	zval *id;
576 	xmlNode *node;
577 	xmlDocPtr docp;
578 	int ret;
579 	size_t value_len;
580 	dom_object *intern;
581 	char *value;
582 
583 	id = ZEND_THIS;
584 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len) == FAILURE) {
585 		RETURN_THROWS();
586 	}
587 
588 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
589 
590 	node = xmlNewDocText(docp, (xmlChar *) value);
591 	if (!node) {
592 		RETURN_FALSE;
593 	}
594 
595 	DOM_RET_OBJ(node, &ret, intern);
596 }
597 /* }}} end dom_document_create_text_node */
598 
599 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1334481328
600 Since:
601 */
PHP_METHOD(DOMDocument,createComment)602 PHP_METHOD(DOMDocument, createComment)
603 {
604 	zval *id;
605 	xmlNode *node;
606 	xmlDocPtr docp;
607 	int ret;
608 	size_t value_len;
609 	dom_object *intern;
610 	char *value;
611 
612 	id = ZEND_THIS;
613 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len) == FAILURE) {
614 		RETURN_THROWS();
615 	}
616 
617 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
618 
619 	node = xmlNewDocComment(docp, (xmlChar *) value);
620 	if (!node) {
621 		RETURN_FALSE;
622 	}
623 
624 	DOM_RET_OBJ(node, &ret, intern);
625 }
626 /* }}} end dom_document_create_comment */
627 
628 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-D26C0AF8
629 Since:
630 */
PHP_METHOD(DOMDocument,createCDATASection)631 PHP_METHOD(DOMDocument, createCDATASection)
632 {
633 	zval *id;
634 	xmlNode *node;
635 	xmlDocPtr docp;
636 	int ret;
637 	size_t value_len;
638 	dom_object *intern;
639 	char *value;
640 
641 	id = ZEND_THIS;
642 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len) == FAILURE) {
643 		RETURN_THROWS();
644 	}
645 
646 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
647 
648 	node = xmlNewCDataBlock(docp, (xmlChar *) value, value_len);
649 	if (!node) {
650 		RETURN_FALSE;
651 	}
652 
653 	DOM_RET_OBJ(node, &ret, intern);
654 }
655 /* }}} end dom_document_create_cdatasection */
656 
657 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-135944439
658 Since:
659 */
PHP_METHOD(DOMDocument,createProcessingInstruction)660 PHP_METHOD(DOMDocument, createProcessingInstruction)
661 {
662 	zval *id;
663 	xmlNode *node;
664 	xmlDocPtr docp;
665 	int ret;
666 	size_t value_len, name_len = 0;
667 	dom_object *intern;
668 	char *name, *value = NULL;
669 
670 	id = ZEND_THIS;
671 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &name, &name_len, &value, &value_len) == FAILURE) {
672 		RETURN_THROWS();
673 	}
674 
675 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
676 
677 	if (xmlValidateName((xmlChar *) name, 0) != 0) {
678 		php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
679 		RETURN_FALSE;
680 	}
681 
682 	node = xmlNewPI((xmlChar *) name, (xmlChar *) value);
683 	if (!node) {
684 		RETURN_FALSE;
685 	}
686 
687 	node->doc = docp;
688 
689 	DOM_RET_OBJ(node, &ret, intern);
690 }
691 /* }}} end dom_document_create_processing_instruction */
692 
693 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1084891198
694 Since:
695 */
PHP_METHOD(DOMDocument,createAttribute)696 PHP_METHOD(DOMDocument, createAttribute)
697 {
698 	zval *id;
699 	xmlAttrPtr node;
700 	xmlDocPtr docp;
701 	int ret;
702 	size_t name_len;
703 	dom_object *intern;
704 	char *name;
705 
706 	id = ZEND_THIS;
707 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
708 		RETURN_THROWS();
709 	}
710 
711 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
712 
713 	if (xmlValidateName((xmlChar *) name, 0) != 0) {
714 		php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
715 		RETURN_FALSE;
716 	}
717 
718 	node = xmlNewDocProp(docp, (xmlChar *) name, NULL);
719 	if (!node) {
720 		RETURN_FALSE;
721 	}
722 
723 	DOM_RET_OBJ((xmlNodePtr) node, &ret, intern);
724 
725 }
726 /* }}} end dom_document_create_attribute */
727 
728 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-392B75AE
729 Since:
730 */
PHP_METHOD(DOMDocument,createEntityReference)731 PHP_METHOD(DOMDocument, createEntityReference)
732 {
733 	zval *id;
734 	xmlNode *node;
735 	xmlDocPtr docp = NULL;
736 	dom_object *intern;
737 	int ret;
738 	size_t name_len;
739 	char *name;
740 
741 	id = ZEND_THIS;
742 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
743 		RETURN_THROWS();
744 	}
745 
746 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
747 
748 	if (xmlValidateName((xmlChar *) name, 0) != 0) {
749 		php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
750 		RETURN_FALSE;
751 	}
752 
753 	node = xmlNewReference(docp, (xmlChar *) name);
754 	if (!node) {
755 		RETURN_FALSE;
756 	}
757 
758 	DOM_RET_OBJ((xmlNodePtr) node, &ret, intern);
759 }
760 /* }}} end dom_document_create_entity_reference */
761 
762 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-A6C9094
763 Since:
764 */
PHP_METHOD(DOMDocument,getElementsByTagName)765 PHP_METHOD(DOMDocument, getElementsByTagName)
766 {
767 	zval *id;
768 	xmlDocPtr docp;
769 	size_t name_len;
770 	dom_object *intern, *namednode;
771 	char *name;
772 	xmlChar *local;
773 
774 	id = ZEND_THIS;
775 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
776 		RETURN_THROWS();
777 	}
778 
779 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
780 
781 	php_dom_create_iterator(return_value, DOM_NODELIST);
782 	namednode = Z_DOMOBJ_P(return_value);
783 	local = xmlCharStrndup(name, name_len);
784 	dom_namednode_iter(intern, 0, namednode, NULL, local, NULL);
785 }
786 /* }}} end dom_document_get_elements_by_tag_name */
787 
788 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Core-Document-importNode
789 Since: DOM Level 2
790 */
PHP_METHOD(DOMDocument,importNode)791 PHP_METHOD(DOMDocument, importNode)
792 {
793 	zval *id, *node;
794 	xmlDocPtr docp;
795 	xmlNodePtr nodep, retnodep;
796 	dom_object *intern, *nodeobj;
797 	int ret;
798 	zend_bool recursive = 0;
799 	/* See http://www.xmlsoft.org/html/libxml-tree.html#xmlDocCopyNode for meaning of values */
800 	int extended_recursive;
801 
802 	id = ZEND_THIS;
803 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &node, dom_node_class_entry, &recursive) == FAILURE) {
804 		RETURN_THROWS();
805 	}
806 
807 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
808 
809 	DOM_GET_OBJ(nodep, node, xmlNodePtr, nodeobj);
810 
811 	if (nodep->type == XML_HTML_DOCUMENT_NODE || nodep->type == XML_DOCUMENT_NODE
812 		|| nodep->type == XML_DOCUMENT_TYPE_NODE) {
813 		php_error_docref(NULL, E_WARNING, "Cannot import: Node Type Not Supported");
814 		RETURN_FALSE;
815 	}
816 
817 	if (nodep->doc == docp) {
818 		retnodep = nodep;
819 	} else {
820 		extended_recursive = recursive;
821 		if ((recursive == 0) && (nodep->type == XML_ELEMENT_NODE)) {
822 			extended_recursive = 2;
823 		}
824 		retnodep = xmlDocCopyNode(nodep, docp, extended_recursive);
825 		if (!retnodep) {
826 			RETURN_FALSE;
827 		}
828 
829 		if ((retnodep->type == XML_ATTRIBUTE_NODE) && (nodep->ns != NULL)) {
830 			xmlNsPtr nsptr = NULL;
831 			xmlNodePtr root = xmlDocGetRootElement(docp);
832 
833 			nsptr = xmlSearchNsByHref (nodep->doc, root, nodep->ns->href);
834 			if (nsptr == NULL) {
835 				int errorcode;
836 				nsptr = dom_get_ns(root, (char *) nodep->ns->href, &errorcode, (char *) nodep->ns->prefix);
837 			}
838 			xmlSetNs(retnodep, nsptr);
839 		}
840 	}
841 
842 	DOM_RET_OBJ((xmlNodePtr) retnodep, &ret, intern);
843 }
844 /* }}} end dom_document_import_node */
845 
846 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrElNS
847 Since: DOM Level 2
848 */
PHP_METHOD(DOMDocument,createElementNS)849 PHP_METHOD(DOMDocument, createElementNS)
850 {
851 	zval *id;
852 	xmlDocPtr docp;
853 	xmlNodePtr nodep = NULL;
854 	xmlNsPtr nsptr = NULL;
855 	int ret;
856 	size_t uri_len = 0, name_len = 0, value_len = 0;
857 	char *uri, *name, *value = NULL;
858 	char *localname = NULL, *prefix = NULL;
859 	int errorcode;
860 	dom_object *intern;
861 
862 	id = ZEND_THIS;
863 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s|s", &uri, &uri_len, &name, &name_len, &value, &value_len) == FAILURE) {
864 		RETURN_THROWS();
865 	}
866 
867 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
868 
869 	errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
870 
871 	if (errorcode == 0) {
872 		if (xmlValidateName((xmlChar *) localname, 0) == 0) {
873 			nodep = xmlNewDocNode(docp, NULL, (xmlChar *) localname, (xmlChar *) value);
874 			if (nodep != NULL && uri != NULL) {
875 				nsptr = xmlSearchNsByHref(nodep->doc, nodep, (xmlChar *) uri);
876 				if (nsptr == NULL) {
877 					nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);
878 				}
879 				xmlSetNs(nodep, nsptr);
880 			}
881 		} else {
882 			errorcode = INVALID_CHARACTER_ERR;
883 		}
884 	}
885 
886 	xmlFree(localname);
887 	if (prefix != NULL) {
888 		xmlFree(prefix);
889 	}
890 
891 	if (errorcode != 0) {
892 		if (nodep != NULL) {
893 			xmlFreeNode(nodep);
894 		}
895 		php_dom_throw_error(errorcode, dom_get_strict_error(intern->document));
896 		RETURN_FALSE;
897 	}
898 
899 	if (nodep == NULL) {
900 		RETURN_FALSE;
901 	}
902 
903 
904 	nodep->ns = nsptr;
905 
906 	DOM_RET_OBJ(nodep, &ret, intern);
907 }
908 /* }}} end dom_document_create_element_ns */
909 
910 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrAttrNS
911 Since: DOM Level 2
912 */
PHP_METHOD(DOMDocument,createAttributeNS)913 PHP_METHOD(DOMDocument, createAttributeNS)
914 {
915 	zval *id;
916 	xmlDocPtr docp;
917 	xmlNodePtr nodep = NULL, root;
918 	xmlNsPtr nsptr;
919 	int ret;
920 	size_t uri_len = 0, name_len = 0;
921 	char *uri, *name;
922 	char *localname = NULL, *prefix = NULL;
923 	dom_object *intern;
924 	int errorcode;
925 
926 	id = ZEND_THIS;
927 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
928 		RETURN_THROWS();
929 	}
930 
931 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
932 
933 	root = xmlDocGetRootElement(docp);
934 	if (root != NULL) {
935 		errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
936 		if (errorcode == 0) {
937 			if (xmlValidateName((xmlChar *) localname, 0) == 0) {
938 				nodep = (xmlNodePtr) xmlNewDocProp(docp, (xmlChar *) localname, NULL);
939 				if (nodep != NULL && uri_len > 0) {
940 					nsptr = xmlSearchNsByHref(nodep->doc, root, (xmlChar *) uri);
941 					if (nsptr == NULL) {
942 						nsptr = dom_get_ns(root, uri, &errorcode, prefix);
943 					}
944 					xmlSetNs(nodep, nsptr);
945 				}
946 			} else {
947 				errorcode = INVALID_CHARACTER_ERR;
948 			}
949 		}
950 	} else {
951 		php_error_docref(NULL, E_WARNING, "Document Missing Root Element");
952 		RETURN_FALSE;
953 	}
954 
955 	xmlFree(localname);
956 	if (prefix != NULL) {
957 		xmlFree(prefix);
958 	}
959 
960 	if (errorcode != 0) {
961 		if (nodep != NULL) {
962 			xmlFreeProp((xmlAttrPtr) nodep);
963 		}
964 		php_dom_throw_error(errorcode, dom_get_strict_error(intern->document));
965 		RETURN_FALSE;
966 	}
967 
968 	if (nodep == NULL) {
969 		RETURN_FALSE;
970 	}
971 
972 	DOM_RET_OBJ(nodep, &ret, intern);
973 }
974 /* }}} end dom_document_create_attribute_ns */
975 
976 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBTNNS
977 Since: DOM Level 2
978 */
PHP_METHOD(DOMDocument,getElementsByTagNameNS)979 PHP_METHOD(DOMDocument, getElementsByTagNameNS)
980 {
981 	zval *id;
982 	xmlDocPtr docp;
983 	size_t uri_len, name_len;
984 	dom_object *intern, *namednode;
985 	char *uri, *name;
986 	xmlChar *local, *nsuri;
987 
988 	id = ZEND_THIS;
989 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
990 		RETURN_THROWS();
991 	}
992 
993 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
994 
995 	php_dom_create_iterator(return_value, DOM_NODELIST);
996 	namednode = Z_DOMOBJ_P(return_value);
997 	local = xmlCharStrndup(name, name_len);
998 	nsuri = xmlCharStrndup(uri ? uri : "", uri_len);
999 	dom_namednode_iter(intern, 0, namednode, NULL, local, nsuri);
1000 }
1001 /* }}} end dom_document_get_elements_by_tag_name_ns */
1002 
1003 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBId
1004 Since: DOM Level 2
1005 */
PHP_METHOD(DOMDocument,getElementById)1006 PHP_METHOD(DOMDocument, getElementById)
1007 {
1008 	zval *id;
1009 	xmlDocPtr docp;
1010 	xmlAttrPtr  attrp;
1011 	int ret;
1012 	size_t idname_len;
1013 	dom_object *intern;
1014 	char *idname;
1015 
1016 	id = ZEND_THIS;
1017 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &idname, &idname_len) == FAILURE) {
1018 		RETURN_THROWS();
1019 	}
1020 
1021 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1022 
1023 	attrp = xmlGetID(docp, (xmlChar *) idname);
1024 
1025 	if (attrp && attrp->parent) {
1026 		DOM_RET_OBJ((xmlNodePtr) attrp->parent, &ret, intern);
1027 	} else {
1028 		RETVAL_NULL();
1029 	}
1030 
1031 }
1032 /* }}} end dom_document_get_element_by_id */
1033 
1034 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-adoptNode
1035 Since: DOM Level 3
1036 */
PHP_METHOD(DOMDocument,adoptNode)1037 PHP_METHOD(DOMDocument, adoptNode)
1038 {
1039 	zval *nodep = NULL;
1040 
1041 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &nodep, dom_node_class_entry) == FAILURE) {
1042 		RETURN_THROWS();
1043 	}
1044 
1045 	DOM_NOT_IMPLEMENTED();
1046 }
1047 /* }}} end dom_document_adopt_node */
1048 
1049 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-normalizeDocument
1050 Since: DOM Level 3
1051 */
PHP_METHOD(DOMDocument,normalizeDocument)1052 PHP_METHOD(DOMDocument, normalizeDocument)
1053 {
1054 	zval *id;
1055 	xmlDocPtr docp;
1056 	dom_object *intern;
1057 
1058 	id = ZEND_THIS;
1059 	if (zend_parse_parameters_none() == FAILURE) {
1060 		RETURN_THROWS();
1061 	}
1062 
1063 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1064 
1065 	dom_normalize((xmlNodePtr) docp);
1066 }
1067 /* }}} end dom_document_normalize_document */
1068 
1069 /* {{{ */
PHP_METHOD(DOMDocument,__construct)1070 PHP_METHOD(DOMDocument, __construct)
1071 {
1072 	xmlDoc *docp = NULL, *olddoc;
1073 	dom_object *intern;
1074 	char *encoding, *version = NULL;
1075 	size_t encoding_len = 0, version_len = 0;
1076 	int refcount;
1077 
1078 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ss", &version, &version_len, &encoding, &encoding_len) == FAILURE) {
1079 		RETURN_THROWS();
1080 	}
1081 
1082 	docp = xmlNewDoc((xmlChar *) version);
1083 
1084 	if (!docp) {
1085 		php_dom_throw_error(INVALID_STATE_ERR, 1);
1086 		return;
1087 	}
1088 
1089 	if (encoding_len > 0) {
1090 		docp->encoding = (const xmlChar *) xmlStrdup((xmlChar *) encoding);
1091 	}
1092 
1093 	intern = Z_DOMOBJ_P(ZEND_THIS);
1094 	if (intern != NULL) {
1095 		olddoc = (xmlDocPtr) dom_object_get_node(intern);
1096 		if (olddoc != NULL) {
1097 			php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1098 			refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1099 			if (refcount != 0) {
1100 				olddoc->_private = NULL;
1101 			}
1102 		}
1103 		intern->document = NULL;
1104 		if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, docp) == -1) {
1105 			/* docp is always non-null so php_libxml_increment_doc_ref() never returns -1 */
1106 			ZEND_UNREACHABLE();
1107 		}
1108 		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)docp, (void *)intern);
1109 	}
1110 }
1111 /* }}} end DOMDocument::__construct */
1112 
_dom_get_valid_file_path(char * source,char * resolved_path,int resolved_path_len)1113 char *_dom_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len ) /* {{{ */
1114 {
1115 	xmlURI *uri;
1116 	xmlChar *escsource;
1117 	char *file_dest;
1118 	int isFileUri = 0;
1119 
1120 	uri = xmlCreateURI();
1121 	escsource = xmlURIEscapeStr((xmlChar *) source, (xmlChar *) ":");
1122 	xmlParseURIReference(uri, (char *) escsource);
1123 	xmlFree(escsource);
1124 
1125 	if (uri->scheme != NULL) {
1126 		/* absolute file uris - libxml only supports localhost or empty host */
1127 #ifdef PHP_WIN32
1128 		if (strncasecmp(source, "file://",7) == 0 && ':' == source[8]) {
1129 			isFileUri = 1;
1130 			source += 7;
1131 		} else
1132 #endif
1133 		if (strncasecmp(source, "file:///",8) == 0) {
1134 			isFileUri = 1;
1135 #ifdef PHP_WIN32
1136 			source += 8;
1137 #else
1138 			source += 7;
1139 #endif
1140 		} else if (strncasecmp(source, "file://localhost/",17) == 0) {
1141 			isFileUri = 1;
1142 #ifdef PHP_WIN32
1143 			source += 17;
1144 #else
1145 			source += 16;
1146 #endif
1147 		}
1148 	}
1149 
1150 	file_dest = source;
1151 
1152 	if ((uri->scheme == NULL || isFileUri)) {
1153 		/* XXX possible buffer overflow if VCWD_REALPATH does not know size of resolved_path */
1154 		if (!VCWD_REALPATH(source, resolved_path) && !expand_filepath(source, resolved_path)) {
1155 			xmlFreeURI(uri);
1156 			return NULL;
1157 		}
1158 		file_dest = resolved_path;
1159 	}
1160 
1161 	xmlFreeURI(uri);
1162 
1163 	return file_dest;
1164 }
1165 /* }}} */
1166 
dom_document_parser(zval * id,int mode,char * source,size_t source_len,size_t options)1167 static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t source_len, size_t options) /* {{{ */
1168 {
1169     xmlDocPtr ret;
1170     xmlParserCtxtPtr ctxt = NULL;
1171 	dom_doc_propsptr doc_props;
1172 	dom_object *intern;
1173 	php_libxml_ref_obj *document = NULL;
1174 	int validate, recover, resolve_externals, keep_blanks, substitute_ent;
1175 	int resolved_path_len;
1176 	int old_error_reporting = 0;
1177 	char *directory=NULL, resolved_path[MAXPATHLEN + 1];
1178 
1179 	if (id != NULL) {
1180 		intern = Z_DOMOBJ_P(id);
1181 		document = intern->document;
1182 	}
1183 
1184 	doc_props = dom_get_doc_props(document);
1185 	validate = doc_props->validateonparse;
1186 	resolve_externals = doc_props->resolveexternals;
1187 	keep_blanks = doc_props->preservewhitespace;
1188 	substitute_ent = doc_props->substituteentities;
1189 	recover = doc_props->recover;
1190 
1191 	if (document == NULL) {
1192 		efree(doc_props);
1193 	}
1194 
1195 	xmlInitParser();
1196 
1197 	if (mode == DOM_LOAD_FILE) {
1198 		char *file_dest;
1199 		if (CHECK_NULL_PATH(source, source_len)) {
1200 			zend_value_error("Path to document must not contain any null bytes");
1201 			return NULL;
1202 		}
1203 		file_dest = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1204 		if (file_dest) {
1205 			ctxt = xmlCreateFileParserCtxt(file_dest);
1206 		}
1207 
1208 	} else {
1209 		ctxt = xmlCreateMemoryParserCtxt(source, source_len);
1210 	}
1211 
1212 	if (ctxt == NULL) {
1213 		return(NULL);
1214 	}
1215 
1216 	/* If loading from memory, we need to set the base directory for the document */
1217 	if (mode != DOM_LOAD_FILE) {
1218 #ifdef HAVE_GETCWD
1219 		directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
1220 #elif defined(HAVE_GETWD)
1221 		directory = VCWD_GETWD(resolved_path);
1222 #endif
1223 		if (directory) {
1224 			if(ctxt->directory != NULL) {
1225 				xmlFree((char *) ctxt->directory);
1226 			}
1227 			resolved_path_len = strlen(resolved_path);
1228 			if (resolved_path[resolved_path_len - 1] != DEFAULT_SLASH) {
1229 				resolved_path[resolved_path_len] = DEFAULT_SLASH;
1230 				resolved_path[++resolved_path_len] = '\0';
1231 			}
1232 			ctxt->directory = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
1233 		}
1234 	}
1235 
1236 	ctxt->vctxt.error = php_libxml_ctx_error;
1237 	ctxt->vctxt.warning = php_libxml_ctx_warning;
1238 
1239 	if (ctxt->sax != NULL) {
1240 		ctxt->sax->error = php_libxml_ctx_error;
1241 		ctxt->sax->warning = php_libxml_ctx_warning;
1242 	}
1243 
1244 	if (validate && ! (options & XML_PARSE_DTDVALID)) {
1245 		options |= XML_PARSE_DTDVALID;
1246 	}
1247 	if (resolve_externals && ! (options & XML_PARSE_DTDATTR)) {
1248 		options |= XML_PARSE_DTDATTR;
1249 	}
1250 	if (substitute_ent && ! (options & XML_PARSE_NOENT)) {
1251 		options |= XML_PARSE_NOENT;
1252 	}
1253 	if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) {
1254 		options |= XML_PARSE_NOBLANKS;
1255 	}
1256 
1257 	php_libxml_sanitize_parse_ctxt_options(ctxt);
1258 	xmlCtxtUseOptions(ctxt, options);
1259 
1260 	ctxt->recovery = recover;
1261 	if (recover) {
1262 		old_error_reporting = EG(error_reporting);
1263 		EG(error_reporting) = old_error_reporting | E_WARNING;
1264 	}
1265 
1266 	xmlParseDocument(ctxt);
1267 
1268 	if (ctxt->wellFormed || recover) {
1269 		ret = ctxt->myDoc;
1270 		if (ctxt->recovery) {
1271 			EG(error_reporting) = old_error_reporting;
1272 		}
1273 		/* If loading from memory, set the base reference uri for the document */
1274 		if (ret && ret->URL == NULL && ctxt->directory != NULL) {
1275 			ret->URL = xmlStrdup((xmlChar *) ctxt->directory);
1276 		}
1277 	} else {
1278 		ret = NULL;
1279 		xmlFreeDoc(ctxt->myDoc);
1280 		ctxt->myDoc = NULL;
1281 	}
1282 
1283 	xmlFreeParserCtxt(ctxt);
1284 
1285 	return(ret);
1286 }
1287 /* }}} */
1288 
1289 /* {{{ static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) */
dom_parse_document(INTERNAL_FUNCTION_PARAMETERS,int mode)1290 static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) {
1291 	zval *id;
1292 	xmlDoc *docp = NULL, *newdoc;
1293 	dom_doc_propsptr doc_prop;
1294 	dom_object *intern;
1295 	char *source;
1296 	size_t source_len;
1297 	int refcount, ret;
1298 	zend_long options = 0;
1299 
1300 	id = getThis();
1301 	if (id != NULL && ! instanceof_function(Z_OBJCE_P(id), dom_document_class_entry)) {
1302 		id = NULL;
1303 	}
1304 
1305 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
1306 		RETURN_THROWS();
1307 	}
1308 
1309 	if (!source_len) {
1310 		zend_argument_value_error(1, "must not be empty");
1311 		RETURN_THROWS();
1312 	}
1313 	if (ZEND_SIZE_T_INT_OVFL(source_len)) {
1314 		php_error_docref(NULL, E_WARNING, "Input string is too long");
1315 		RETURN_FALSE;
1316 	}
1317 	if (ZEND_LONG_EXCEEDS_INT(options)) {
1318 		php_error_docref(NULL, E_WARNING, "Invalid options");
1319 		RETURN_FALSE;
1320 	}
1321 
1322 	newdoc = dom_document_parser(id, mode, source, source_len, options);
1323 
1324 	if (!newdoc)
1325 		RETURN_FALSE;
1326 
1327 	if (id != NULL) {
1328 		intern = Z_DOMOBJ_P(id);
1329 		if (intern != NULL) {
1330 			docp = (xmlDocPtr) dom_object_get_node(intern);
1331 			doc_prop = NULL;
1332 			if (docp != NULL) {
1333 				php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1334 				doc_prop = intern->document->doc_props;
1335 				intern->document->doc_props = NULL;
1336 				refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1337 				if (refcount != 0) {
1338 					docp->_private = NULL;
1339 				}
1340 			}
1341 			intern->document = NULL;
1342 			if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
1343 				RETURN_FALSE;
1344 			}
1345 			intern->document->doc_props = doc_prop;
1346 		}
1347 
1348 		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
1349 
1350 		RETURN_TRUE;
1351 	} else {
1352 		DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1353 	}
1354 }
1355 /* }}} end dom_parser_document */
1356 
1357 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-load
1358 Since: DOM Level 3
1359 */
PHP_METHOD(DOMDocument,load)1360 PHP_METHOD(DOMDocument, load)
1361 {
1362 	dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1363 }
1364 /* }}} end dom_document_load */
1365 
1366 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-loadXML
1367 Since: DOM Level 3
1368 */
PHP_METHOD(DOMDocument,loadXML)1369 PHP_METHOD(DOMDocument, loadXML)
1370 {
1371 	dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1372 }
1373 /* }}} end dom_document_loadxml */
1374 
1375 /* {{{ Convenience method to save to file */
PHP_METHOD(DOMDocument,save)1376 PHP_METHOD(DOMDocument, save)
1377 {
1378 	zval *id;
1379 	xmlDoc *docp;
1380 	size_t file_len = 0;
1381 	int bytes, format, saveempty = 0;
1382 	dom_object *intern;
1383 	dom_doc_propsptr doc_props;
1384 	char *file;
1385 	zend_long options = 0;
1386 
1387 	id = ZEND_THIS;
1388 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &file, &file_len, &options) == FAILURE) {
1389 		RETURN_THROWS();
1390 	}
1391 
1392 	if (file_len == 0) {
1393 		zend_argument_value_error(1, "must not be empty");
1394 		RETURN_THROWS();
1395 	}
1396 
1397 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1398 
1399 	/* encoding handled by property on doc */
1400 
1401 	doc_props = dom_get_doc_props(intern->document);
1402 	format = doc_props->formatoutput;
1403 	if (options & LIBXML_SAVE_NOEMPTYTAG) {
1404 		saveempty = xmlSaveNoEmptyTags;
1405 		xmlSaveNoEmptyTags = 1;
1406 	}
1407 	bytes = xmlSaveFormatFileEnc(file, docp, NULL, format);
1408 	if (options & LIBXML_SAVE_NOEMPTYTAG) {
1409 		xmlSaveNoEmptyTags = saveempty;
1410 	}
1411 	if (bytes == -1) {
1412 		RETURN_FALSE;
1413 	}
1414 	RETURN_LONG(bytes);
1415 }
1416 /* }}} end dom_document_save */
1417 
1418 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-saveXML
1419 Since: DOM Level 3
1420 */
PHP_METHOD(DOMDocument,saveXML)1421 PHP_METHOD(DOMDocument, saveXML)
1422 {
1423 	zval *id, *nodep = NULL;
1424 	xmlDoc *docp;
1425 	xmlNode *node;
1426 	xmlBufferPtr buf;
1427 	xmlChar *mem;
1428 	dom_object *intern, *nodeobj;
1429 	dom_doc_propsptr doc_props;
1430 	int size, format, saveempty = 0;
1431 	zend_long options = 0;
1432 
1433 	id = ZEND_THIS;
1434 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!l", &nodep, dom_node_class_entry, &options) == FAILURE) {
1435 		RETURN_THROWS();
1436 	}
1437 
1438 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1439 
1440 	doc_props = dom_get_doc_props(intern->document);
1441 	format = doc_props->formatoutput;
1442 
1443 	if (nodep != NULL) {
1444 		/* Dump contents of Node */
1445 		DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1446 		if (node->doc != docp) {
1447 			php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
1448 			RETURN_FALSE;
1449 		}
1450 		buf = xmlBufferCreate();
1451 		if (!buf) {
1452 			php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
1453 			RETURN_FALSE;
1454 		}
1455 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1456 			saveempty = xmlSaveNoEmptyTags;
1457 			xmlSaveNoEmptyTags = 1;
1458 		}
1459 		xmlNodeDump(buf, docp, node, 0, format);
1460 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1461 			xmlSaveNoEmptyTags = saveempty;
1462 		}
1463 		mem = (xmlChar*) xmlBufferContent(buf);
1464 		if (!mem) {
1465 			xmlBufferFree(buf);
1466 			RETURN_FALSE;
1467 		}
1468 		RETVAL_STRING((char *) mem);
1469 		xmlBufferFree(buf);
1470 	} else {
1471 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1472 			saveempty = xmlSaveNoEmptyTags;
1473 			xmlSaveNoEmptyTags = 1;
1474 		}
1475 		/* Encoding is handled from the encoding property set on the document */
1476 		xmlDocDumpFormatMemory(docp, &mem, &size, format);
1477 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1478 			xmlSaveNoEmptyTags = saveempty;
1479 		}
1480 		if (!size || !mem) {
1481 			RETURN_FALSE;
1482 		}
1483 		RETVAL_STRINGL((char *) mem, size);
1484 		xmlFree(mem);
1485 	}
1486 }
1487 /* }}} end dom_document_savexml */
1488 
php_dom_free_xinclude_node(xmlNodePtr cur)1489 static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur) /* {{{ */
1490 {
1491 	xmlNodePtr xincnode;
1492 
1493 	xincnode = cur;
1494 	cur = cur->next;
1495 	xmlUnlinkNode(xincnode);
1496 	php_libxml_node_free_resource(xincnode);
1497 
1498 	return cur;
1499 }
1500 /* }}} */
1501 
php_dom_remove_xinclude_nodes(xmlNodePtr cur)1502 static void php_dom_remove_xinclude_nodes(xmlNodePtr cur) /* {{{ */
1503 {
1504 	while(cur) {
1505 		if (cur->type == XML_XINCLUDE_START) {
1506 			cur = php_dom_free_xinclude_node(cur);
1507 
1508 			/* XML_XINCLUDE_END node will be a sibling of XML_XINCLUDE_START */
1509 			while(cur && cur->type != XML_XINCLUDE_END) {
1510 				/* remove xinclude processing nodes from recursive xincludes */
1511 				if (cur->type == XML_ELEMENT_NODE) {
1512 					   php_dom_remove_xinclude_nodes(cur->children);
1513 				}
1514 				cur = cur->next;
1515 			}
1516 
1517 			if (cur && cur->type == XML_XINCLUDE_END) {
1518 				cur = php_dom_free_xinclude_node(cur);
1519 			}
1520 		} else {
1521 			if (cur->type == XML_ELEMENT_NODE) {
1522 				php_dom_remove_xinclude_nodes(cur->children);
1523 			}
1524 			cur = cur->next;
1525 		}
1526 	}
1527 }
1528 /* }}} */
1529 
1530 /* {{{ Substitutues xincludes in a DomDocument */
PHP_METHOD(DOMDocument,xinclude)1531 PHP_METHOD(DOMDocument, xinclude)
1532 {
1533 	zval *id;
1534 	xmlDoc *docp;
1535 	xmlNodePtr root;
1536 	zend_long flags = 0;
1537 	int err;
1538 	dom_object *intern;
1539 
1540 	id = ZEND_THIS;
1541 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags) == FAILURE) {
1542 		RETURN_THROWS();
1543 	}
1544 
1545 	if (ZEND_LONG_EXCEEDS_INT(flags)) {
1546 		php_error_docref(NULL, E_WARNING, "Invalid flags");
1547 		RETURN_FALSE;
1548 	}
1549 
1550 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1551 
1552 	PHP_LIBXML_SANITIZE_GLOBALS(xinclude);
1553 	err = xmlXIncludeProcessFlags(docp, (int)flags);
1554 	PHP_LIBXML_RESTORE_GLOBALS(xinclude);
1555 
1556 	/* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1557 	are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1558 	but are not wanted in resulting document - must be done even if err as it could fail after
1559 	having processed some xincludes */
1560 	root = (xmlNodePtr) docp->children;
1561 	while(root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1562 		root = root->next;
1563 	}
1564 	if (root) {
1565 		php_dom_remove_xinclude_nodes(root);
1566 	}
1567 
1568 	if (err) {
1569 		RETVAL_LONG(err);
1570 	} else {
1571 		RETVAL_FALSE;
1572 	}
1573 
1574 }
1575 /* }}} */
1576 
1577 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,validate)1578 PHP_METHOD(DOMDocument, validate)
1579 {
1580 	zval *id;
1581 	xmlDoc *docp;
1582 	dom_object *intern;
1583 	xmlValidCtxt *cvp;
1584 
1585 	id = ZEND_THIS;
1586 	if (zend_parse_parameters_none() == FAILURE) {
1587 		RETURN_THROWS();
1588 	}
1589 
1590 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1591 
1592 	PHP_LIBXML_SANITIZE_GLOBALS(validate);
1593 	cvp = xmlNewValidCtxt();
1594 
1595 	cvp->userData = NULL;
1596 	cvp->error    = (xmlValidityErrorFunc) php_libxml_error_handler;
1597 	cvp->warning  = (xmlValidityErrorFunc) php_libxml_error_handler;
1598 
1599 	if (xmlValidateDocument(cvp, docp)) {
1600 		RETVAL_TRUE;
1601 	} else {
1602 		RETVAL_FALSE;
1603 	}
1604 	PHP_LIBXML_RESTORE_GLOBALS(validate);
1605 
1606 	xmlFreeValidCtxt(cvp);
1607 
1608 }
1609 /* }}} */
1610 
1611 #ifdef LIBXML_SCHEMAS_ENABLED
_dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS,int type)1612 static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1613 {
1614 	zval *id;
1615 	xmlDoc *docp;
1616 	dom_object *intern;
1617 	char *source = NULL, *valid_file = NULL;
1618 	size_t source_len = 0;
1619 	int valid_opts = 0;
1620 	zend_long flags = 0;
1621 	xmlSchemaParserCtxtPtr  parser;
1622 	xmlSchemaPtr            sptr;
1623 	xmlSchemaValidCtxtPtr   vptr;
1624 	int                     is_valid;
1625 	char resolved_path[MAXPATHLEN + 1];
1626 
1627 	id = ZEND_THIS;
1628 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &flags) == FAILURE) {
1629 		RETURN_THROWS();
1630 	}
1631 
1632 	if (!source_len) {
1633 		zend_argument_value_error(1, "must not be empty");
1634 		RETURN_THROWS();
1635 	}
1636 
1637 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1638 
1639 	PHP_LIBXML_SANITIZE_GLOBALS(new_parser_ctxt);
1640 
1641 	switch (type) {
1642 	case DOM_LOAD_FILE:
1643 		if (CHECK_NULL_PATH(source, source_len)) {
1644 			PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
1645 			zend_argument_value_error(1, "must not contain any null bytes");
1646 			RETURN_THROWS();
1647 		}
1648 		valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1649 		if (!valid_file) {
1650 			PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
1651 			php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
1652 			RETURN_FALSE;
1653 		}
1654 		parser = xmlSchemaNewParserCtxt(valid_file);
1655 		break;
1656 	case DOM_LOAD_STRING:
1657 		parser = xmlSchemaNewMemParserCtxt(source, source_len);
1658 		/* If loading from memory, we need to set the base directory for the document
1659 		   but it is not apparent how to do that for schema's */
1660 		break;
1661 	default:
1662 		return;
1663 	}
1664 
1665 	xmlSchemaSetParserErrors(parser,
1666 		(xmlSchemaValidityErrorFunc) php_libxml_error_handler,
1667 		(xmlSchemaValidityWarningFunc) php_libxml_error_handler,
1668 		parser);
1669 	sptr = xmlSchemaParse(parser);
1670 	xmlSchemaFreeParserCtxt(parser);
1671 	PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
1672 	if (!sptr) {
1673 		if (!EG(exception)) {
1674 			php_error_docref(NULL, E_WARNING, "Invalid Schema");
1675 		}
1676 		RETURN_FALSE;
1677 	}
1678 
1679 	docp = (xmlDocPtr) dom_object_get_node(intern);
1680 
1681 	vptr = xmlSchemaNewValidCtxt(sptr);
1682 	if (!vptr) {
1683 		xmlSchemaFree(sptr);
1684 		zend_throw_error(NULL, "Invalid Schema Validation Context");
1685 		RETURN_THROWS();
1686 	}
1687 
1688 	if (flags & XML_SCHEMA_VAL_VC_I_CREATE) {
1689 		valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE;
1690 	}
1691 
1692 	PHP_LIBXML_SANITIZE_GLOBALS(validate);
1693 	xmlSchemaSetValidOptions(vptr, valid_opts);
1694 	xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1695 	is_valid = xmlSchemaValidateDoc(vptr, docp);
1696 	xmlSchemaFree(sptr);
1697 	xmlSchemaFreeValidCtxt(vptr);
1698 	PHP_LIBXML_RESTORE_GLOBALS(validate);
1699 
1700 	if (is_valid == 0) {
1701 		RETURN_TRUE;
1702 	} else {
1703 		RETURN_FALSE;
1704 	}
1705 }
1706 /* }}} */
1707 
1708 /* {{{ */
PHP_METHOD(DOMDocument,schemaValidate)1709 PHP_METHOD(DOMDocument, schemaValidate)
1710 {
1711 	_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1712 }
1713 /* }}} end dom_document_schema_validate_file */
1714 
1715 /* {{{ */
PHP_METHOD(DOMDocument,schemaValidateSource)1716 PHP_METHOD(DOMDocument, schemaValidateSource)
1717 {
1718 	_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1719 }
1720 /* }}} end dom_document_schema_validate */
1721 
_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS,int type)1722 static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1723 {
1724 	zval *id;
1725 	xmlDoc *docp;
1726 	dom_object *intern;
1727 	char *source = NULL, *valid_file = NULL;
1728 	size_t source_len = 0;
1729 	xmlRelaxNGParserCtxtPtr parser;
1730 	xmlRelaxNGPtr           sptr;
1731 	xmlRelaxNGValidCtxtPtr  vptr;
1732 	int                     is_valid;
1733 	char resolved_path[MAXPATHLEN + 1];
1734 
1735 	id = ZEND_THIS;
1736 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &source, &source_len) == FAILURE) {
1737 		RETURN_THROWS();
1738 	}
1739 
1740 	if (!source_len) {
1741 		zend_argument_value_error(1, "must not be empty");
1742 		RETURN_THROWS();
1743 	}
1744 
1745 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1746 
1747 	switch (type) {
1748 	case DOM_LOAD_FILE:
1749 		if (CHECK_NULL_PATH(source, source_len)) {
1750 			zend_argument_value_error(1, "must not contain any null bytes");
1751 			RETURN_THROWS();
1752 		}
1753 		valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1754 		if (!valid_file) {
1755 			php_error_docref(NULL, E_WARNING, "Invalid RelaxNG file source");
1756 			RETURN_FALSE;
1757 		}
1758 		parser = xmlRelaxNGNewParserCtxt(valid_file);
1759 		break;
1760 	case DOM_LOAD_STRING:
1761 		parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
1762 		/* If loading from memory, we need to set the base directory for the document
1763 		   but it is not apparent how to do that for schema's */
1764 		break;
1765 	default:
1766 		return;
1767 	}
1768 
1769 	PHP_LIBXML_SANITIZE_GLOBALS(parse);
1770 	xmlRelaxNGSetParserErrors(parser,
1771 		(xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
1772 		(xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
1773 		parser);
1774 	sptr = xmlRelaxNGParse(parser);
1775 	xmlRelaxNGFreeParserCtxt(parser);
1776 	PHP_LIBXML_RESTORE_GLOBALS(parse);
1777 	if (!sptr) {
1778 		php_error_docref(NULL, E_WARNING, "Invalid RelaxNG");
1779 		RETURN_FALSE;
1780 	}
1781 
1782 	docp = (xmlDocPtr) dom_object_get_node(intern);
1783 
1784 	vptr = xmlRelaxNGNewValidCtxt(sptr);
1785 	if (!vptr) {
1786 		xmlRelaxNGFree(sptr);
1787 		zend_throw_error(NULL, "Invalid RelaxNG Validation Context");
1788 		RETURN_THROWS();
1789 	}
1790 
1791 	xmlRelaxNGSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1792 	is_valid = xmlRelaxNGValidateDoc(vptr, docp);
1793 	xmlRelaxNGFree(sptr);
1794 	xmlRelaxNGFreeValidCtxt(vptr);
1795 
1796 	if (is_valid == 0) {
1797 		RETURN_TRUE;
1798 	} else {
1799 		RETURN_FALSE;
1800 	}
1801 }
1802 /* }}} */
1803 
1804 /* {{{ */
PHP_METHOD(DOMDocument,relaxNGValidate)1805 PHP_METHOD(DOMDocument, relaxNGValidate)
1806 {
1807 	_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1808 }
1809 /* }}} end dom_document_relaxNG_validate_file */
1810 
1811 /* {{{ */
PHP_METHOD(DOMDocument,relaxNGValidateSource)1812 PHP_METHOD(DOMDocument, relaxNGValidateSource)
1813 {
1814 	_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1815 }
1816 /* }}} end dom_document_relaxNG_validate_xml */
1817 
1818 #endif
1819 
1820 #ifdef LIBXML_HTML_ENABLED
1821 
dom_load_html(INTERNAL_FUNCTION_PARAMETERS,int mode)1822 static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
1823 {
1824 	zval *id;
1825 	xmlDoc *docp = NULL, *newdoc;
1826 	dom_object *intern;
1827 	dom_doc_propsptr doc_prop;
1828 	char *source;
1829 	size_t source_len;
1830 	int refcount, ret;
1831 	zend_long options = 0;
1832 	htmlParserCtxtPtr ctxt;
1833 
1834 	id = getThis();
1835 
1836 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
1837 		RETURN_THROWS();
1838 	}
1839 
1840 	if (!source_len) {
1841 		zend_argument_value_error(1, "must not be empty");
1842 		RETURN_THROWS();
1843 	}
1844 
1845 	if (ZEND_LONG_EXCEEDS_INT(options)) {
1846 		php_error_docref(NULL, E_WARNING, "Invalid options");
1847 		RETURN_FALSE;
1848 	}
1849 
1850 	if (mode == DOM_LOAD_FILE) {
1851 		if (CHECK_NULL_PATH(source, source_len)) {
1852 			zend_argument_value_error(1, "must not contain any null bytes");
1853 			RETURN_THROWS();
1854 		}
1855 		ctxt = htmlCreateFileParserCtxt(source, NULL);
1856 	} else {
1857 		if (ZEND_SIZE_T_INT_OVFL(source_len)) {
1858 			php_error_docref(NULL, E_WARNING, "Input string is too long");
1859 			RETURN_FALSE;
1860 		}
1861 		ctxt = htmlCreateMemoryParserCtxt(source, (int)source_len);
1862 	}
1863 
1864 	if (!ctxt) {
1865 		RETURN_FALSE;
1866 	}
1867 
1868 
1869 	ctxt->vctxt.error = php_libxml_ctx_error;
1870 	ctxt->vctxt.warning = php_libxml_ctx_warning;
1871 	if (ctxt->sax != NULL) {
1872 		ctxt->sax->error = php_libxml_ctx_error;
1873 		ctxt->sax->warning = php_libxml_ctx_warning;
1874 	}
1875 	php_libxml_sanitize_parse_ctxt_options(ctxt);
1876 	if (options) {
1877 		htmlCtxtUseOptions(ctxt, (int)options);
1878 	}
1879 	htmlParseDocument(ctxt);
1880 	newdoc = ctxt->myDoc;
1881 	htmlFreeParserCtxt(ctxt);
1882 
1883 	if (!newdoc)
1884 		RETURN_FALSE;
1885 
1886 	if (id != NULL && instanceof_function(Z_OBJCE_P(id), dom_document_class_entry)) {
1887 		intern = Z_DOMOBJ_P(id);
1888 		if (intern != NULL) {
1889 			docp = (xmlDocPtr) dom_object_get_node(intern);
1890 			doc_prop = NULL;
1891 			if (docp != NULL) {
1892 				php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1893 				doc_prop = intern->document->doc_props;
1894 				intern->document->doc_props = NULL;
1895 				refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1896 				if (refcount != 0) {
1897 					docp->_private = NULL;
1898 				}
1899 			}
1900 			intern->document = NULL;
1901 			if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
1902 				RETURN_FALSE;
1903 			}
1904 			intern->document->doc_props = doc_prop;
1905 		}
1906 
1907 		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
1908 
1909 		RETURN_TRUE;
1910 	} else {
1911 		DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1912 	}
1913 }
1914 /* }}} */
1915 
1916 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,loadHTMLFile)1917 PHP_METHOD(DOMDocument, loadHTMLFile)
1918 {
1919 	dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1920 }
1921 /* }}} end dom_document_load_html_file */
1922 
1923 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,loadHTML)1924 PHP_METHOD(DOMDocument, loadHTML)
1925 {
1926 	dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1927 }
1928 /* }}} end dom_document_load_html */
1929 
1930 /* {{{ Convenience method to save to file as html */
PHP_METHOD(DOMDocument,saveHTMLFile)1931 PHP_METHOD(DOMDocument, saveHTMLFile)
1932 {
1933 	zval *id;
1934 	xmlDoc *docp;
1935 	size_t file_len;
1936 	int bytes, format;
1937 	dom_object *intern;
1938 	dom_doc_propsptr doc_props;
1939 	char *file;
1940 	const char *encoding;
1941 
1942 	id = ZEND_THIS;
1943 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &file, &file_len) == FAILURE) {
1944 		RETURN_THROWS();
1945 	}
1946 
1947 	if (file_len == 0) {
1948 		zend_argument_value_error(1, "must not be empty");
1949 		RETURN_THROWS();
1950 	}
1951 
1952 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1953 
1954 
1955 	encoding = (const char *) htmlGetMetaEncoding(docp);
1956 
1957 	doc_props = dom_get_doc_props(intern->document);
1958 	format = doc_props->formatoutput;
1959 	bytes = htmlSaveFileFormat(file, docp, encoding, format);
1960 
1961 	if (bytes == -1) {
1962 		RETURN_FALSE;
1963 	}
1964 	RETURN_LONG(bytes);
1965 }
1966 /* }}} end dom_document_save_html_file */
1967 
1968 /* {{{ Convenience method to output as html */
PHP_METHOD(DOMDocument,saveHTML)1969 PHP_METHOD(DOMDocument, saveHTML)
1970 {
1971 	zval *id, *nodep = NULL;
1972 	xmlDoc *docp;
1973 	xmlNode *node;
1974 	xmlOutputBufferPtr outBuf;
1975 	xmlBufferPtr buf;
1976 	dom_object *intern, *nodeobj;
1977 	xmlChar *mem = NULL;
1978 	int format;
1979 	dom_doc_propsptr doc_props;
1980 
1981 	id = ZEND_THIS;
1982 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
1983 		"|O!", &nodep, dom_node_class_entry)
1984 		== FAILURE) {
1985 		RETURN_THROWS();
1986 	}
1987 
1988 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1989 
1990 	doc_props = dom_get_doc_props(intern->document);
1991 	format = doc_props->formatoutput;
1992 
1993 	if (nodep != NULL) {
1994 		/* Dump contents of Node */
1995 		DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1996 		if (node->doc != docp) {
1997 			php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
1998 			RETURN_FALSE;
1999 		}
2000 
2001 		buf = xmlBufferCreate();
2002 		if (!buf) {
2003 			php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
2004 			RETURN_FALSE;
2005 		}
2006 		outBuf = xmlOutputBufferCreateBuffer(buf, NULL);
2007 		if (!outBuf) {
2008 			xmlBufferFree(buf);
2009 			php_error_docref(NULL, E_WARNING, "Could not fetch output buffer");
2010 			RETURN_FALSE;
2011 		}
2012 
2013 		if (node->type == XML_DOCUMENT_FRAG_NODE) {
2014 			for (node = node->children; node; node = node->next) {
2015 				htmlNodeDumpFormatOutput(outBuf, docp, node, NULL, format);
2016 				if (outBuf->error) {
2017 					break;
2018 				}
2019 			}
2020 		} else {
2021 			htmlNodeDumpFormatOutput(outBuf, docp, node, NULL, format);
2022 		}
2023 		if (!outBuf->error) {
2024 			xmlOutputBufferFlush(outBuf);
2025 			mem = (xmlChar*) xmlBufferContent(buf);
2026 			if (!mem) {
2027 				RETVAL_FALSE;
2028 			} else {
2029 				int size = xmlBufferLength(buf);
2030 				RETVAL_STRINGL((const char*) mem, size);
2031 			}
2032 		} else {
2033 			php_error_docref(NULL, E_WARNING, "Error dumping HTML node");
2034 			RETVAL_FALSE;
2035 		}
2036 		xmlOutputBufferClose(outBuf);
2037 		xmlBufferFree(buf);
2038 	} else {
2039 		int size = 0;
2040 		htmlDocDumpMemoryFormat(docp, &mem, &size, format);
2041 		if (!size || !mem) {
2042 			RETVAL_FALSE;
2043 		} else {
2044 			RETVAL_STRINGL((const char*) mem, size);
2045 		}
2046 		if (mem)
2047 			xmlFree(mem);
2048 	}
2049 
2050 }
2051 /* }}} end dom_document_save_html */
2052 
2053 #endif  /* defined(LIBXML_HTML_ENABLED) */
2054 
2055 /* {{{ Register extended class used to create base node type */
PHP_METHOD(DOMDocument,registerNodeClass)2056 PHP_METHOD(DOMDocument, registerNodeClass)
2057 {
2058 	zval *id;
2059 	xmlDoc *docp;
2060 	zend_class_entry *basece = dom_node_class_entry, *ce = NULL;
2061 	dom_object *intern;
2062 
2063 	id = ZEND_THIS;
2064 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "CC!", &basece, &ce) == FAILURE) {
2065 		RETURN_THROWS();
2066 	}
2067 
2068 	if (ce == NULL || instanceof_function(ce, basece)) {
2069 		DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2070 		dom_set_doc_classmap(intern->document, basece, ce);
2071 		RETURN_TRUE;
2072 	}
2073 
2074 	zend_argument_error(NULL, 2, "must be a class name derived from %s or null, %s given", ZSTR_VAL(basece->name), ZSTR_VAL(ce->name));
2075 }
2076 /* }}} */
2077 
2078 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-append
2079 Since: DOM Living Standard (DOM4)
2080 */
PHP_METHOD(DOMDocument,append)2081 PHP_METHOD(DOMDocument, append)
2082 {
2083 	int argc;
2084 	zval *args, *id;
2085 	dom_object *intern;
2086 	xmlNode *context;
2087 
2088 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
2089 		RETURN_THROWS();
2090 	}
2091 
2092 	id = ZEND_THIS;
2093 	DOM_GET_OBJ(context, id, xmlNodePtr, intern);
2094 
2095 	dom_parent_node_append(intern, args, argc);
2096 }
2097 /* }}} */
2098 
2099 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
2100 Since: DOM Living Standard (DOM4)
2101 */
PHP_METHOD(DOMDocument,prepend)2102 PHP_METHOD(DOMDocument, prepend)
2103 {
2104 	int argc;
2105 	zval *args, *id;
2106 	dom_object *intern;
2107 	xmlNode *context;
2108 
2109 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
2110 		RETURN_THROWS();
2111 	}
2112 
2113 	id = ZEND_THIS;
2114 	DOM_GET_OBJ(context, id, xmlNodePtr, intern);
2115 
2116 	dom_parent_node_prepend(intern, args, argc);
2117 }
2118 /* }}} */
2119 
2120 #endif  /* HAVE_LIBXML && HAVE_DOM */
2121