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];
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 	xmlCtxtUseOptions(ctxt, options);
1258 
1259 	ctxt->recovery = recover;
1260 	if (recover) {
1261 		old_error_reporting = EG(error_reporting);
1262 		EG(error_reporting) = old_error_reporting | E_WARNING;
1263 	}
1264 
1265 	xmlParseDocument(ctxt);
1266 
1267 	if (ctxt->wellFormed || recover) {
1268 		ret = ctxt->myDoc;
1269 		if (ctxt->recovery) {
1270 			EG(error_reporting) = old_error_reporting;
1271 		}
1272 		/* If loading from memory, set the base reference uri for the document */
1273 		if (ret && ret->URL == NULL && ctxt->directory != NULL) {
1274 			ret->URL = xmlStrdup((xmlChar *) ctxt->directory);
1275 		}
1276 	} else {
1277 		ret = NULL;
1278 		xmlFreeDoc(ctxt->myDoc);
1279 		ctxt->myDoc = NULL;
1280 	}
1281 
1282 	xmlFreeParserCtxt(ctxt);
1283 
1284 	return(ret);
1285 }
1286 /* }}} */
1287 
1288 /* {{{ static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) */
dom_parse_document(INTERNAL_FUNCTION_PARAMETERS,int mode)1289 static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) {
1290 	zval *id;
1291 	xmlDoc *docp = NULL, *newdoc;
1292 	dom_doc_propsptr doc_prop;
1293 	dom_object *intern;
1294 	char *source;
1295 	size_t source_len;
1296 	int refcount, ret;
1297 	zend_long options = 0;
1298 
1299 	id = getThis();
1300 	if (id != NULL && ! instanceof_function(Z_OBJCE_P(id), dom_document_class_entry)) {
1301 		id = NULL;
1302 	}
1303 
1304 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
1305 		RETURN_THROWS();
1306 	}
1307 
1308 	if (!source_len) {
1309 		zend_argument_value_error(1, "must not be empty");
1310 		RETURN_THROWS();
1311 	}
1312 	if (ZEND_SIZE_T_INT_OVFL(source_len)) {
1313 		php_error_docref(NULL, E_WARNING, "Input string is too long");
1314 		RETURN_FALSE;
1315 	}
1316 	if (ZEND_LONG_EXCEEDS_INT(options)) {
1317 		php_error_docref(NULL, E_WARNING, "Invalid options");
1318 		RETURN_FALSE;
1319 	}
1320 
1321 	newdoc = dom_document_parser(id, mode, source, source_len, options);
1322 
1323 	if (!newdoc)
1324 		RETURN_FALSE;
1325 
1326 	if (id != NULL) {
1327 		intern = Z_DOMOBJ_P(id);
1328 		if (intern != NULL) {
1329 			docp = (xmlDocPtr) dom_object_get_node(intern);
1330 			doc_prop = NULL;
1331 			if (docp != NULL) {
1332 				php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1333 				doc_prop = intern->document->doc_props;
1334 				intern->document->doc_props = NULL;
1335 				refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1336 				if (refcount != 0) {
1337 					docp->_private = NULL;
1338 				}
1339 			}
1340 			intern->document = NULL;
1341 			if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
1342 				RETURN_FALSE;
1343 			}
1344 			intern->document->doc_props = doc_prop;
1345 		}
1346 
1347 		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
1348 
1349 		RETURN_TRUE;
1350 	} else {
1351 		DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1352 	}
1353 }
1354 /* }}} end dom_parser_document */
1355 
1356 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-load
1357 Since: DOM Level 3
1358 */
PHP_METHOD(DOMDocument,load)1359 PHP_METHOD(DOMDocument, load)
1360 {
1361 	dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1362 }
1363 /* }}} end dom_document_load */
1364 
1365 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-loadXML
1366 Since: DOM Level 3
1367 */
PHP_METHOD(DOMDocument,loadXML)1368 PHP_METHOD(DOMDocument, loadXML)
1369 {
1370 	dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1371 }
1372 /* }}} end dom_document_loadxml */
1373 
1374 /* {{{ Convenience method to save to file */
PHP_METHOD(DOMDocument,save)1375 PHP_METHOD(DOMDocument, save)
1376 {
1377 	zval *id;
1378 	xmlDoc *docp;
1379 	size_t file_len = 0;
1380 	int bytes, format, saveempty = 0;
1381 	dom_object *intern;
1382 	dom_doc_propsptr doc_props;
1383 	char *file;
1384 	zend_long options = 0;
1385 
1386 	id = ZEND_THIS;
1387 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &file, &file_len, &options) == FAILURE) {
1388 		RETURN_THROWS();
1389 	}
1390 
1391 	if (file_len == 0) {
1392 		zend_argument_value_error(1, "must not be empty");
1393 		RETURN_THROWS();
1394 	}
1395 
1396 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1397 
1398 	/* encoding handled by property on doc */
1399 
1400 	doc_props = dom_get_doc_props(intern->document);
1401 	format = doc_props->formatoutput;
1402 	if (options & LIBXML_SAVE_NOEMPTYTAG) {
1403 		saveempty = xmlSaveNoEmptyTags;
1404 		xmlSaveNoEmptyTags = 1;
1405 	}
1406 	bytes = xmlSaveFormatFileEnc(file, docp, NULL, format);
1407 	if (options & LIBXML_SAVE_NOEMPTYTAG) {
1408 		xmlSaveNoEmptyTags = saveempty;
1409 	}
1410 	if (bytes == -1) {
1411 		RETURN_FALSE;
1412 	}
1413 	RETURN_LONG(bytes);
1414 }
1415 /* }}} end dom_document_save */
1416 
1417 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-saveXML
1418 Since: DOM Level 3
1419 */
PHP_METHOD(DOMDocument,saveXML)1420 PHP_METHOD(DOMDocument, saveXML)
1421 {
1422 	zval *id, *nodep = NULL;
1423 	xmlDoc *docp;
1424 	xmlNode *node;
1425 	xmlBufferPtr buf;
1426 	xmlChar *mem;
1427 	dom_object *intern, *nodeobj;
1428 	dom_doc_propsptr doc_props;
1429 	int size, format, saveempty = 0;
1430 	zend_long options = 0;
1431 
1432 	id = ZEND_THIS;
1433 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!l", &nodep, dom_node_class_entry, &options) == FAILURE) {
1434 		RETURN_THROWS();
1435 	}
1436 
1437 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1438 
1439 	doc_props = dom_get_doc_props(intern->document);
1440 	format = doc_props->formatoutput;
1441 
1442 	if (nodep != NULL) {
1443 		/* Dump contents of Node */
1444 		DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1445 		if (node->doc != docp) {
1446 			php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
1447 			RETURN_FALSE;
1448 		}
1449 		buf = xmlBufferCreate();
1450 		if (!buf) {
1451 			php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
1452 			RETURN_FALSE;
1453 		}
1454 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1455 			saveempty = xmlSaveNoEmptyTags;
1456 			xmlSaveNoEmptyTags = 1;
1457 		}
1458 		xmlNodeDump(buf, docp, node, 0, format);
1459 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1460 			xmlSaveNoEmptyTags = saveempty;
1461 		}
1462 		mem = (xmlChar*) xmlBufferContent(buf);
1463 		if (!mem) {
1464 			xmlBufferFree(buf);
1465 			RETURN_FALSE;
1466 		}
1467 		RETVAL_STRING((char *) mem);
1468 		xmlBufferFree(buf);
1469 	} else {
1470 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1471 			saveempty = xmlSaveNoEmptyTags;
1472 			xmlSaveNoEmptyTags = 1;
1473 		}
1474 		/* Encoding is handled from the encoding property set on the document */
1475 		xmlDocDumpFormatMemory(docp, &mem, &size, format);
1476 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1477 			xmlSaveNoEmptyTags = saveempty;
1478 		}
1479 		if (!size || !mem) {
1480 			RETURN_FALSE;
1481 		}
1482 		RETVAL_STRINGL((char *) mem, size);
1483 		xmlFree(mem);
1484 	}
1485 }
1486 /* }}} end dom_document_savexml */
1487 
php_dom_free_xinclude_node(xmlNodePtr cur)1488 static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur) /* {{{ */
1489 {
1490 	xmlNodePtr xincnode;
1491 
1492 	xincnode = cur;
1493 	cur = cur->next;
1494 	xmlUnlinkNode(xincnode);
1495 	php_libxml_node_free_resource(xincnode);
1496 
1497 	return cur;
1498 }
1499 /* }}} */
1500 
php_dom_remove_xinclude_nodes(xmlNodePtr cur)1501 static void php_dom_remove_xinclude_nodes(xmlNodePtr cur) /* {{{ */
1502 {
1503 	while(cur) {
1504 		if (cur->type == XML_XINCLUDE_START) {
1505 			cur = php_dom_free_xinclude_node(cur);
1506 
1507 			/* XML_XINCLUDE_END node will be a sibling of XML_XINCLUDE_START */
1508 			while(cur && cur->type != XML_XINCLUDE_END) {
1509 				/* remove xinclude processing nodes from recursive xincludes */
1510 				if (cur->type == XML_ELEMENT_NODE) {
1511 					   php_dom_remove_xinclude_nodes(cur->children);
1512 				}
1513 				cur = cur->next;
1514 			}
1515 
1516 			if (cur && cur->type == XML_XINCLUDE_END) {
1517 				cur = php_dom_free_xinclude_node(cur);
1518 			}
1519 		} else {
1520 			if (cur->type == XML_ELEMENT_NODE) {
1521 				php_dom_remove_xinclude_nodes(cur->children);
1522 			}
1523 			cur = cur->next;
1524 		}
1525 	}
1526 }
1527 /* }}} */
1528 
1529 /* {{{ Substitutues xincludes in a DomDocument */
PHP_METHOD(DOMDocument,xinclude)1530 PHP_METHOD(DOMDocument, xinclude)
1531 {
1532 	zval *id;
1533 	xmlDoc *docp;
1534 	xmlNodePtr root;
1535 	zend_long flags = 0;
1536 	int err;
1537 	dom_object *intern;
1538 
1539 	id = ZEND_THIS;
1540 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags) == FAILURE) {
1541 		RETURN_THROWS();
1542 	}
1543 
1544 	if (ZEND_LONG_EXCEEDS_INT(flags)) {
1545 		php_error_docref(NULL, E_WARNING, "Invalid flags");
1546 		RETURN_FALSE;
1547 	}
1548 
1549 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1550 
1551 	err = xmlXIncludeProcessFlags(docp, (int)flags);
1552 
1553 	/* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1554 	are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1555 	but are not wanted in resulting document - must be done even if err as it could fail after
1556 	having processed some xincludes */
1557 	root = (xmlNodePtr) docp->children;
1558 	while(root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1559 		root = root->next;
1560 	}
1561 	if (root) {
1562 		php_dom_remove_xinclude_nodes(root);
1563 	}
1564 
1565 	if (err) {
1566 		RETVAL_LONG(err);
1567 	} else {
1568 		RETVAL_FALSE;
1569 	}
1570 
1571 }
1572 /* }}} */
1573 
1574 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,validate)1575 PHP_METHOD(DOMDocument, validate)
1576 {
1577 	zval *id;
1578 	xmlDoc *docp;
1579 	dom_object *intern;
1580 	xmlValidCtxt *cvp;
1581 
1582 	id = ZEND_THIS;
1583 	if (zend_parse_parameters_none() == FAILURE) {
1584 		RETURN_THROWS();
1585 	}
1586 
1587 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1588 
1589 	cvp = xmlNewValidCtxt();
1590 
1591 	cvp->userData = NULL;
1592 	cvp->error    = (xmlValidityErrorFunc) php_libxml_error_handler;
1593 	cvp->warning  = (xmlValidityErrorFunc) php_libxml_error_handler;
1594 
1595 	if (xmlValidateDocument(cvp, docp)) {
1596 		RETVAL_TRUE;
1597 	} else {
1598 		RETVAL_FALSE;
1599 	}
1600 
1601 	xmlFreeValidCtxt(cvp);
1602 
1603 }
1604 /* }}} */
1605 
1606 #ifdef LIBXML_SCHEMAS_ENABLED
_dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS,int type)1607 static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1608 {
1609 	zval *id;
1610 	xmlDoc *docp;
1611 	dom_object *intern;
1612 	char *source = NULL, *valid_file = NULL;
1613 	size_t source_len = 0;
1614 	int valid_opts = 0;
1615 	zend_long flags = 0;
1616 	xmlSchemaParserCtxtPtr  parser;
1617 	xmlSchemaPtr            sptr;
1618 	xmlSchemaValidCtxtPtr   vptr;
1619 	int                     is_valid;
1620 	char resolved_path[MAXPATHLEN + 1];
1621 
1622 	id = ZEND_THIS;
1623 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &flags) == FAILURE) {
1624 		RETURN_THROWS();
1625 	}
1626 
1627 	if (!source_len) {
1628 		zend_argument_value_error(1, "must not be empty");
1629 		RETURN_THROWS();
1630 	}
1631 
1632 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1633 
1634 	switch (type) {
1635 	case DOM_LOAD_FILE:
1636 		if (CHECK_NULL_PATH(source, source_len)) {
1637 			zend_argument_value_error(1, "must not contain any null bytes");
1638 			RETURN_THROWS();
1639 		}
1640 		valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1641 		if (!valid_file) {
1642 			php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
1643 			RETURN_FALSE;
1644 		}
1645 		parser = xmlSchemaNewParserCtxt(valid_file);
1646 		break;
1647 	case DOM_LOAD_STRING:
1648 		parser = xmlSchemaNewMemParserCtxt(source, source_len);
1649 		/* If loading from memory, we need to set the base directory for the document
1650 		   but it is not apparent how to do that for schema's */
1651 		break;
1652 	default:
1653 		return;
1654 	}
1655 
1656 	xmlSchemaSetParserErrors(parser,
1657 		(xmlSchemaValidityErrorFunc) php_libxml_error_handler,
1658 		(xmlSchemaValidityWarningFunc) php_libxml_error_handler,
1659 		parser);
1660 	sptr = xmlSchemaParse(parser);
1661 	xmlSchemaFreeParserCtxt(parser);
1662 	if (!sptr) {
1663 		if (!EG(exception)) {
1664 			php_error_docref(NULL, E_WARNING, "Invalid Schema");
1665 		}
1666 		RETURN_FALSE;
1667 	}
1668 
1669 	docp = (xmlDocPtr) dom_object_get_node(intern);
1670 
1671 	vptr = xmlSchemaNewValidCtxt(sptr);
1672 	if (!vptr) {
1673 		xmlSchemaFree(sptr);
1674 		zend_throw_error(NULL, "Invalid Schema Validation Context");
1675 		RETURN_THROWS();
1676 	}
1677 
1678 	if (flags & XML_SCHEMA_VAL_VC_I_CREATE) {
1679 		valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE;
1680 	}
1681 
1682 	xmlSchemaSetValidOptions(vptr, valid_opts);
1683 	xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1684 	is_valid = xmlSchemaValidateDoc(vptr, docp);
1685 	xmlSchemaFree(sptr);
1686 	xmlSchemaFreeValidCtxt(vptr);
1687 
1688 	if (is_valid == 0) {
1689 		RETURN_TRUE;
1690 	} else {
1691 		RETURN_FALSE;
1692 	}
1693 }
1694 /* }}} */
1695 
1696 /* {{{ */
PHP_METHOD(DOMDocument,schemaValidate)1697 PHP_METHOD(DOMDocument, schemaValidate)
1698 {
1699 	_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1700 }
1701 /* }}} end dom_document_schema_validate_file */
1702 
1703 /* {{{ */
PHP_METHOD(DOMDocument,schemaValidateSource)1704 PHP_METHOD(DOMDocument, schemaValidateSource)
1705 {
1706 	_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1707 }
1708 /* }}} end dom_document_schema_validate */
1709 
_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS,int type)1710 static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1711 {
1712 	zval *id;
1713 	xmlDoc *docp;
1714 	dom_object *intern;
1715 	char *source = NULL, *valid_file = NULL;
1716 	size_t source_len = 0;
1717 	xmlRelaxNGParserCtxtPtr parser;
1718 	xmlRelaxNGPtr           sptr;
1719 	xmlRelaxNGValidCtxtPtr  vptr;
1720 	int                     is_valid;
1721 	char resolved_path[MAXPATHLEN + 1];
1722 
1723 	id = ZEND_THIS;
1724 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &source, &source_len) == FAILURE) {
1725 		RETURN_THROWS();
1726 	}
1727 
1728 	if (!source_len) {
1729 		zend_argument_value_error(1, "must not be empty");
1730 		RETURN_THROWS();
1731 	}
1732 
1733 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1734 
1735 	switch (type) {
1736 	case DOM_LOAD_FILE:
1737 		if (CHECK_NULL_PATH(source, source_len)) {
1738 			zend_argument_value_error(1, "must not contain any null bytes");
1739 			RETURN_THROWS();
1740 		}
1741 		valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1742 		if (!valid_file) {
1743 			php_error_docref(NULL, E_WARNING, "Invalid RelaxNG file source");
1744 			RETURN_FALSE;
1745 		}
1746 		parser = xmlRelaxNGNewParserCtxt(valid_file);
1747 		break;
1748 	case DOM_LOAD_STRING:
1749 		parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
1750 		/* If loading from memory, we need to set the base directory for the document
1751 		   but it is not apparent how to do that for schema's */
1752 		break;
1753 	default:
1754 		return;
1755 	}
1756 
1757 	xmlRelaxNGSetParserErrors(parser,
1758 		(xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
1759 		(xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
1760 		parser);
1761 	sptr = xmlRelaxNGParse(parser);
1762 	xmlRelaxNGFreeParserCtxt(parser);
1763 	if (!sptr) {
1764 		php_error_docref(NULL, E_WARNING, "Invalid RelaxNG");
1765 		RETURN_FALSE;
1766 	}
1767 
1768 	docp = (xmlDocPtr) dom_object_get_node(intern);
1769 
1770 	vptr = xmlRelaxNGNewValidCtxt(sptr);
1771 	if (!vptr) {
1772 		xmlRelaxNGFree(sptr);
1773 		zend_throw_error(NULL, "Invalid RelaxNG Validation Context");
1774 		RETURN_THROWS();
1775 	}
1776 
1777 	xmlRelaxNGSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1778 	is_valid = xmlRelaxNGValidateDoc(vptr, docp);
1779 	xmlRelaxNGFree(sptr);
1780 	xmlRelaxNGFreeValidCtxt(vptr);
1781 
1782 	if (is_valid == 0) {
1783 		RETURN_TRUE;
1784 	} else {
1785 		RETURN_FALSE;
1786 	}
1787 }
1788 /* }}} */
1789 
1790 /* {{{ */
PHP_METHOD(DOMDocument,relaxNGValidate)1791 PHP_METHOD(DOMDocument, relaxNGValidate)
1792 {
1793 	_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1794 }
1795 /* }}} end dom_document_relaxNG_validate_file */
1796 
1797 /* {{{ */
PHP_METHOD(DOMDocument,relaxNGValidateSource)1798 PHP_METHOD(DOMDocument, relaxNGValidateSource)
1799 {
1800 	_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1801 }
1802 /* }}} end dom_document_relaxNG_validate_xml */
1803 
1804 #endif
1805 
1806 #ifdef LIBXML_HTML_ENABLED
1807 
dom_load_html(INTERNAL_FUNCTION_PARAMETERS,int mode)1808 static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
1809 {
1810 	zval *id;
1811 	xmlDoc *docp = NULL, *newdoc;
1812 	dom_object *intern;
1813 	dom_doc_propsptr doc_prop;
1814 	char *source;
1815 	size_t source_len;
1816 	int refcount, ret;
1817 	zend_long options = 0;
1818 	htmlParserCtxtPtr ctxt;
1819 
1820 	id = getThis();
1821 
1822 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
1823 		RETURN_THROWS();
1824 	}
1825 
1826 	if (!source_len) {
1827 		zend_argument_value_error(1, "must not be empty");
1828 		RETURN_THROWS();
1829 	}
1830 
1831 	if (ZEND_LONG_EXCEEDS_INT(options)) {
1832 		php_error_docref(NULL, E_WARNING, "Invalid options");
1833 		RETURN_FALSE;
1834 	}
1835 
1836 	if (mode == DOM_LOAD_FILE) {
1837 		if (CHECK_NULL_PATH(source, source_len)) {
1838 			zend_argument_value_error(1, "must not contain any null bytes");
1839 			RETURN_THROWS();
1840 		}
1841 		ctxt = htmlCreateFileParserCtxt(source, NULL);
1842 	} else {
1843 		if (ZEND_SIZE_T_INT_OVFL(source_len)) {
1844 			php_error_docref(NULL, E_WARNING, "Input string is too long");
1845 			RETURN_FALSE;
1846 		}
1847 		ctxt = htmlCreateMemoryParserCtxt(source, (int)source_len);
1848 	}
1849 
1850 	if (!ctxt) {
1851 		RETURN_FALSE;
1852 	}
1853 
1854 
1855 	ctxt->vctxt.error = php_libxml_ctx_error;
1856 	ctxt->vctxt.warning = php_libxml_ctx_warning;
1857 	if (ctxt->sax != NULL) {
1858 		ctxt->sax->error = php_libxml_ctx_error;
1859 		ctxt->sax->warning = php_libxml_ctx_warning;
1860 	}
1861 	if (options) {
1862 		htmlCtxtUseOptions(ctxt, (int)options);
1863 	}
1864 	htmlParseDocument(ctxt);
1865 	newdoc = ctxt->myDoc;
1866 	htmlFreeParserCtxt(ctxt);
1867 
1868 	if (!newdoc)
1869 		RETURN_FALSE;
1870 
1871 	if (id != NULL && instanceof_function(Z_OBJCE_P(id), dom_document_class_entry)) {
1872 		intern = Z_DOMOBJ_P(id);
1873 		if (intern != NULL) {
1874 			docp = (xmlDocPtr) dom_object_get_node(intern);
1875 			doc_prop = NULL;
1876 			if (docp != NULL) {
1877 				php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1878 				doc_prop = intern->document->doc_props;
1879 				intern->document->doc_props = NULL;
1880 				refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1881 				if (refcount != 0) {
1882 					docp->_private = NULL;
1883 				}
1884 			}
1885 			intern->document = NULL;
1886 			if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
1887 				RETURN_FALSE;
1888 			}
1889 			intern->document->doc_props = doc_prop;
1890 		}
1891 
1892 		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
1893 
1894 		RETURN_TRUE;
1895 	} else {
1896 		DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1897 	}
1898 }
1899 /* }}} */
1900 
1901 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,loadHTMLFile)1902 PHP_METHOD(DOMDocument, loadHTMLFile)
1903 {
1904 	dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1905 }
1906 /* }}} end dom_document_load_html_file */
1907 
1908 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,loadHTML)1909 PHP_METHOD(DOMDocument, loadHTML)
1910 {
1911 	dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1912 }
1913 /* }}} end dom_document_load_html */
1914 
1915 /* {{{ Convenience method to save to file as html */
PHP_METHOD(DOMDocument,saveHTMLFile)1916 PHP_METHOD(DOMDocument, saveHTMLFile)
1917 {
1918 	zval *id;
1919 	xmlDoc *docp;
1920 	size_t file_len;
1921 	int bytes, format;
1922 	dom_object *intern;
1923 	dom_doc_propsptr doc_props;
1924 	char *file;
1925 	const char *encoding;
1926 
1927 	id = ZEND_THIS;
1928 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &file, &file_len) == FAILURE) {
1929 		RETURN_THROWS();
1930 	}
1931 
1932 	if (file_len == 0) {
1933 		zend_argument_value_error(1, "must not be empty");
1934 		RETURN_THROWS();
1935 	}
1936 
1937 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1938 
1939 
1940 	encoding = (const char *) htmlGetMetaEncoding(docp);
1941 
1942 	doc_props = dom_get_doc_props(intern->document);
1943 	format = doc_props->formatoutput;
1944 	bytes = htmlSaveFileFormat(file, docp, encoding, format);
1945 
1946 	if (bytes == -1) {
1947 		RETURN_FALSE;
1948 	}
1949 	RETURN_LONG(bytes);
1950 }
1951 /* }}} end dom_document_save_html_file */
1952 
1953 /* {{{ Convenience method to output as html */
PHP_METHOD(DOMDocument,saveHTML)1954 PHP_METHOD(DOMDocument, saveHTML)
1955 {
1956 	zval *id, *nodep = NULL;
1957 	xmlDoc *docp;
1958 	xmlNode *node;
1959 	xmlOutputBufferPtr outBuf;
1960 	xmlBufferPtr buf;
1961 	dom_object *intern, *nodeobj;
1962 	xmlChar *mem = NULL;
1963 	int format;
1964 	dom_doc_propsptr doc_props;
1965 
1966 	id = ZEND_THIS;
1967 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
1968 		"|O!", &nodep, dom_node_class_entry)
1969 		== FAILURE) {
1970 		RETURN_THROWS();
1971 	}
1972 
1973 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1974 
1975 	doc_props = dom_get_doc_props(intern->document);
1976 	format = doc_props->formatoutput;
1977 
1978 	if (nodep != NULL) {
1979 		/* Dump contents of Node */
1980 		DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1981 		if (node->doc != docp) {
1982 			php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
1983 			RETURN_FALSE;
1984 		}
1985 
1986 		buf = xmlBufferCreate();
1987 		if (!buf) {
1988 			php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
1989 			RETURN_FALSE;
1990 		}
1991 		outBuf = xmlOutputBufferCreateBuffer(buf, NULL);
1992 		if (!outBuf) {
1993 			xmlBufferFree(buf);
1994 			php_error_docref(NULL, E_WARNING, "Could not fetch output buffer");
1995 			RETURN_FALSE;
1996 		}
1997 
1998 		if (node->type == XML_DOCUMENT_FRAG_NODE) {
1999 			for (node = node->children; node; node = node->next) {
2000 				htmlNodeDumpFormatOutput(outBuf, docp, node, NULL, format);
2001 				if (outBuf->error) {
2002 					break;
2003 				}
2004 			}
2005 		} else {
2006 			htmlNodeDumpFormatOutput(outBuf, docp, node, NULL, format);
2007 		}
2008 		if (!outBuf->error) {
2009 			xmlOutputBufferFlush(outBuf);
2010 			mem = (xmlChar*) xmlBufferContent(buf);
2011 			if (!mem) {
2012 				RETVAL_FALSE;
2013 			} else {
2014 				int size = xmlBufferLength(buf);
2015 				RETVAL_STRINGL((const char*) mem, size);
2016 			}
2017 		} else {
2018 			php_error_docref(NULL, E_WARNING, "Error dumping HTML node");
2019 			RETVAL_FALSE;
2020 		}
2021 		xmlOutputBufferClose(outBuf);
2022 		xmlBufferFree(buf);
2023 	} else {
2024 		int size = 0;
2025 		htmlDocDumpMemoryFormat(docp, &mem, &size, format);
2026 		if (!size || !mem) {
2027 			RETVAL_FALSE;
2028 		} else {
2029 			RETVAL_STRINGL((const char*) mem, size);
2030 		}
2031 		if (mem)
2032 			xmlFree(mem);
2033 	}
2034 
2035 }
2036 /* }}} end dom_document_save_html */
2037 
2038 #endif  /* defined(LIBXML_HTML_ENABLED) */
2039 
2040 /* {{{ Register extended class used to create base node type */
PHP_METHOD(DOMDocument,registerNodeClass)2041 PHP_METHOD(DOMDocument, registerNodeClass)
2042 {
2043 	zval *id;
2044 	xmlDoc *docp;
2045 	zend_class_entry *basece = dom_node_class_entry, *ce = NULL;
2046 	dom_object *intern;
2047 
2048 	id = ZEND_THIS;
2049 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "CC!", &basece, &ce) == FAILURE) {
2050 		RETURN_THROWS();
2051 	}
2052 
2053 	if (ce == NULL || instanceof_function(ce, basece)) {
2054 		DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2055 		dom_set_doc_classmap(intern->document, basece, ce);
2056 		RETURN_TRUE;
2057 	}
2058 
2059 	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));
2060 }
2061 /* }}} */
2062 
2063 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-append
2064 Since: DOM Living Standard (DOM4)
2065 */
PHP_METHOD(DOMDocument,append)2066 PHP_METHOD(DOMDocument, append)
2067 {
2068 	int argc;
2069 	zval *args, *id;
2070 	dom_object *intern;
2071 	xmlNode *context;
2072 
2073 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
2074 		RETURN_THROWS();
2075 	}
2076 
2077 	id = ZEND_THIS;
2078 	DOM_GET_OBJ(context, id, xmlNodePtr, intern);
2079 
2080 	dom_parent_node_append(intern, args, argc);
2081 }
2082 /* }}} */
2083 
2084 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
2085 Since: DOM Living Standard (DOM4)
2086 */
PHP_METHOD(DOMDocument,prepend)2087 PHP_METHOD(DOMDocument, prepend)
2088 {
2089 	int argc;
2090 	zval *args, *id;
2091 	dom_object *intern;
2092 	xmlNode *context;
2093 
2094 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
2095 		RETURN_THROWS();
2096 	}
2097 
2098 	id = ZEND_THIS;
2099 	DOM_GET_OBJ(context, id, xmlNodePtr, intern);
2100 
2101 	dom_parent_node_prepend(intern, args, argc);
2102 }
2103 /* }}} */
2104 
2105 #endif  /* HAVE_LIBXML && HAVE_DOM */
2106