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 #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, 1);
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, 1);
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, 1);
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, 1);
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, 1);
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, 1);
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, 1);
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, 1);
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, 1);
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, 1);
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 		php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
537 		RETURN_THROWS();
538 	}
539 
540 	DOM_RET_OBJ(node, &ret, intern);
541 }
542 /* }}} end dom_document_create_element */
543 
544 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-35CB04B5
545 Since:
546 */
PHP_METHOD(DOMDocument,createDocumentFragment)547 PHP_METHOD(DOMDocument, createDocumentFragment)
548 {
549 	zval *id;
550 	xmlNode *node;
551 	xmlDocPtr docp;
552 	dom_object *intern;
553 	int ret;
554 
555 	id = ZEND_THIS;
556 	if (zend_parse_parameters_none() == FAILURE) {
557 		RETURN_THROWS();
558 	}
559 
560 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
561 
562 	node = xmlNewDocFragment(docp);
563 	if (!node) {
564 		php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
565 		RETURN_THROWS();
566 	}
567 
568 	DOM_RET_OBJ(node, &ret, intern);
569 }
570 /* }}} end dom_document_create_document_fragment */
571 
572 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1975348127
573 Since:
574 */
PHP_METHOD(DOMDocument,createTextNode)575 PHP_METHOD(DOMDocument, createTextNode)
576 {
577 	zval *id;
578 	xmlNode *node;
579 	xmlDocPtr docp;
580 	int ret;
581 	size_t value_len;
582 	dom_object *intern;
583 	char *value;
584 
585 	id = ZEND_THIS;
586 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len) == FAILURE) {
587 		RETURN_THROWS();
588 	}
589 
590 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
591 
592 	node = xmlNewDocText(docp, (xmlChar *) value);
593 	if (!node) {
594 		php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
595 		RETURN_THROWS();
596 	}
597 
598 	DOM_RET_OBJ(node, &ret, intern);
599 }
600 /* }}} end dom_document_create_text_node */
601 
602 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1334481328
603 Since:
604 */
PHP_METHOD(DOMDocument,createComment)605 PHP_METHOD(DOMDocument, createComment)
606 {
607 	zval *id;
608 	xmlNode *node;
609 	xmlDocPtr docp;
610 	int ret;
611 	size_t value_len;
612 	dom_object *intern;
613 	char *value;
614 
615 	id = ZEND_THIS;
616 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len) == FAILURE) {
617 		RETURN_THROWS();
618 	}
619 
620 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
621 
622 	node = xmlNewDocComment(docp, (xmlChar *) value);
623 	if (!node) {
624 		php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
625 		RETURN_THROWS();
626 	}
627 
628 	DOM_RET_OBJ(node, &ret, intern);
629 }
630 /* }}} end dom_document_create_comment */
631 
632 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-D26C0AF8
633 Since:
634 */
PHP_METHOD(DOMDocument,createCDATASection)635 PHP_METHOD(DOMDocument, createCDATASection)
636 {
637 	zval *id;
638 	xmlNode *node;
639 	xmlDocPtr docp;
640 	int ret;
641 	size_t value_len;
642 	dom_object *intern;
643 	char *value;
644 
645 	id = ZEND_THIS;
646 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len) == FAILURE) {
647 		RETURN_THROWS();
648 	}
649 
650 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
651 
652 	node = xmlNewCDataBlock(docp, (xmlChar *) value, value_len);
653 	if (!node) {
654 		php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
655 		RETURN_THROWS();
656 	}
657 
658 	DOM_RET_OBJ(node, &ret, intern);
659 }
660 /* }}} end dom_document_create_cdatasection */
661 
662 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-135944439
663 Since:
664 */
PHP_METHOD(DOMDocument,createProcessingInstruction)665 PHP_METHOD(DOMDocument, createProcessingInstruction)
666 {
667 	zval *id;
668 	xmlNode *node;
669 	xmlDocPtr docp;
670 	int ret;
671 	size_t value_len, name_len = 0;
672 	dom_object *intern;
673 	char *name, *value = NULL;
674 
675 	id = ZEND_THIS;
676 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &name, &name_len, &value, &value_len) == FAILURE) {
677 		RETURN_THROWS();
678 	}
679 
680 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
681 
682 	if (xmlValidateName((xmlChar *) name, 0) != 0) {
683 		php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
684 		RETURN_FALSE;
685 	}
686 
687 	node = xmlNewPI((xmlChar *) name, (xmlChar *) value);
688 	if (!node) {
689 		php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
690 		RETURN_THROWS();
691 	}
692 
693 	node->doc = docp;
694 
695 	DOM_RET_OBJ(node, &ret, intern);
696 }
697 /* }}} end dom_document_create_processing_instruction */
698 
699 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1084891198
700 Since:
701 */
PHP_METHOD(DOMDocument,createAttribute)702 PHP_METHOD(DOMDocument, createAttribute)
703 {
704 	zval *id;
705 	xmlAttrPtr node;
706 	xmlDocPtr docp;
707 	int ret;
708 	size_t name_len;
709 	dom_object *intern;
710 	char *name;
711 
712 	id = ZEND_THIS;
713 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
714 		RETURN_THROWS();
715 	}
716 
717 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
718 
719 	if (xmlValidateName((xmlChar *) name, 0) != 0) {
720 		php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
721 		RETURN_FALSE;
722 	}
723 
724 	node = xmlNewDocProp(docp, (xmlChar *) name, NULL);
725 	if (!node) {
726 		php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
727 		RETURN_THROWS();
728 	}
729 
730 	DOM_RET_OBJ((xmlNodePtr) node, &ret, intern);
731 
732 }
733 /* }}} end dom_document_create_attribute */
734 
735 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-392B75AE
736 Since:
737 */
PHP_METHOD(DOMDocument,createEntityReference)738 PHP_METHOD(DOMDocument, createEntityReference)
739 {
740 	zval *id;
741 	xmlNode *node;
742 	xmlDocPtr docp = NULL;
743 	dom_object *intern;
744 	int ret;
745 	size_t name_len;
746 	char *name;
747 
748 	id = ZEND_THIS;
749 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
750 		RETURN_THROWS();
751 	}
752 
753 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
754 
755 	if (xmlValidateName((xmlChar *) name, 0) != 0) {
756 		php_dom_throw_error(INVALID_CHARACTER_ERR, dom_get_strict_error(intern->document));
757 		RETURN_FALSE;
758 	}
759 
760 	node = xmlNewReference(docp, (xmlChar *) name);
761 	if (!node) {
762 		php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
763 		RETURN_THROWS();
764 	}
765 
766 	DOM_RET_OBJ((xmlNodePtr) node, &ret, intern);
767 }
768 /* }}} end dom_document_create_entity_reference */
769 
770 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-A6C9094
771 Since:
772 */
PHP_METHOD(DOMDocument,getElementsByTagName)773 PHP_METHOD(DOMDocument, getElementsByTagName)
774 {
775 	zval *id;
776 	xmlDocPtr docp;
777 	size_t name_len;
778 	dom_object *intern, *namednode;
779 	char *name;
780 	xmlChar *local;
781 
782 	id = ZEND_THIS;
783 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
784 		RETURN_THROWS();
785 	}
786 
787 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
788 
789 	php_dom_create_iterator(return_value, DOM_NODELIST);
790 	namednode = Z_DOMOBJ_P(return_value);
791 	local = xmlCharStrndup(name, name_len);
792 	dom_namednode_iter(intern, 0, namednode, NULL, local, NULL);
793 }
794 /* }}} end dom_document_get_elements_by_tag_name */
795 
796 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Core-Document-importNode
797 Since: DOM Level 2
798 */
PHP_METHOD(DOMDocument,importNode)799 PHP_METHOD(DOMDocument, importNode)
800 {
801 	zval *id, *node;
802 	xmlDocPtr docp;
803 	xmlNodePtr nodep, retnodep;
804 	dom_object *intern, *nodeobj;
805 	int ret;
806 	bool recursive = 0;
807 	/* See http://www.xmlsoft.org/html/libxml-tree.html#xmlDocCopyNode for meaning of values */
808 	int extended_recursive;
809 
810 	id = ZEND_THIS;
811 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &node, dom_node_class_entry, &recursive) == FAILURE) {
812 		RETURN_THROWS();
813 	}
814 
815 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
816 
817 	DOM_GET_OBJ(nodep, node, xmlNodePtr, nodeobj);
818 
819 	if (nodep->type == XML_HTML_DOCUMENT_NODE || nodep->type == XML_DOCUMENT_NODE
820 		|| nodep->type == XML_DOCUMENT_TYPE_NODE) {
821 		php_error_docref(NULL, E_WARNING, "Cannot import: Node Type Not Supported");
822 		RETURN_FALSE;
823 	}
824 
825 	if (nodep->doc == docp) {
826 		retnodep = nodep;
827 	} else {
828 		extended_recursive = recursive;
829 		if ((recursive == 0) && (nodep->type == XML_ELEMENT_NODE)) {
830 			extended_recursive = 2;
831 		}
832 		retnodep = xmlDocCopyNode(nodep, docp, extended_recursive);
833 		if (!retnodep) {
834 			RETURN_FALSE;
835 		}
836 
837 		if ((retnodep->type == XML_ATTRIBUTE_NODE) && (nodep->ns != NULL)) {
838 			xmlNsPtr nsptr = NULL;
839 			xmlNodePtr root = xmlDocGetRootElement(docp);
840 
841 			nsptr = xmlSearchNsByHref (nodep->doc, root, nodep->ns->href);
842 			if (nsptr == NULL) {
843 				int errorcode;
844 				nsptr = dom_get_ns(root, (char *) nodep->ns->href, &errorcode, (char *) nodep->ns->prefix);
845 			}
846 			xmlSetNs(retnodep, nsptr);
847 		}
848 	}
849 
850 	DOM_RET_OBJ((xmlNodePtr) retnodep, &ret, intern);
851 }
852 /* }}} end dom_document_import_node */
853 
854 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrElNS
855 Since: DOM Level 2
856 */
PHP_METHOD(DOMDocument,createElementNS)857 PHP_METHOD(DOMDocument, createElementNS)
858 {
859 	zval *id;
860 	xmlDocPtr docp;
861 	xmlNodePtr nodep = NULL;
862 	xmlNsPtr nsptr = NULL;
863 	int ret;
864 	size_t uri_len = 0, name_len = 0, value_len = 0;
865 	char *uri, *name, *value = NULL;
866 	char *localname = NULL, *prefix = NULL;
867 	int errorcode;
868 	dom_object *intern;
869 
870 	id = ZEND_THIS;
871 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s|s", &uri, &uri_len, &name, &name_len, &value, &value_len) == FAILURE) {
872 		RETURN_THROWS();
873 	}
874 
875 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
876 
877 	errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
878 
879 	if (errorcode == 0) {
880 		if (xmlValidateName((xmlChar *) localname, 0) == 0) {
881 			nodep = xmlNewDocNode(docp, NULL, (xmlChar *) localname, (xmlChar *) value);
882 			if (nodep != NULL && uri != NULL) {
883 				nsptr = xmlSearchNsByHref(nodep->doc, nodep, (xmlChar *) uri);
884 				if (nsptr == NULL) {
885 					nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);
886 				}
887 				xmlSetNs(nodep, nsptr);
888 			}
889 		} else {
890 			errorcode = INVALID_CHARACTER_ERR;
891 		}
892 	}
893 
894 	xmlFree(localname);
895 	if (prefix != NULL) {
896 		xmlFree(prefix);
897 	}
898 
899 	if (errorcode != 0) {
900 		if (nodep != NULL) {
901 			xmlFreeNode(nodep);
902 		}
903 		php_dom_throw_error(errorcode, dom_get_strict_error(intern->document));
904 		RETURN_FALSE;
905 	}
906 
907 	if (nodep == NULL) {
908 		RETURN_FALSE;
909 	}
910 
911 
912 	nodep->ns = nsptr;
913 
914 	DOM_RET_OBJ(nodep, &ret, intern);
915 }
916 /* }}} end dom_document_create_element_ns */
917 
918 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-DocCrAttrNS
919 Since: DOM Level 2
920 */
PHP_METHOD(DOMDocument,createAttributeNS)921 PHP_METHOD(DOMDocument, createAttributeNS)
922 {
923 	zval *id;
924 	xmlDocPtr docp;
925 	xmlNodePtr nodep = NULL, root;
926 	xmlNsPtr nsptr;
927 	int ret;
928 	size_t uri_len = 0, name_len = 0;
929 	char *uri, *name;
930 	char *localname = NULL, *prefix = NULL;
931 	dom_object *intern;
932 	int errorcode;
933 
934 	id = ZEND_THIS;
935 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
936 		RETURN_THROWS();
937 	}
938 
939 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
940 
941 	root = xmlDocGetRootElement(docp);
942 	if (root != NULL) {
943 		errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
944 		if (errorcode == 0) {
945 			if (xmlValidateName((xmlChar *) localname, 0) == 0) {
946 				nodep = (xmlNodePtr) xmlNewDocProp(docp, (xmlChar *) localname, NULL);
947 				if (nodep != NULL && uri_len > 0) {
948 					nsptr = xmlSearchNsByHref(nodep->doc, root, (xmlChar *) uri);
949 					if (nsptr == NULL) {
950 						nsptr = dom_get_ns(root, uri, &errorcode, prefix);
951 					}
952 					xmlSetNs(nodep, nsptr);
953 				}
954 			} else {
955 				errorcode = INVALID_CHARACTER_ERR;
956 			}
957 		}
958 	} else {
959 		php_error_docref(NULL, E_WARNING, "Document Missing Root Element");
960 		RETURN_FALSE;
961 	}
962 
963 	xmlFree(localname);
964 	if (prefix != NULL) {
965 		xmlFree(prefix);
966 	}
967 
968 	if (errorcode != 0) {
969 		if (nodep != NULL) {
970 			xmlFreeProp((xmlAttrPtr) nodep);
971 		}
972 		php_dom_throw_error(errorcode, dom_get_strict_error(intern->document));
973 		RETURN_FALSE;
974 	}
975 
976 	if (nodep == NULL) {
977 		RETURN_FALSE;
978 	}
979 
980 	DOM_RET_OBJ(nodep, &ret, intern);
981 }
982 /* }}} end dom_document_create_attribute_ns */
983 
984 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBTNNS
985 Since: DOM Level 2
986 */
PHP_METHOD(DOMDocument,getElementsByTagNameNS)987 PHP_METHOD(DOMDocument, getElementsByTagNameNS)
988 {
989 	zval *id;
990 	xmlDocPtr docp;
991 	size_t uri_len, name_len;
992 	dom_object *intern, *namednode;
993 	char *uri, *name;
994 	xmlChar *local, *nsuri;
995 
996 	id = ZEND_THIS;
997 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
998 		RETURN_THROWS();
999 	}
1000 
1001 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1002 
1003 	php_dom_create_iterator(return_value, DOM_NODELIST);
1004 	namednode = Z_DOMOBJ_P(return_value);
1005 	local = xmlCharStrndup(name, name_len);
1006 	nsuri = xmlCharStrndup(uri ? uri : "", uri_len);
1007 	dom_namednode_iter(intern, 0, namednode, NULL, local, nsuri);
1008 }
1009 /* }}} end dom_document_get_elements_by_tag_name_ns */
1010 
1011 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-getElBId
1012 Since: DOM Level 2
1013 */
PHP_METHOD(DOMDocument,getElementById)1014 PHP_METHOD(DOMDocument, getElementById)
1015 {
1016 	zval *id;
1017 	xmlDocPtr docp;
1018 	xmlAttrPtr  attrp;
1019 	int ret;
1020 	size_t idname_len;
1021 	dom_object *intern;
1022 	char *idname;
1023 
1024 	id = ZEND_THIS;
1025 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &idname, &idname_len) == FAILURE) {
1026 		RETURN_THROWS();
1027 	}
1028 
1029 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1030 
1031 	attrp = xmlGetID(docp, (xmlChar *) idname);
1032 
1033 	if (attrp && attrp->parent) {
1034 		DOM_RET_OBJ((xmlNodePtr) attrp->parent, &ret, intern);
1035 	} else {
1036 		RETVAL_NULL();
1037 	}
1038 
1039 }
1040 /* }}} end dom_document_get_element_by_id */
1041 
1042 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-adoptNode
1043 Since: DOM Level 3
1044 */
PHP_METHOD(DOMDocument,adoptNode)1045 PHP_METHOD(DOMDocument, adoptNode)
1046 {
1047 	zval *nodep = NULL;
1048 
1049 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &nodep, dom_node_class_entry) == FAILURE) {
1050 		RETURN_THROWS();
1051 	}
1052 
1053 	DOM_NOT_IMPLEMENTED();
1054 }
1055 /* }}} end dom_document_adopt_node */
1056 
1057 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-normalizeDocument
1058 Since: DOM Level 3
1059 */
PHP_METHOD(DOMDocument,normalizeDocument)1060 PHP_METHOD(DOMDocument, normalizeDocument)
1061 {
1062 	zval *id;
1063 	xmlDocPtr docp;
1064 	dom_object *intern;
1065 
1066 	id = ZEND_THIS;
1067 	if (zend_parse_parameters_none() == FAILURE) {
1068 		RETURN_THROWS();
1069 	}
1070 
1071 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1072 
1073 	dom_normalize((xmlNodePtr) docp);
1074 }
1075 /* }}} end dom_document_normalize_document */
1076 
1077 /* {{{ */
PHP_METHOD(DOMDocument,__construct)1078 PHP_METHOD(DOMDocument, __construct)
1079 {
1080 	xmlDoc *docp = NULL, *olddoc;
1081 	dom_object *intern;
1082 	char *encoding, *version = NULL;
1083 	size_t encoding_len = 0, version_len = 0;
1084 	int refcount;
1085 
1086 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ss", &version, &version_len, &encoding, &encoding_len) == FAILURE) {
1087 		RETURN_THROWS();
1088 	}
1089 
1090 	docp = xmlNewDoc((xmlChar *) version);
1091 
1092 	if (!docp) {
1093 		php_dom_throw_error(INVALID_STATE_ERR, 1);
1094 		return;
1095 	}
1096 
1097 	if (encoding_len > 0) {
1098 		docp->encoding = (const xmlChar *) xmlStrdup((xmlChar *) encoding);
1099 	}
1100 
1101 	intern = Z_DOMOBJ_P(ZEND_THIS);
1102 	if (intern != NULL) {
1103 		olddoc = (xmlDocPtr) dom_object_get_node(intern);
1104 		if (olddoc != NULL) {
1105 			php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1106 			refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1107 			if (refcount != 0) {
1108 				olddoc->_private = NULL;
1109 			}
1110 		}
1111 		intern->document = NULL;
1112 		if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, docp) == -1) {
1113 			/* docp is always non-null so php_libxml_increment_doc_ref() never returns -1 */
1114 			ZEND_UNREACHABLE();
1115 		}
1116 		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)docp, (void *)intern);
1117 	}
1118 }
1119 /* }}} end DOMDocument::__construct */
1120 
_dom_get_valid_file_path(char * source,char * resolved_path,int resolved_path_len)1121 char *_dom_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len ) /* {{{ */
1122 {
1123 	xmlURI *uri;
1124 	xmlChar *escsource;
1125 	char *file_dest;
1126 	int isFileUri = 0;
1127 
1128 	uri = xmlCreateURI();
1129 	escsource = xmlURIEscapeStr((xmlChar *) source, (xmlChar *) ":");
1130 	xmlParseURIReference(uri, (char *) escsource);
1131 	xmlFree(escsource);
1132 
1133 	if (uri->scheme != NULL) {
1134 		/* absolute file uris - libxml only supports localhost or empty host */
1135 #ifdef PHP_WIN32
1136 		if (strncasecmp(source, "file://",7) == 0 && ':' == source[8]) {
1137 			isFileUri = 1;
1138 			source += 7;
1139 		} else
1140 #endif
1141 		if (strncasecmp(source, "file:///",8) == 0) {
1142 			isFileUri = 1;
1143 #ifdef PHP_WIN32
1144 			source += 8;
1145 #else
1146 			source += 7;
1147 #endif
1148 		} else if (strncasecmp(source, "file://localhost/",17) == 0) {
1149 			isFileUri = 1;
1150 #ifdef PHP_WIN32
1151 			source += 17;
1152 #else
1153 			source += 16;
1154 #endif
1155 		}
1156 	}
1157 
1158 	file_dest = source;
1159 
1160 	if ((uri->scheme == NULL || isFileUri)) {
1161 		/* XXX possible buffer overflow if VCWD_REALPATH does not know size of resolved_path */
1162 		if (!VCWD_REALPATH(source, resolved_path) && !expand_filepath(source, resolved_path)) {
1163 			xmlFreeURI(uri);
1164 			return NULL;
1165 		}
1166 		file_dest = resolved_path;
1167 	}
1168 
1169 	xmlFreeURI(uri);
1170 
1171 	return file_dest;
1172 }
1173 /* }}} */
1174 
dom_document_parser(zval * id,int mode,char * source,size_t source_len,size_t options)1175 static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t source_len, size_t options) /* {{{ */
1176 {
1177 	xmlDocPtr ret;
1178 	xmlParserCtxtPtr ctxt = NULL;
1179 	dom_doc_propsptr doc_props;
1180 	dom_object *intern;
1181 	php_libxml_ref_obj *document = NULL;
1182 	int validate, recover, resolve_externals, keep_blanks, substitute_ent;
1183 	int resolved_path_len;
1184 	int old_error_reporting = 0;
1185 	char *directory=NULL, resolved_path[MAXPATHLEN];
1186 
1187 	if (id != NULL) {
1188 		intern = Z_DOMOBJ_P(id);
1189 		document = intern->document;
1190 	}
1191 
1192 	doc_props = dom_get_doc_props(document);
1193 	validate = doc_props->validateonparse;
1194 	resolve_externals = doc_props->resolveexternals;
1195 	keep_blanks = doc_props->preservewhitespace;
1196 	substitute_ent = doc_props->substituteentities;
1197 	recover = doc_props->recover;
1198 
1199 	if (document == NULL) {
1200 		efree(doc_props);
1201 	}
1202 
1203 	xmlInitParser();
1204 
1205 	if (mode == DOM_LOAD_FILE) {
1206 		char *file_dest;
1207 		if (CHECK_NULL_PATH(source, source_len)) {
1208 			zend_value_error("Path to document must not contain any null bytes");
1209 			return NULL;
1210 		}
1211 		file_dest = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1212 		if (file_dest) {
1213 			ctxt = xmlCreateFileParserCtxt(file_dest);
1214 		}
1215 
1216 	} else {
1217 		ctxt = xmlCreateMemoryParserCtxt(source, source_len);
1218 	}
1219 
1220 	if (ctxt == NULL) {
1221 		return(NULL);
1222 	}
1223 
1224 	/* If loading from memory, we need to set the base directory for the document */
1225 	if (mode != DOM_LOAD_FILE) {
1226 #ifdef HAVE_GETCWD
1227 		directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
1228 #elif defined(HAVE_GETWD)
1229 		directory = VCWD_GETWD(resolved_path);
1230 #endif
1231 		if (directory) {
1232 			if(ctxt->directory != NULL) {
1233 				xmlFree((char *) ctxt->directory);
1234 			}
1235 			resolved_path_len = strlen(resolved_path);
1236 			if (resolved_path[resolved_path_len - 1] != DEFAULT_SLASH) {
1237 				resolved_path[resolved_path_len] = DEFAULT_SLASH;
1238 				resolved_path[++resolved_path_len] = '\0';
1239 			}
1240 			ctxt->directory = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
1241 		}
1242 	}
1243 
1244 	ctxt->vctxt.error = php_libxml_ctx_error;
1245 	ctxt->vctxt.warning = php_libxml_ctx_warning;
1246 
1247 	if (ctxt->sax != NULL) {
1248 		ctxt->sax->error = php_libxml_ctx_error;
1249 		ctxt->sax->warning = php_libxml_ctx_warning;
1250 	}
1251 
1252 	if (validate && ! (options & XML_PARSE_DTDVALID)) {
1253 		options |= XML_PARSE_DTDVALID;
1254 	}
1255 	if (resolve_externals && ! (options & XML_PARSE_DTDATTR)) {
1256 		options |= XML_PARSE_DTDATTR;
1257 	}
1258 	if (substitute_ent && ! (options & XML_PARSE_NOENT)) {
1259 		options |= XML_PARSE_NOENT;
1260 	}
1261 	if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) {
1262 		options |= XML_PARSE_NOBLANKS;
1263 	}
1264 
1265 	xmlCtxtUseOptions(ctxt, options);
1266 
1267 	ctxt->recovery = recover;
1268 	if (recover) {
1269 		old_error_reporting = EG(error_reporting);
1270 		EG(error_reporting) = old_error_reporting | E_WARNING;
1271 	}
1272 
1273 	xmlParseDocument(ctxt);
1274 
1275 	if (ctxt->wellFormed || recover) {
1276 		ret = ctxt->myDoc;
1277 		if (ctxt->recovery) {
1278 			EG(error_reporting) = old_error_reporting;
1279 		}
1280 		/* If loading from memory, set the base reference uri for the document */
1281 		if (ret && ret->URL == NULL && ctxt->directory != NULL) {
1282 			ret->URL = xmlStrdup((xmlChar *) ctxt->directory);
1283 		}
1284 	} else {
1285 		ret = NULL;
1286 		xmlFreeDoc(ctxt->myDoc);
1287 		ctxt->myDoc = NULL;
1288 	}
1289 
1290 	xmlFreeParserCtxt(ctxt);
1291 
1292 	return(ret);
1293 }
1294 /* }}} */
1295 
1296 /* {{{ static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) */
dom_parse_document(INTERNAL_FUNCTION_PARAMETERS,int mode)1297 static void dom_parse_document(INTERNAL_FUNCTION_PARAMETERS, int mode) {
1298 	zval *id;
1299 	xmlDoc *docp = NULL, *newdoc;
1300 	dom_doc_propsptr doc_prop;
1301 	dom_object *intern;
1302 	char *source;
1303 	size_t source_len;
1304 	int refcount, ret;
1305 	zend_long options = 0;
1306 
1307 	id = getThis();
1308 	if (id != NULL && ! instanceof_function(Z_OBJCE_P(id), dom_document_class_entry)) {
1309 		id = NULL;
1310 	}
1311 
1312 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
1313 		RETURN_THROWS();
1314 	}
1315 
1316 	if (!source_len) {
1317 		zend_argument_value_error(1, "must not be empty");
1318 		RETURN_THROWS();
1319 	}
1320 	if (ZEND_SIZE_T_INT_OVFL(source_len)) {
1321 		php_error_docref(NULL, E_WARNING, "Input string is too long");
1322 		RETURN_FALSE;
1323 	}
1324 	if (ZEND_LONG_EXCEEDS_INT(options)) {
1325 		php_error_docref(NULL, E_WARNING, "Invalid options");
1326 		RETURN_FALSE;
1327 	}
1328 
1329 	newdoc = dom_document_parser(id, mode, source, source_len, options);
1330 
1331 	if (!newdoc)
1332 		RETURN_FALSE;
1333 
1334 	if (id != NULL) {
1335 		intern = Z_DOMOBJ_P(id);
1336 		if (intern != NULL) {
1337 			docp = (xmlDocPtr) dom_object_get_node(intern);
1338 			doc_prop = NULL;
1339 			if (docp != NULL) {
1340 				php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1341 				doc_prop = intern->document->doc_props;
1342 				intern->document->doc_props = NULL;
1343 				refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1344 				if (refcount != 0) {
1345 					docp->_private = NULL;
1346 				}
1347 			}
1348 			intern->document = NULL;
1349 			if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
1350 				RETURN_FALSE;
1351 			}
1352 			intern->document->doc_props = doc_prop;
1353 		}
1354 
1355 		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
1356 
1357 		RETURN_TRUE;
1358 	} else {
1359 		DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1360 	}
1361 }
1362 /* }}} end dom_parser_document */
1363 
1364 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-load
1365 Since: DOM Level 3
1366 */
PHP_METHOD(DOMDocument,load)1367 PHP_METHOD(DOMDocument, load)
1368 {
1369 	dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1370 }
1371 /* }}} end dom_document_load */
1372 
1373 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-loadXML
1374 Since: DOM Level 3
1375 */
PHP_METHOD(DOMDocument,loadXML)1376 PHP_METHOD(DOMDocument, loadXML)
1377 {
1378 	dom_parse_document(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1379 }
1380 /* }}} end dom_document_loadxml */
1381 
1382 /* {{{ Convenience method to save to file */
PHP_METHOD(DOMDocument,save)1383 PHP_METHOD(DOMDocument, save)
1384 {
1385 	zval *id;
1386 	xmlDoc *docp;
1387 	size_t file_len = 0;
1388 	int bytes, format, saveempty = 0;
1389 	dom_object *intern;
1390 	dom_doc_propsptr doc_props;
1391 	char *file;
1392 	zend_long options = 0;
1393 
1394 	id = ZEND_THIS;
1395 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &file, &file_len, &options) == FAILURE) {
1396 		RETURN_THROWS();
1397 	}
1398 
1399 	if (file_len == 0) {
1400 		zend_argument_value_error(1, "must not be empty");
1401 		RETURN_THROWS();
1402 	}
1403 
1404 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1405 
1406 	/* encoding handled by property on doc */
1407 
1408 	doc_props = dom_get_doc_props(intern->document);
1409 	format = doc_props->formatoutput;
1410 	if (options & LIBXML_SAVE_NOEMPTYTAG) {
1411 		saveempty = xmlSaveNoEmptyTags;
1412 		xmlSaveNoEmptyTags = 1;
1413 	}
1414 	bytes = xmlSaveFormatFileEnc(file, docp, NULL, format);
1415 	if (options & LIBXML_SAVE_NOEMPTYTAG) {
1416 		xmlSaveNoEmptyTags = saveempty;
1417 	}
1418 	if (bytes == -1) {
1419 		RETURN_FALSE;
1420 	}
1421 	RETURN_LONG(bytes);
1422 }
1423 /* }}} end dom_document_save */
1424 
1425 /* {{{ URL: http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS-saveXML
1426 Since: DOM Level 3
1427 */
PHP_METHOD(DOMDocument,saveXML)1428 PHP_METHOD(DOMDocument, saveXML)
1429 {
1430 	zval *id, *nodep = NULL;
1431 	xmlDoc *docp;
1432 	xmlNode *node;
1433 	xmlBufferPtr buf;
1434 	xmlChar *mem;
1435 	dom_object *intern, *nodeobj;
1436 	dom_doc_propsptr doc_props;
1437 	int size, format, saveempty = 0;
1438 	zend_long options = 0;
1439 
1440 	id = ZEND_THIS;
1441 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!l", &nodep, dom_node_class_entry, &options) == FAILURE) {
1442 		RETURN_THROWS();
1443 	}
1444 
1445 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1446 
1447 	doc_props = dom_get_doc_props(intern->document);
1448 	format = doc_props->formatoutput;
1449 
1450 	if (nodep != NULL) {
1451 		/* Dump contents of Node */
1452 		DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1453 		if (node->doc != docp) {
1454 			php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
1455 			RETURN_FALSE;
1456 		}
1457 		buf = xmlBufferCreate();
1458 		if (!buf) {
1459 			php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
1460 			RETURN_FALSE;
1461 		}
1462 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1463 			saveempty = xmlSaveNoEmptyTags;
1464 			xmlSaveNoEmptyTags = 1;
1465 		}
1466 		xmlNodeDump(buf, docp, node, 0, format);
1467 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1468 			xmlSaveNoEmptyTags = saveempty;
1469 		}
1470 		mem = (xmlChar*) xmlBufferContent(buf);
1471 		if (!mem) {
1472 			xmlBufferFree(buf);
1473 			RETURN_FALSE;
1474 		}
1475 		RETVAL_STRING((char *) mem);
1476 		xmlBufferFree(buf);
1477 	} else {
1478 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1479 			saveempty = xmlSaveNoEmptyTags;
1480 			xmlSaveNoEmptyTags = 1;
1481 		}
1482 		/* Encoding is handled from the encoding property set on the document */
1483 		xmlDocDumpFormatMemory(docp, &mem, &size, format);
1484 		if (options & LIBXML_SAVE_NOEMPTYTAG) {
1485 			xmlSaveNoEmptyTags = saveempty;
1486 		}
1487 		if (!size || !mem) {
1488 			RETURN_FALSE;
1489 		}
1490 		RETVAL_STRINGL((char *) mem, size);
1491 		xmlFree(mem);
1492 	}
1493 }
1494 /* }}} end dom_document_savexml */
1495 
php_dom_free_xinclude_node(xmlNodePtr cur)1496 static xmlNodePtr php_dom_free_xinclude_node(xmlNodePtr cur) /* {{{ */
1497 {
1498 	xmlNodePtr xincnode;
1499 
1500 	xincnode = cur;
1501 	cur = cur->next;
1502 	xmlUnlinkNode(xincnode);
1503 	php_libxml_node_free_resource(xincnode);
1504 
1505 	return cur;
1506 }
1507 /* }}} */
1508 
php_dom_remove_xinclude_nodes(xmlNodePtr cur)1509 static void php_dom_remove_xinclude_nodes(xmlNodePtr cur) /* {{{ */
1510 {
1511 	while(cur) {
1512 		if (cur->type == XML_XINCLUDE_START) {
1513 			cur = php_dom_free_xinclude_node(cur);
1514 
1515 			/* XML_XINCLUDE_END node will be a sibling of XML_XINCLUDE_START */
1516 			while(cur && cur->type != XML_XINCLUDE_END) {
1517 				/* remove xinclude processing nodes from recursive xincludes */
1518 				if (cur->type == XML_ELEMENT_NODE) {
1519 					   php_dom_remove_xinclude_nodes(cur->children);
1520 				}
1521 				cur = cur->next;
1522 			}
1523 
1524 			if (cur && cur->type == XML_XINCLUDE_END) {
1525 				cur = php_dom_free_xinclude_node(cur);
1526 			}
1527 		} else {
1528 			if (cur->type == XML_ELEMENT_NODE) {
1529 				php_dom_remove_xinclude_nodes(cur->children);
1530 			}
1531 			cur = cur->next;
1532 		}
1533 	}
1534 }
1535 /* }}} */
1536 
1537 /* {{{ Substitutues xincludes in a DomDocument */
PHP_METHOD(DOMDocument,xinclude)1538 PHP_METHOD(DOMDocument, xinclude)
1539 {
1540 	zval *id;
1541 	xmlDoc *docp;
1542 	xmlNodePtr root;
1543 	zend_long flags = 0;
1544 	int err;
1545 	dom_object *intern;
1546 
1547 	id = ZEND_THIS;
1548 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags) == FAILURE) {
1549 		RETURN_THROWS();
1550 	}
1551 
1552 	if (ZEND_LONG_EXCEEDS_INT(flags)) {
1553 		php_error_docref(NULL, E_WARNING, "Invalid flags");
1554 		RETURN_FALSE;
1555 	}
1556 
1557 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1558 
1559 	err = xmlXIncludeProcessFlags(docp, (int)flags);
1560 
1561 	/* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
1562 	are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
1563 	but are not wanted in resulting document - must be done even if err as it could fail after
1564 	having processed some xincludes */
1565 	root = (xmlNodePtr) docp->children;
1566 	while(root && root->type != XML_ELEMENT_NODE && root->type != XML_XINCLUDE_START) {
1567 		root = root->next;
1568 	}
1569 	if (root) {
1570 		php_dom_remove_xinclude_nodes(root);
1571 	}
1572 
1573 	if (err) {
1574 		RETVAL_LONG(err);
1575 	} else {
1576 		RETVAL_FALSE;
1577 	}
1578 
1579 }
1580 /* }}} */
1581 
1582 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,validate)1583 PHP_METHOD(DOMDocument, validate)
1584 {
1585 	zval *id;
1586 	xmlDoc *docp;
1587 	dom_object *intern;
1588 	xmlValidCtxt *cvp;
1589 
1590 	id = ZEND_THIS;
1591 	if (zend_parse_parameters_none() == FAILURE) {
1592 		RETURN_THROWS();
1593 	}
1594 
1595 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1596 
1597 	cvp = xmlNewValidCtxt();
1598 
1599 	cvp->userData = NULL;
1600 	cvp->error    = (xmlValidityErrorFunc) php_libxml_error_handler;
1601 	cvp->warning  = (xmlValidityErrorFunc) php_libxml_error_handler;
1602 
1603 	if (xmlValidateDocument(cvp, docp)) {
1604 		RETVAL_TRUE;
1605 	} else {
1606 		RETVAL_FALSE;
1607 	}
1608 
1609 	xmlFreeValidCtxt(cvp);
1610 
1611 }
1612 /* }}} */
1613 
1614 #ifdef LIBXML_SCHEMAS_ENABLED
_dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS,int type)1615 static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1616 {
1617 	zval *id;
1618 	xmlDoc *docp;
1619 	dom_object *intern;
1620 	char *source = NULL, *valid_file = NULL;
1621 	size_t source_len = 0;
1622 	int valid_opts = 0;
1623 	zend_long flags = 0;
1624 	xmlSchemaParserCtxtPtr  parser;
1625 	xmlSchemaPtr            sptr;
1626 	xmlSchemaValidCtxtPtr   vptr;
1627 	int                     is_valid;
1628 	char resolved_path[MAXPATHLEN + 1];
1629 
1630 	id = ZEND_THIS;
1631 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &flags) == FAILURE) {
1632 		RETURN_THROWS();
1633 	}
1634 
1635 	if (!source_len) {
1636 		zend_argument_value_error(1, "must not be empty");
1637 		RETURN_THROWS();
1638 	}
1639 
1640 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1641 
1642 	switch (type) {
1643 	case DOM_LOAD_FILE:
1644 		if (CHECK_NULL_PATH(source, source_len)) {
1645 			zend_argument_value_error(1, "must not contain any null bytes");
1646 			RETURN_THROWS();
1647 		}
1648 		valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1649 		if (!valid_file) {
1650 			php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
1651 			RETURN_FALSE;
1652 		}
1653 		parser = xmlSchemaNewParserCtxt(valid_file);
1654 		break;
1655 	case DOM_LOAD_STRING:
1656 		parser = xmlSchemaNewMemParserCtxt(source, source_len);
1657 		/* If loading from memory, we need to set the base directory for the document
1658 		   but it is not apparent how to do that for schema's */
1659 		break;
1660 	default:
1661 		return;
1662 	}
1663 
1664 	xmlSchemaSetParserErrors(parser,
1665 		(xmlSchemaValidityErrorFunc) php_libxml_error_handler,
1666 		(xmlSchemaValidityWarningFunc) php_libxml_error_handler,
1667 		parser);
1668 	sptr = xmlSchemaParse(parser);
1669 	xmlSchemaFreeParserCtxt(parser);
1670 	if (!sptr) {
1671 		if (!EG(exception)) {
1672 			php_error_docref(NULL, E_WARNING, "Invalid Schema");
1673 		}
1674 		RETURN_FALSE;
1675 	}
1676 
1677 	docp = (xmlDocPtr) dom_object_get_node(intern);
1678 
1679 	vptr = xmlSchemaNewValidCtxt(sptr);
1680 	if (!vptr) {
1681 		xmlSchemaFree(sptr);
1682 		zend_throw_error(NULL, "Invalid Schema Validation Context");
1683 		RETURN_THROWS();
1684 	}
1685 
1686 	if (flags & XML_SCHEMA_VAL_VC_I_CREATE) {
1687 		valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE;
1688 	}
1689 
1690 	xmlSchemaSetValidOptions(vptr, valid_opts);
1691 	xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1692 	is_valid = xmlSchemaValidateDoc(vptr, docp);
1693 	xmlSchemaFree(sptr);
1694 	xmlSchemaFreeValidCtxt(vptr);
1695 
1696 	if (is_valid == 0) {
1697 		RETURN_TRUE;
1698 	} else {
1699 		RETURN_FALSE;
1700 	}
1701 }
1702 /* }}} */
1703 
1704 /* {{{ */
PHP_METHOD(DOMDocument,schemaValidate)1705 PHP_METHOD(DOMDocument, schemaValidate)
1706 {
1707 	_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1708 }
1709 /* }}} end dom_document_schema_validate_file */
1710 
1711 /* {{{ */
PHP_METHOD(DOMDocument,schemaValidateSource)1712 PHP_METHOD(DOMDocument, schemaValidateSource)
1713 {
1714 	_dom_document_schema_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1715 }
1716 /* }}} end dom_document_schema_validate */
1717 
_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS,int type)1718 static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
1719 {
1720 	zval *id;
1721 	xmlDoc *docp;
1722 	dom_object *intern;
1723 	char *source = NULL, *valid_file = NULL;
1724 	size_t source_len = 0;
1725 	xmlRelaxNGParserCtxtPtr parser;
1726 	xmlRelaxNGPtr           sptr;
1727 	xmlRelaxNGValidCtxtPtr  vptr;
1728 	int                     is_valid;
1729 	char resolved_path[MAXPATHLEN + 1];
1730 
1731 	id = ZEND_THIS;
1732 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &source, &source_len) == FAILURE) {
1733 		RETURN_THROWS();
1734 	}
1735 
1736 	if (!source_len) {
1737 		zend_argument_value_error(1, "must not be empty");
1738 		RETURN_THROWS();
1739 	}
1740 
1741 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1742 
1743 	switch (type) {
1744 	case DOM_LOAD_FILE:
1745 		if (CHECK_NULL_PATH(source, source_len)) {
1746 			zend_argument_value_error(1, "must not contain any null bytes");
1747 			RETURN_THROWS();
1748 		}
1749 		valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
1750 		if (!valid_file) {
1751 			php_error_docref(NULL, E_WARNING, "Invalid RelaxNG file source");
1752 			RETURN_FALSE;
1753 		}
1754 		parser = xmlRelaxNGNewParserCtxt(valid_file);
1755 		break;
1756 	case DOM_LOAD_STRING:
1757 		parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
1758 		/* If loading from memory, we need to set the base directory for the document
1759 		   but it is not apparent how to do that for schema's */
1760 		break;
1761 	default:
1762 		return;
1763 	}
1764 
1765 	xmlRelaxNGSetParserErrors(parser,
1766 		(xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
1767 		(xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
1768 		parser);
1769 	sptr = xmlRelaxNGParse(parser);
1770 	xmlRelaxNGFreeParserCtxt(parser);
1771 	if (!sptr) {
1772 		php_error_docref(NULL, E_WARNING, "Invalid RelaxNG");
1773 		RETURN_FALSE;
1774 	}
1775 
1776 	docp = (xmlDocPtr) dom_object_get_node(intern);
1777 
1778 	vptr = xmlRelaxNGNewValidCtxt(sptr);
1779 	if (!vptr) {
1780 		xmlRelaxNGFree(sptr);
1781 		zend_throw_error(NULL, "Invalid RelaxNG Validation Context");
1782 		RETURN_THROWS();
1783 	}
1784 
1785 	xmlRelaxNGSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
1786 	is_valid = xmlRelaxNGValidateDoc(vptr, docp);
1787 	xmlRelaxNGFree(sptr);
1788 	xmlRelaxNGFreeValidCtxt(vptr);
1789 
1790 	if (is_valid == 0) {
1791 		RETURN_TRUE;
1792 	} else {
1793 		RETURN_FALSE;
1794 	}
1795 }
1796 /* }}} */
1797 
1798 /* {{{ */
PHP_METHOD(DOMDocument,relaxNGValidate)1799 PHP_METHOD(DOMDocument, relaxNGValidate)
1800 {
1801 	_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1802 }
1803 /* }}} end dom_document_relaxNG_validate_file */
1804 
1805 /* {{{ */
PHP_METHOD(DOMDocument,relaxNGValidateSource)1806 PHP_METHOD(DOMDocument, relaxNGValidateSource)
1807 {
1808 	_dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1809 }
1810 /* }}} end dom_document_relaxNG_validate_xml */
1811 
1812 #endif
1813 
1814 #ifdef LIBXML_HTML_ENABLED
1815 
dom_load_html(INTERNAL_FUNCTION_PARAMETERS,int mode)1816 static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
1817 {
1818 	zval *id;
1819 	xmlDoc *docp = NULL, *newdoc;
1820 	dom_object *intern;
1821 	dom_doc_propsptr doc_prop;
1822 	char *source;
1823 	size_t source_len;
1824 	int refcount, ret;
1825 	zend_long options = 0;
1826 	htmlParserCtxtPtr ctxt;
1827 
1828 	id = getThis();
1829 
1830 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &source, &source_len, &options) == FAILURE) {
1831 		RETURN_THROWS();
1832 	}
1833 
1834 	if (!source_len) {
1835 		zend_argument_value_error(1, "must not be empty");
1836 		RETURN_THROWS();
1837 	}
1838 
1839 	if (ZEND_LONG_EXCEEDS_INT(options)) {
1840 		php_error_docref(NULL, E_WARNING, "Invalid options");
1841 		RETURN_FALSE;
1842 	}
1843 
1844 	if (mode == DOM_LOAD_FILE) {
1845 		if (CHECK_NULL_PATH(source, source_len)) {
1846 			zend_argument_value_error(1, "must not contain any null bytes");
1847 			RETURN_THROWS();
1848 		}
1849 		ctxt = htmlCreateFileParserCtxt(source, NULL);
1850 	} else {
1851 		if (ZEND_SIZE_T_INT_OVFL(source_len)) {
1852 			php_error_docref(NULL, E_WARNING, "Input string is too long");
1853 			RETURN_FALSE;
1854 		}
1855 		ctxt = htmlCreateMemoryParserCtxt(source, (int)source_len);
1856 	}
1857 
1858 	if (!ctxt) {
1859 		RETURN_FALSE;
1860 	}
1861 
1862 
1863 	ctxt->vctxt.error = php_libxml_ctx_error;
1864 	ctxt->vctxt.warning = php_libxml_ctx_warning;
1865 	if (ctxt->sax != NULL) {
1866 		ctxt->sax->error = php_libxml_ctx_error;
1867 		ctxt->sax->warning = php_libxml_ctx_warning;
1868 	}
1869 	if (options) {
1870 		htmlCtxtUseOptions(ctxt, (int)options);
1871 	}
1872 	htmlParseDocument(ctxt);
1873 	newdoc = ctxt->myDoc;
1874 	htmlFreeParserCtxt(ctxt);
1875 
1876 	if (!newdoc)
1877 		RETURN_FALSE;
1878 
1879 	if (id != NULL && instanceof_function(Z_OBJCE_P(id), dom_document_class_entry)) {
1880 		intern = Z_DOMOBJ_P(id);
1881 		if (intern != NULL) {
1882 			docp = (xmlDocPtr) dom_object_get_node(intern);
1883 			doc_prop = NULL;
1884 			if (docp != NULL) {
1885 				php_libxml_decrement_node_ptr((php_libxml_node_object *) intern);
1886 				doc_prop = intern->document->doc_props;
1887 				intern->document->doc_props = NULL;
1888 				refcount = php_libxml_decrement_doc_ref((php_libxml_node_object *)intern);
1889 				if (refcount != 0) {
1890 					docp->_private = NULL;
1891 				}
1892 			}
1893 			intern->document = NULL;
1894 			if (php_libxml_increment_doc_ref((php_libxml_node_object *)intern, newdoc) == -1) {
1895 				RETURN_FALSE;
1896 			}
1897 			intern->document->doc_props = doc_prop;
1898 		}
1899 
1900 		php_libxml_increment_node_ptr((php_libxml_node_object *)intern, (xmlNodePtr)newdoc, (void *)intern);
1901 
1902 		RETURN_TRUE;
1903 	} else {
1904 		DOM_RET_OBJ((xmlNodePtr) newdoc, &ret, NULL);
1905 	}
1906 }
1907 /* }}} */
1908 
1909 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,loadHTMLFile)1910 PHP_METHOD(DOMDocument, loadHTMLFile)
1911 {
1912 	dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_FILE);
1913 }
1914 /* }}} end dom_document_load_html_file */
1915 
1916 /* {{{ Since: DOM extended */
PHP_METHOD(DOMDocument,loadHTML)1917 PHP_METHOD(DOMDocument, loadHTML)
1918 {
1919 	dom_load_html(INTERNAL_FUNCTION_PARAM_PASSTHRU, DOM_LOAD_STRING);
1920 }
1921 /* }}} end dom_document_load_html */
1922 
1923 /* {{{ Convenience method to save to file as html */
PHP_METHOD(DOMDocument,saveHTMLFile)1924 PHP_METHOD(DOMDocument, saveHTMLFile)
1925 {
1926 	zval *id;
1927 	xmlDoc *docp;
1928 	size_t file_len;
1929 	int bytes, format;
1930 	dom_object *intern;
1931 	dom_doc_propsptr doc_props;
1932 	char *file;
1933 	const char *encoding;
1934 
1935 	id = ZEND_THIS;
1936 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &file, &file_len) == FAILURE) {
1937 		RETURN_THROWS();
1938 	}
1939 
1940 	if (file_len == 0) {
1941 		zend_argument_value_error(1, "must not be empty");
1942 		RETURN_THROWS();
1943 	}
1944 
1945 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1946 
1947 
1948 	encoding = (const char *) htmlGetMetaEncoding(docp);
1949 
1950 	doc_props = dom_get_doc_props(intern->document);
1951 	format = doc_props->formatoutput;
1952 	bytes = htmlSaveFileFormat(file, docp, encoding, format);
1953 
1954 	if (bytes == -1) {
1955 		RETURN_FALSE;
1956 	}
1957 	RETURN_LONG(bytes);
1958 }
1959 /* }}} end dom_document_save_html_file */
1960 
1961 /* {{{ Convenience method to output as html */
PHP_METHOD(DOMDocument,saveHTML)1962 PHP_METHOD(DOMDocument, saveHTML)
1963 {
1964 	zval *id, *nodep = NULL;
1965 	xmlDoc *docp;
1966 	xmlNode *node;
1967 	xmlOutputBufferPtr outBuf;
1968 	xmlBufferPtr buf;
1969 	dom_object *intern, *nodeobj;
1970 	xmlChar *mem = NULL;
1971 	int format;
1972 	dom_doc_propsptr doc_props;
1973 
1974 	id = ZEND_THIS;
1975 	if (zend_parse_parameters(ZEND_NUM_ARGS(),
1976 		"|O!", &nodep, dom_node_class_entry)
1977 		== FAILURE) {
1978 		RETURN_THROWS();
1979 	}
1980 
1981 	DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
1982 
1983 	doc_props = dom_get_doc_props(intern->document);
1984 	format = doc_props->formatoutput;
1985 
1986 	if (nodep != NULL) {
1987 		/* Dump contents of Node */
1988 		DOM_GET_OBJ(node, nodep, xmlNodePtr, nodeobj);
1989 		if (node->doc != docp) {
1990 			php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
1991 			RETURN_FALSE;
1992 		}
1993 
1994 		buf = xmlBufferCreate();
1995 		if (!buf) {
1996 			php_error_docref(NULL, E_WARNING, "Could not fetch buffer");
1997 			RETURN_FALSE;
1998 		}
1999 		outBuf = xmlOutputBufferCreateBuffer(buf, NULL);
2000 		if (!outBuf) {
2001 			xmlBufferFree(buf);
2002 			php_error_docref(NULL, E_WARNING, "Could not fetch output buffer");
2003 			RETURN_FALSE;
2004 		}
2005 
2006 		if (node->type == XML_DOCUMENT_FRAG_NODE) {
2007 			for (node = node->children; node; node = node->next) {
2008 				htmlNodeDumpFormatOutput(outBuf, docp, node, NULL, format);
2009 				if (outBuf->error) {
2010 					break;
2011 				}
2012 			}
2013 		} else {
2014 			htmlNodeDumpFormatOutput(outBuf, docp, node, NULL, format);
2015 		}
2016 		if (!outBuf->error) {
2017 			xmlOutputBufferFlush(outBuf);
2018 			mem = (xmlChar*) xmlBufferContent(buf);
2019 			if (!mem) {
2020 				RETVAL_FALSE;
2021 			} else {
2022 				int size = xmlBufferLength(buf);
2023 				RETVAL_STRINGL((const char*) mem, size);
2024 			}
2025 		} else {
2026 			php_error_docref(NULL, E_WARNING, "Error dumping HTML node");
2027 			RETVAL_FALSE;
2028 		}
2029 		xmlOutputBufferClose(outBuf);
2030 		xmlBufferFree(buf);
2031 	} else {
2032 		int size = 0;
2033 		htmlDocDumpMemoryFormat(docp, &mem, &size, format);
2034 		if (!size || !mem) {
2035 			RETVAL_FALSE;
2036 		} else {
2037 			RETVAL_STRINGL((const char*) mem, size);
2038 		}
2039 		if (mem)
2040 			xmlFree(mem);
2041 	}
2042 
2043 }
2044 /* }}} end dom_document_save_html */
2045 
2046 #endif  /* defined(LIBXML_HTML_ENABLED) */
2047 
2048 /* {{{ Register extended class used to create base node type */
PHP_METHOD(DOMDocument,registerNodeClass)2049 PHP_METHOD(DOMDocument, registerNodeClass)
2050 {
2051 	zval *id;
2052 	xmlDoc *docp;
2053 	zend_class_entry *basece = dom_node_class_entry, *ce = NULL;
2054 	dom_object *intern;
2055 
2056 	id = ZEND_THIS;
2057 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "CC!", &basece, &ce) == FAILURE) {
2058 		RETURN_THROWS();
2059 	}
2060 
2061 	if (ce == NULL || instanceof_function(ce, basece)) {
2062 		DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
2063 		dom_set_doc_classmap(intern->document, basece, ce);
2064 		RETURN_TRUE;
2065 	}
2066 
2067 	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));
2068 }
2069 /* }}} */
2070 
2071 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-append
2072 Since: DOM Living Standard (DOM4)
2073 */
PHP_METHOD(DOMDocument,append)2074 PHP_METHOD(DOMDocument, append)
2075 {
2076 	int argc;
2077 	zval *args, *id;
2078 	dom_object *intern;
2079 	xmlNode *context;
2080 
2081 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
2082 		RETURN_THROWS();
2083 	}
2084 
2085 	id = ZEND_THIS;
2086 	DOM_GET_OBJ(context, id, xmlNodePtr, intern);
2087 
2088 	dom_parent_node_append(intern, args, argc);
2089 }
2090 /* }}} */
2091 
2092 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
2093 Since: DOM Living Standard (DOM4)
2094 */
PHP_METHOD(DOMDocument,prepend)2095 PHP_METHOD(DOMDocument, prepend)
2096 {
2097 	int argc;
2098 	zval *args, *id;
2099 	dom_object *intern;
2100 	xmlNode *context;
2101 
2102 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
2103 		RETURN_THROWS();
2104 	}
2105 
2106 	id = ZEND_THIS;
2107 	DOM_GET_OBJ(context, id, xmlNodePtr, intern);
2108 
2109 	dom_parent_node_prepend(intern, args, argc);
2110 }
2111 /* }}} */
2112 
2113 #endif  /* HAVE_LIBXML && HAVE_DOM */
2114