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