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