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