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