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