1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Christian Stocker <chregu@php.net> |
14 | Rob Richards <rrichards@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php.h"
23 #if defined(HAVE_LIBXML) && defined(HAVE_DOM)
24 #include "php_dom.h"
25 #include "namespace_compat.h"
26 #include "internal_helpers.h"
27 #include "dom_properties.h"
28
29 /*
30 * class DOMElement extends DOMNode
31 *
32 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-745549614
33 * Since:
34 */
35
36 /* {{{ */
PHP_METHOD(DOMElement,__construct)37 PHP_METHOD(DOMElement, __construct)
38 {
39 xmlNodePtr nodep = NULL, oldnode = NULL;
40 dom_object *intern;
41 char *name, *value = NULL, *uri = NULL;
42 char *localname = NULL, *prefix = NULL;
43 int errorcode = 0;
44 size_t name_len, value_len = 0, uri_len = 0;
45 int name_valid;
46 xmlNsPtr nsptr = NULL;
47
48 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!s", &name, &name_len, &value, &value_len, &uri, &uri_len) == FAILURE) {
49 RETURN_THROWS();
50 }
51
52 name_valid = xmlValidateName(BAD_CAST name, 0);
53 if (name_valid != 0) {
54 php_dom_throw_error(INVALID_CHARACTER_ERR, true);
55 RETURN_THROWS();
56 }
57
58 /* Namespace logic is separate and only when uri passed in to insure no BC breakage */
59 if (uri_len > 0) {
60 errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
61 if (errorcode == 0) {
62 nodep = xmlNewNode (NULL, BAD_CAST localname);
63 if (nodep != NULL && uri != NULL) {
64 nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);
65 xmlSetNs(nodep, nsptr);
66 }
67 }
68 xmlFree(localname);
69 if (prefix != NULL) {
70 xmlFree(prefix);
71 }
72 if (errorcode != 0) {
73 if (nodep != NULL) {
74 xmlFreeNode(nodep);
75 }
76 php_dom_throw_error(errorcode, true);
77 RETURN_THROWS();
78 }
79 } else {
80 /* If you don't pass a namespace uri, then you can't set a prefix */
81 localname = (char *) xmlSplitQName2(BAD_CAST name, (xmlChar **) &prefix);
82 if (prefix != NULL) {
83 xmlFree(localname);
84 xmlFree(prefix);
85 php_dom_throw_error(NAMESPACE_ERR, true);
86 RETURN_THROWS();
87 }
88 nodep = xmlNewNode(NULL, BAD_CAST name);
89 }
90
91 if (!nodep) {
92 php_dom_throw_error(INVALID_STATE_ERR, true);
93 RETURN_THROWS();
94 }
95
96 if (value_len > 0) {
97 xmlNodeSetContentLen(nodep, BAD_CAST value, value_len);
98 }
99
100 intern = Z_DOMOBJ_P(ZEND_THIS);
101 oldnode = dom_object_get_node(intern);
102 if (oldnode != NULL) {
103 php_libxml_node_decrement_resource((php_libxml_node_object *)intern);
104 }
105 php_libxml_increment_node_ptr((php_libxml_node_object *)intern, nodep, (void *)intern);
106 }
107 /* }}} end DOMElement::__construct */
108
109 /* {{{ tagName string
110 readonly=yes
111 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-104682815
112 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-tagname
113 Since:
114 */
dom_element_tag_name_read(dom_object * obj,zval * retval)115 zend_result dom_element_tag_name_read(dom_object *obj, zval *retval)
116 {
117 DOM_PROP_NODE(xmlNodePtr, nodep, obj);
118
119 bool uppercase = php_dom_follow_spec_intern(obj) && php_dom_ns_is_html_and_document_is_html(nodep);
120
121 zend_string *result = dom_node_get_node_name_attribute_or_element((const xmlNode *) nodep, uppercase);
122 ZVAL_NEW_STR(retval, result);
123
124 return SUCCESS;
125 }
126
127 /* }}} */
128
dom_element_reflected_attribute_read(dom_object * obj,zval * retval,const char * name)129 static zend_result dom_element_reflected_attribute_read(dom_object *obj, zval *retval, const char *name)
130 {
131 DOM_PROP_NODE(xmlNodePtr, nodep, obj);
132
133 xmlChar *content = xmlGetNoNsProp(nodep, (const xmlChar *) name);
134 if (content == NULL) {
135 ZVAL_EMPTY_STRING(retval);
136 return SUCCESS;
137 }
138
139 ZVAL_STRING(retval, (const char *) content);
140 xmlFree(content);
141
142 return SUCCESS;
143 }
144
dom_element_reflected_attribute_write(dom_object * obj,zval * newval,const char * name)145 static xmlAttrPtr dom_element_reflected_attribute_write(dom_object *obj, zval *newval, const char *name)
146 {
147 xmlNode *nodep = dom_object_get_node(obj);
148
149 if (nodep == NULL) {
150 php_dom_throw_error(INVALID_STATE_ERR, true);
151 return NULL;
152 }
153
154 /* Typed property, so it is a string already */
155 ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING);
156 return xmlSetNsProp(nodep, NULL, (const xmlChar *) name, (const xmlChar *) Z_STRVAL_P(newval));
157 }
158
159 /* {{{ className string
160 URL: https://dom.spec.whatwg.org/#dom-element-classname
161 Since:
162 */
dom_element_class_name_read(dom_object * obj,zval * retval)163 zend_result dom_element_class_name_read(dom_object *obj, zval *retval)
164 {
165 return dom_element_reflected_attribute_read(obj, retval, "class");
166 }
167
dom_element_class_name_write(dom_object * obj,zval * newval)168 zend_result dom_element_class_name_write(dom_object *obj, zval *newval)
169 {
170 if (dom_element_reflected_attribute_write(obj, newval, "class")) {
171 return SUCCESS;
172 }
173 return FAILURE;
174 }
175 /* }}} */
176
177 /* {{{ id string
178 URL: https://dom.spec.whatwg.org/#dom-element-id
179 Since:
180 */
dom_element_id_read(dom_object * obj,zval * retval)181 zend_result dom_element_id_read(dom_object *obj, zval *retval)
182 {
183 return dom_element_reflected_attribute_read(obj, retval, "id");
184 }
185
186 static void php_set_attribute_id(xmlAttrPtr attrp, bool is_id);
187
dom_element_id_write(dom_object * obj,zval * newval)188 zend_result dom_element_id_write(dom_object *obj, zval *newval)
189 {
190 xmlAttrPtr attr = dom_element_reflected_attribute_write(obj, newval, "id");
191 if (!attr) {
192 return FAILURE;
193 }
194 php_set_attribute_id(attr, true);
195 return SUCCESS;
196 }
197 /* }}} */
198
199 /* {{{ schemaTypeInfo typeinfo
200 readonly=yes
201 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Element-schemaTypeInfo
202 Since: DOM Level 3
203 */
dom_element_schema_type_info_read(dom_object * obj,zval * retval)204 zend_result dom_element_schema_type_info_read(dom_object *obj, zval *retval)
205 {
206 ZVAL_NULL(retval);
207 return SUCCESS;
208 }
209
210 /* }}} */
211
212 /* Note: the object returned is not necessarily a node, but can be an attribute or a namespace declaration. */
dom_get_attribute_or_nsdecl(dom_object * intern,xmlNodePtr elem,const xmlChar * name,size_t name_len)213 static xmlNodePtr dom_get_attribute_or_nsdecl(dom_object *intern, xmlNodePtr elem, const xmlChar *name, size_t name_len) /* {{{ */
214 {
215 if (!php_dom_follow_spec_intern(intern)) {
216 int len;
217 const xmlChar *nqname = xmlSplitQName3(name, &len);
218
219 if (nqname != NULL) {
220 xmlNsPtr ns;
221 if (strncmp((const char *) name, "xmlns:", len + 1) == 0) {
222 ns = elem->nsDef;
223 while (ns) {
224 if (xmlStrEqual(ns->prefix, nqname)) {
225 break;
226 }
227 ns = ns->next;
228 }
229 return (xmlNodePtr)ns;
230 }
231 xmlChar *prefix = xmlStrndup(name, len);
232 ns = xmlSearchNs(elem->doc, elem, prefix);
233 if (prefix != NULL) {
234 xmlFree(prefix);
235 }
236 if (ns != NULL) {
237 return (xmlNodePtr)xmlHasNsProp(elem, nqname, ns->href);
238 }
239 } else {
240 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
241 xmlNsPtr nsPtr = elem->nsDef;
242 while (nsPtr) {
243 if (nsPtr->prefix == NULL) {
244 return (xmlNodePtr)nsPtr;
245 }
246 nsPtr = nsPtr->next;
247 }
248 return NULL;
249 }
250 }
251 return (xmlNodePtr) xmlHasNsProp(elem, name, NULL);
252 } else {
253 return (xmlNodePtr) php_dom_get_attribute_node(elem, name, name_len);
254 }
255 }
256 /* }}} */
257
258 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-666EE0F9
259 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-getattribute
260 Since:
261 */
PHP_METHOD(DOMElement,getAttribute)262 PHP_METHOD(DOMElement, getAttribute)
263 {
264 zval *id;
265 xmlNode *nodep;
266 char *name;
267 xmlChar *value = NULL;
268 dom_object *intern;
269 xmlNodePtr attr;
270 size_t name_len;
271 bool should_free = false;
272
273 id = ZEND_THIS;
274 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
275 RETURN_THROWS();
276 }
277
278 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
279
280 attr = dom_get_attribute_or_nsdecl(intern, nodep, BAD_CAST name, name_len);
281 if (attr) {
282 switch (attr->type) {
283 case XML_ATTRIBUTE_NODE:
284 value = xmlNodeListGetString(attr->doc, attr->children, 1);
285 should_free = true;
286 break;
287 case XML_NAMESPACE_DECL:
288 value = BAD_CAST ((xmlNsPtr)attr)->href;
289 should_free = false;
290 break;
291 default:
292 value = BAD_CAST ((xmlAttributePtr)attr)->defaultValue;
293 should_free = false;
294 }
295 }
296
297 if (value == NULL) {
298 if (php_dom_follow_spec_intern(intern)) {
299 RETURN_NULL();
300 }
301 RETURN_EMPTY_STRING();
302 } else {
303 RETVAL_STRING((char *)value);
304 if (should_free) {
305 xmlFree(value);
306 }
307 }
308 }
309 /* }}} end dom_element_get_attribute */
310
311 /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-getattributenames
312 Since:
313 */
PHP_METHOD(DOMElement,getAttributeNames)314 PHP_METHOD(DOMElement, getAttributeNames)
315 {
316 zval *id;
317 xmlNode *nodep;
318 dom_object *intern;
319 zval tmp;
320
321 if (zend_parse_parameters_none() == FAILURE) {
322 RETURN_THROWS();
323 }
324
325 DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern);
326
327 array_init(return_value);
328 HashTable *ht = Z_ARRVAL_P(return_value);
329 zend_hash_real_init_packed(ht);
330
331 if (!php_dom_follow_spec_intern(intern)) {
332 for (xmlNsPtr nsptr = nodep->nsDef; nsptr; nsptr = nsptr->next) {
333 const char *prefix = (const char *) nsptr->prefix;
334 ZVAL_NEW_STR(&tmp, dom_node_concatenated_name_helper(strlen(prefix), prefix, strlen("xmlns"), (const char *) "xmlns"));
335 zend_hash_next_index_insert(ht, &tmp);
336 }
337 }
338
339 for (xmlAttrPtr attr = nodep->properties; attr; attr = attr->next) {
340 ZVAL_NEW_STR(&tmp, dom_node_get_node_name_attribute_or_element((const xmlNode *) attr, false));
341 zend_hash_next_index_insert(ht, &tmp);
342 }
343 }
344 /* }}} end DOMElement::getAttributeNames() */
345
dom_create_attribute(xmlNodePtr nodep,const char * name,const char * value)346 static xmlNodePtr dom_create_attribute(xmlNodePtr nodep, const char *name, const char* value)
347 {
348 if (xmlStrEqual(BAD_CAST name, BAD_CAST "xmlns")) {
349 return (xmlNodePtr) xmlNewNs(nodep, BAD_CAST value, NULL);
350 } else {
351 return (xmlNodePtr) xmlSetProp(nodep, BAD_CAST name, BAD_CAST value);
352 }
353 }
354
355 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-F68F082
356 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-setattribute
357 Since:
358 */
PHP_METHOD(DOMElement,setAttribute)359 PHP_METHOD(DOMElement, setAttribute)
360 {
361 zval *id;
362 xmlNode *nodep;
363 xmlNodePtr attr = NULL;
364 int name_valid;
365 size_t name_len, value_len;
366 dom_object *intern;
367 char *name, *value;
368
369 id = ZEND_THIS;
370 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &name, &name_len, &value, &value_len) == FAILURE) {
371 RETURN_THROWS();
372 }
373
374 if (name_len == 0) {
375 zend_argument_value_error(1, "cannot be empty");
376 RETURN_THROWS();
377 }
378
379 name_valid = xmlValidateName(BAD_CAST name, 0);
380 if (name_valid != 0) {
381 php_dom_throw_error(INVALID_CHARACTER_ERR, true);
382 RETURN_THROWS();
383 }
384
385 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
386
387 if (php_dom_follow_spec_intern(intern)) {
388 xmlChar *name_processed = BAD_CAST name;
389 if (php_dom_ns_is_html_and_document_is_html(nodep)) {
390 char *lowercase_copy = zend_str_tolower_dup_ex(name, name_len);
391 if (lowercase_copy != NULL) {
392 name_processed = BAD_CAST lowercase_copy;
393 }
394 }
395
396 /* Can't use xmlSetNsProp unconditionally here because that doesn't take into account the qualified name matching... */
397 attr = (xmlNodePtr) php_dom_get_attribute_node(nodep, BAD_CAST name, name_len);
398 if (attr != NULL) {
399 dom_remove_all_children(attr);
400 xmlNodePtr node = xmlNewDocText(attr->doc, BAD_CAST value);
401 xmlAddChild(attr, node);
402 } else {
403 attr = (xmlNodePtr) xmlSetNsProp(nodep, NULL, name_processed, BAD_CAST value);
404 }
405
406 if (name_processed != BAD_CAST name) {
407 efree(name_processed);
408 }
409 } else {
410 attr = dom_get_attribute_or_nsdecl(intern, nodep, BAD_CAST name, name_len);
411 if (attr != NULL) {
412 switch (attr->type) {
413 case XML_ATTRIBUTE_NODE:
414 node_list_unlink(attr->children);
415 break;
416 case XML_NAMESPACE_DECL:
417 RETURN_FALSE;
418 EMPTY_SWITCH_DEFAULT_CASE();
419 }
420 }
421
422 attr = dom_create_attribute(nodep, name, value);
423 if (!attr) {
424 zend_argument_value_error(1, "must be a valid XML attribute");
425 RETURN_THROWS();
426 }
427 if (attr->type == XML_NAMESPACE_DECL) {
428 RETURN_TRUE;
429 }
430
431 DOM_RET_OBJ(attr, intern);
432 }
433 }
434 /* }}} end dom_element_set_attribute */
435
436 typedef struct _dom_deep_ns_redef_item {
437 xmlNodePtr current_node;
438 xmlNsPtr defined_ns;
439 } dom_deep_ns_redef_item;
440
441 /* Reconciliation for a *single* namespace, but reconciles *closest* to the subtree needing it. */
dom_deep_ns_redef(xmlNodePtr node,xmlNsPtr ns_to_redefine)442 static void dom_deep_ns_redef(xmlNodePtr node, xmlNsPtr ns_to_redefine)
443 {
444 size_t worklist_capacity = 128;
445 dom_deep_ns_redef_item *worklist = emalloc(sizeof(dom_deep_ns_redef_item) * worklist_capacity);
446 worklist[0].current_node = node;
447 worklist[0].defined_ns = NULL;
448 size_t worklist_size = 1;
449
450 while (worklist_size > 0) {
451 worklist_size--;
452 dom_deep_ns_redef_item *current_worklist_item = &worklist[worklist_size];
453 ZEND_ASSERT(current_worklist_item->current_node->type == XML_ELEMENT_NODE);
454 xmlNsPtr defined_ns = current_worklist_item->defined_ns;
455
456 if (current_worklist_item->current_node->ns == ns_to_redefine) {
457 if (defined_ns == NULL) {
458 defined_ns = xmlNewNs(current_worklist_item->current_node, ns_to_redefine->href, ns_to_redefine->prefix);
459 }
460 current_worklist_item->current_node->ns = defined_ns;
461 }
462
463 for (xmlAttrPtr attr = current_worklist_item->current_node->properties; attr; attr = attr->next) {
464 if (attr->ns == ns_to_redefine) {
465 if (defined_ns == NULL) {
466 defined_ns = xmlNewNs(current_worklist_item->current_node, ns_to_redefine->href, ns_to_redefine->prefix);
467 }
468 attr->ns = defined_ns;
469 }
470 }
471
472 for (xmlNodePtr child = current_worklist_item->current_node->children; child; child = child->next) {
473 if (child->type != XML_ELEMENT_NODE) {
474 continue;
475 }
476 if (worklist_size == worklist_capacity) {
477 if (UNEXPECTED(worklist_capacity >= SIZE_MAX / 3 * 2 / sizeof(dom_deep_ns_redef_item))) {
478 /* Shouldn't be possible to hit, but checked for safety anyway */
479 goto out;
480 }
481 worklist_capacity = worklist_capacity * 3 / 2;
482 worklist = erealloc(worklist, sizeof(dom_deep_ns_redef_item) * worklist_capacity);
483 }
484 worklist[worklist_size].current_node = child;
485 worklist[worklist_size].defined_ns = defined_ns;
486 worklist_size++;
487 }
488 }
489
490 out:
491 efree(worklist);
492 }
493
dom_remove_attribute(xmlNodePtr thisp,xmlNodePtr attrp)494 static bool dom_remove_attribute(xmlNodePtr thisp, xmlNodePtr attrp)
495 {
496 ZEND_ASSERT(thisp != NULL);
497 ZEND_ASSERT(attrp != NULL);
498
499 switch (attrp->type) {
500 case XML_ATTRIBUTE_NODE:
501 if (php_dom_object_get_data(attrp) == NULL) {
502 node_list_unlink(attrp->children);
503 xmlUnlinkNode(attrp);
504 xmlFreeProp((xmlAttrPtr)attrp);
505 } else {
506 xmlUnlinkNode(attrp);
507 }
508 break;
509 case XML_NAMESPACE_DECL: {
510 /* They will always be removed, but can be re-added.
511 *
512 * If any reference was left to the namespace, the only effect is that
513 * the definition is potentially moved closer to the element using it.
514 * If no reference was left, it is actually removed. */
515 xmlNsPtr ns = (xmlNsPtr) attrp;
516 if (thisp->nsDef == ns) {
517 thisp->nsDef = ns->next;
518 } else if (thisp->nsDef != NULL) {
519 xmlNsPtr prev = thisp->nsDef;
520 xmlNsPtr cur = prev->next;
521 while (cur) {
522 if (cur == ns) {
523 prev->next = cur->next;
524 break;
525 }
526 prev = cur;
527 cur = cur->next;
528 }
529 } else {
530 /* defensive: attrp not defined in thisp ??? */
531 #if ZEND_DEBUG
532 ZEND_UNREACHABLE();
533 #endif
534 break; /* defensive */
535 }
536
537 ns->next = NULL;
538 php_libxml_set_old_ns(thisp->doc, ns); /* note: can't deallocate as it might be referenced by a "fake namespace node" */
539 /* xmlReconciliateNs() redefines at the top of the tree instead of closest to the child, own reconciliation here.
540 * Similarly, the DOM version has other issues too (see dom_libxml_reconcile_ensure_namespaces_are_declared). */
541 dom_deep_ns_redef(thisp, ns);
542
543 break;
544 }
545 EMPTY_SWITCH_DEFAULT_CASE();
546 }
547 return true;
548 }
549
550 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6D6AC0F9
551 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-removeattribute
552 Since:
553 */
PHP_METHOD(DOMElement,removeAttribute)554 PHP_METHOD(DOMElement, removeAttribute)
555 {
556 xmlNodePtr nodep, attrp;
557 dom_object *intern;
558 size_t name_len;
559 char *name;
560
561 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
562 RETURN_THROWS();
563 }
564
565 DOM_GET_OBJ(nodep, ZEND_THIS, xmlNodePtr, intern);
566
567 attrp = dom_get_attribute_or_nsdecl(intern, nodep, BAD_CAST name, name_len);
568 if (attrp == NULL) {
569 RETURN_FALSE;
570 }
571
572 RETURN_BOOL(dom_remove_attribute(nodep, attrp));
573 }
574
PHP_METHOD(DOM_Element,removeAttribute)575 PHP_METHOD(DOM_Element, removeAttribute)
576 {
577 xmlNodePtr nodep, attrp;
578 dom_object *intern;
579 size_t name_len;
580 char *name;
581
582 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
583 RETURN_THROWS();
584 }
585
586 DOM_GET_OBJ(nodep, ZEND_THIS, xmlNodePtr, intern);
587
588 attrp = dom_get_attribute_or_nsdecl(intern, nodep, BAD_CAST name, name_len);
589 if (attrp != NULL) {
590 dom_remove_attribute(nodep, attrp);
591 }
592 }
593 /* }}} end dom_element_remove_attribute */
594
595 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-217A91B8
596 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-getattributenode
597 Since:
598 */
PHP_METHOD(DOMElement,getAttributeNode)599 PHP_METHOD(DOMElement, getAttributeNode)
600 {
601 zval *id;
602 xmlNodePtr nodep, attrp;
603 size_t name_len;
604 dom_object *intern;
605 char *name;
606
607 id = ZEND_THIS;
608 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
609 RETURN_THROWS();
610 }
611
612 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
613
614 attrp = dom_get_attribute_or_nsdecl(intern, nodep, BAD_CAST name, name_len);
615 if (attrp == NULL) {
616 if (php_dom_follow_spec_intern(intern)) {
617 RETURN_NULL();
618 }
619 RETURN_FALSE;
620 }
621
622 if (attrp->type == XML_NAMESPACE_DECL) {
623 xmlNsPtr original = (xmlNsPtr) attrp;
624 /* Keep parent alive, because we're a fake child. */
625 GC_ADDREF(&intern->std);
626 (void) php_dom_create_fake_namespace_decl(nodep, original, return_value, intern);
627 } else {
628 DOM_RET_OBJ((xmlNodePtr) attrp, intern);
629 }
630 }
631 /* }}} end dom_element_get_attribute_node */
632
dom_element_set_attribute_node_common(INTERNAL_FUNCTION_PARAMETERS,bool use_ns,bool modern)633 static void dom_element_set_attribute_node_common(INTERNAL_FUNCTION_PARAMETERS, bool use_ns, bool modern)
634 {
635 zval *id, *node;
636 xmlNode *nodep;
637 xmlNs *nsp;
638 xmlAttr *attrp, *existattrp = NULL;
639 dom_object *intern, *attrobj, *oldobj;
640
641 id = ZEND_THIS;
642 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node, dom_get_node_ce(modern)) == FAILURE) {
643 RETURN_THROWS();
644 }
645
646 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
647 DOM_GET_OBJ(attrp, node, xmlAttrPtr, attrobj);
648
649 /* ZPP Guarantees that a DOMAttr class is given, as it is converted to a xmlAttr
650 * to pass to libxml (see http://www.xmlsoft.org/html/libxml-tree.html#xmlAttr)
651 * if it is not of type XML_ATTRIBUTE_NODE it indicates a bug somewhere */
652 ZEND_ASSERT(attrp->type == XML_ATTRIBUTE_NODE);
653
654 if (modern) {
655 if (attrp->parent != NULL && attrp->parent != nodep) {
656 php_dom_throw_error(INUSE_ATTRIBUTE_ERR, /* strict */ true);
657 RETURN_THROWS();
658 }
659 if (attrp->doc != NULL && attrp->doc != nodep->doc) {
660 php_dom_adopt_node((xmlNodePtr) attrp, intern, nodep->doc);
661 }
662 } else {
663 if (!(attrp->doc == NULL || attrp->doc == nodep->doc)) {
664 php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(intern->document));
665 RETURN_FALSE;
666 }
667 }
668
669 nsp = attrp->ns;
670 if (use_ns && nsp != NULL) {
671 existattrp = xmlHasNsProp(nodep, attrp->name, nsp->href);
672 } else {
673 existattrp = xmlHasProp(nodep, attrp->name);
674 }
675
676 if (existattrp != NULL && existattrp->type != XML_ATTRIBUTE_DECL) {
677 if ((oldobj = php_dom_object_get_data((xmlNodePtr) existattrp)) != NULL &&
678 ((php_libxml_node_ptr *)oldobj->ptr)->node == (xmlNodePtr) attrp)
679 {
680 RETURN_NULL();
681 }
682 xmlUnlinkNode((xmlNodePtr) existattrp);
683 }
684
685 if (attrp->parent != NULL) {
686 xmlUnlinkNode((xmlNodePtr) attrp);
687 }
688
689 if (attrp->doc == NULL && nodep->doc != NULL) {
690 attrobj->document = intern->document;
691 php_libxml_increment_doc_ref((php_libxml_node_object *)attrobj, NULL);
692 }
693
694 xmlAddChild(nodep, (xmlNodePtr) attrp);
695 if (!modern) {
696 php_dom_reconcile_attribute_namespace_after_insertion(attrp);
697 }
698
699 /* Returns old property if removed otherwise NULL */
700 if (existattrp != NULL) {
701 DOM_RET_OBJ((xmlNodePtr) existattrp, intern);
702 } else {
703 RETURN_NULL();
704 }
705 }
706
707 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-887236154
708 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-setattributenode
709 Since:
710 */
PHP_METHOD(DOMElement,setAttributeNode)711 PHP_METHOD(DOMElement, setAttributeNode)
712 {
713 dom_element_set_attribute_node_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, /* use_ns */ false, /* modern */ false);
714 }
715 /* }}} end dom_element_set_attribute_node */
716
717 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-D589198
718 Since:
719 */
dom_element_remove_attribute_node(INTERNAL_FUNCTION_PARAMETERS,zend_class_entry * node_ce)720 static void dom_element_remove_attribute_node(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *node_ce)
721 {
722 zval *node;
723 xmlNode *nodep;
724 xmlAttr *attrp;
725 dom_object *intern, *attrobj;
726
727 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node, node_ce) == FAILURE) {
728 RETURN_THROWS();
729 }
730
731 DOM_GET_OBJ(nodep, ZEND_THIS, xmlNodePtr, intern);
732
733 DOM_GET_OBJ(attrp, node, xmlAttrPtr, attrobj);
734
735 ZEND_ASSERT(attrp->type == XML_ATTRIBUTE_NODE);
736
737 if (attrp->parent != nodep) {
738 php_dom_throw_error(NOT_FOUND_ERR, dom_get_strict_error(intern->document));
739 RETURN_FALSE;
740 }
741
742 xmlUnlinkNode((xmlNodePtr) attrp);
743
744 DOM_RET_OBJ((xmlNodePtr) attrp, intern);
745 }
746
PHP_METHOD(DOMElement,removeAttributeNode)747 PHP_METHOD(DOMElement, removeAttributeNode)
748 {
749 dom_element_remove_attribute_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_node_class_entry);
750 }
751
PHP_METHOD(DOM_Element,removeAttributeNode)752 PHP_METHOD(DOM_Element, removeAttributeNode)
753 {
754 dom_element_remove_attribute_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_modern_node_class_entry);
755 }
756 /* }}} end dom_element_remove_attribute_node */
757
758 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1938918D
759 Modern spec URL: https://dom.spec.whatwg.org/#concept-getelementsbytagname
760 Since:
761 */
dom_element_get_elements_by_tag_name(INTERNAL_FUNCTION_PARAMETERS,bool modern)762 static void dom_element_get_elements_by_tag_name(INTERNAL_FUNCTION_PARAMETERS, bool modern)
763 {
764 size_t name_len;
765 dom_object *intern, *namednode;
766 char *name;
767
768 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
769 RETURN_THROWS();
770 }
771
772 DOM_GET_THIS_INTERN(intern);
773
774 if (modern) {
775 php_dom_create_iterator(return_value, DOM_HTMLCOLLECTION, true);
776 } else {
777 php_dom_create_iterator(return_value, DOM_NODELIST, false);
778 }
779 namednode = Z_DOMOBJ_P(return_value);
780 dom_namednode_iter(intern, 0, namednode, NULL, name, name_len, NULL, 0);
781 }
782
PHP_METHOD(DOMElement,getElementsByTagName)783 PHP_METHOD(DOMElement, getElementsByTagName)
784 {
785 dom_element_get_elements_by_tag_name(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
786 }
787
PHP_METHOD(DOM_Element,getElementsByTagName)788 PHP_METHOD(DOM_Element, getElementsByTagName)
789 {
790 dom_element_get_elements_by_tag_name(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
791 }
792 /* }}} end dom_element_get_elements_by_tag_name */
793
794 /* should_free_result must be initialized to false */
dom_get_attribute_ns(dom_object * intern,xmlNodePtr elemp,const char * uri,size_t uri_len,const char * name,bool * should_free_result)795 static const xmlChar *dom_get_attribute_ns(dom_object *intern, xmlNodePtr elemp, const char *uri, size_t uri_len, const char *name, bool *should_free_result)
796 {
797 bool follow_spec = php_dom_follow_spec_intern(intern);
798 if (follow_spec && uri_len == 0) {
799 uri = NULL;
800 }
801
802 xmlChar *strattr = xmlGetNsProp(elemp, BAD_CAST name, BAD_CAST uri);
803
804 if (strattr != NULL) {
805 *should_free_result = true;
806 return strattr;
807 } else {
808 if (!follow_spec && xmlStrEqual(BAD_CAST uri, BAD_CAST DOM_XMLNS_NS_URI)) {
809 xmlNsPtr nsptr = dom_get_nsdecl(elemp, BAD_CAST name);
810 if (nsptr != NULL) {
811 return nsptr->href;
812 } else {
813 return NULL;
814 }
815 } else {
816 return NULL;
817 }
818 }
819 }
820
821 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElGetAttrNS
822 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-getattributens
823 Since: DOM Level 2
824 */
PHP_METHOD(DOMElement,getAttributeNS)825 PHP_METHOD(DOMElement, getAttributeNS)
826 {
827 zval *id;
828 xmlNodePtr elemp;
829 dom_object *intern;
830 size_t uri_len = 0, name_len = 0;
831 char *uri, *name;
832
833 id = ZEND_THIS;
834 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
835 RETURN_THROWS();
836 }
837
838 DOM_GET_OBJ(elemp, id, xmlNodePtr, intern);
839
840 bool should_free_result = false;
841 const xmlChar *result = dom_get_attribute_ns(intern, elemp, uri, uri_len, name, &should_free_result);
842 if (result == NULL) {
843 if (php_dom_follow_spec_intern(intern)) {
844 RETURN_NULL();
845 }
846 RETURN_EMPTY_STRING();
847 } else {
848 RETVAL_STRING((const char *) result);
849 if (should_free_result) {
850 xmlFree(BAD_CAST result);
851 }
852 }
853 }
854 /* }}} end dom_element_get_attribute_ns */
855
dom_set_attribute_ns_legacy(dom_object * intern,xmlNodePtr elemp,char * uri,size_t uri_len,char * name,size_t name_len,const char * value)856 static void dom_set_attribute_ns_legacy(dom_object *intern, xmlNodePtr elemp, char *uri, size_t uri_len, char *name, size_t name_len, const char *value)
857 {
858 if (name_len == 0) {
859 zend_argument_value_error(2, "cannot be empty");
860 return;
861 }
862
863 xmlNodePtr nodep = NULL;
864 xmlNsPtr nsptr;
865 xmlAttr *attr;
866 char *localname = NULL, *prefix = NULL;
867 int is_xmlns = 0, name_valid;
868 bool stricterror = dom_get_strict_error(intern->document);
869
870 int errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
871
872 if (errorcode == 0) {
873 if (uri_len > 0) {
874 nodep = (xmlNodePtr) xmlHasNsProp(elemp, BAD_CAST localname, BAD_CAST uri);
875 if (nodep != NULL && nodep->type != XML_ATTRIBUTE_DECL) {
876 node_list_unlink(nodep->children);
877 }
878
879 if ((xmlStrEqual(BAD_CAST prefix, BAD_CAST "xmlns") ||
880 (prefix == NULL && xmlStrEqual(BAD_CAST localname, BAD_CAST "xmlns"))) &&
881 xmlStrEqual(BAD_CAST uri, BAD_CAST DOM_XMLNS_NS_URI)) {
882 is_xmlns = 1;
883 if (prefix == NULL) {
884 nsptr = dom_get_nsdecl(elemp, NULL);
885 } else {
886 nsptr = dom_get_nsdecl(elemp, BAD_CAST localname);
887 }
888 } else {
889 nsptr = xmlSearchNsByHref(elemp->doc, elemp, BAD_CAST uri);
890 if (nsptr && nsptr->prefix == NULL) {
891 xmlNsPtr tmpnsptr;
892
893 tmpnsptr = nsptr->next;
894 while (tmpnsptr) {
895 if ((tmpnsptr->prefix != NULL) && (tmpnsptr->href != NULL) &&
896 (xmlStrEqual(tmpnsptr->href, BAD_CAST uri))) {
897 nsptr = tmpnsptr;
898 break;
899 }
900 tmpnsptr = tmpnsptr->next;
901 }
902 if (tmpnsptr == NULL) {
903 nsptr = dom_get_ns_resolve_prefix_conflict(elemp, (const char *) nsptr->href);
904 }
905 }
906 }
907
908 if (nsptr == NULL) {
909 if (is_xmlns == 1) {
910 xmlNewNs(elemp, BAD_CAST value, prefix == NULL ? NULL : BAD_CAST localname);
911 } else {
912 nsptr = dom_get_ns(elemp, uri, &errorcode, prefix);
913 }
914 xmlReconciliateNs(elemp->doc, elemp);
915 } else {
916 if (is_xmlns == 1) {
917 if (nsptr->href) {
918 xmlFree(BAD_CAST nsptr->href);
919 }
920 nsptr->href = xmlStrdup(BAD_CAST value);
921 }
922 }
923
924 if (errorcode == 0 && is_xmlns == 0) {
925 xmlSetNsProp(elemp, nsptr, BAD_CAST localname, BAD_CAST value);
926 }
927 } else {
928 name_valid = xmlValidateName(BAD_CAST localname, 0);
929 if (name_valid != 0) {
930 errorcode = INVALID_CHARACTER_ERR;
931 stricterror = 1;
932 } else {
933 attr = xmlHasProp(elemp, BAD_CAST localname);
934 if (attr != NULL && attr->type != XML_ATTRIBUTE_DECL) {
935 node_list_unlink(attr->children);
936 }
937 xmlSetProp(elemp, BAD_CAST localname, BAD_CAST value);
938 }
939 }
940 }
941
942 xmlFree(localname);
943 if (prefix != NULL) {
944 xmlFree(prefix);
945 }
946
947 if (errorcode != 0) {
948 php_dom_throw_error(errorcode, stricterror);
949 }
950 }
951
952 /* https://dom.spec.whatwg.org/#dom-element-setattributens */
dom_set_attribute_ns_modern(dom_object * intern,xmlNodePtr elemp,zend_string * uri,const zend_string * name,const char * value)953 static void dom_set_attribute_ns_modern(dom_object *intern, xmlNodePtr elemp, zend_string *uri, const zend_string *name, const char *value)
954 {
955 xmlChar *localname = NULL, *prefix = NULL;
956 int errorcode = dom_validate_and_extract(uri, name, &localname, &prefix);
957
958 if (errorcode == 0) {
959 php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern);
960 xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), uri);
961 if (UNEXPECTED(xmlSetNsProp(elemp, ns, localname, BAD_CAST value) == NULL)) {
962 php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
963 }
964 } else {
965 php_dom_throw_error(errorcode, /* strict */ true);
966 }
967
968 xmlFree(localname);
969 xmlFree(prefix);
970 }
971
972 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElSetAttrNS
973 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-setattributens
974 Since: DOM Level 2
975 */
PHP_METHOD(DOMElement,setAttributeNS)976 PHP_METHOD(DOMElement, setAttributeNS)
977 {
978 zval *id;
979 xmlNodePtr elemp;
980 size_t value_len = 0;
981 char *value;
982 zend_string *uri;
983 zend_string *name = NULL;
984 dom_object *intern;
985
986 id = ZEND_THIS;
987 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!Ss", &uri, &name, &value, &value_len) == FAILURE) {
988 RETURN_THROWS();
989 }
990
991 DOM_GET_OBJ(elemp, id, xmlNodePtr, intern);
992
993 if (php_dom_follow_spec_intern(intern)) {
994 dom_set_attribute_ns_modern(intern, elemp, uri, name, value);
995 } else {
996 dom_set_attribute_ns_legacy(intern, elemp, uri ? ZSTR_VAL(uri) : NULL, uri ? ZSTR_LEN(uri) : 0, ZSTR_VAL(name), ZSTR_LEN(name), value);
997 }
998 }
999 /* }}} end dom_element_set_attribute_ns */
1000
dom_remove_eliminated_ns_single_element(xmlNodePtr node,xmlNsPtr eliminatedNs)1001 static void dom_remove_eliminated_ns_single_element(xmlNodePtr node, xmlNsPtr eliminatedNs)
1002 {
1003 ZEND_ASSERT(node->type == XML_ELEMENT_NODE);
1004 if (node->ns == eliminatedNs) {
1005 node->ns = NULL;
1006 }
1007
1008 for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
1009 if (attr->ns == eliminatedNs) {
1010 attr->ns = NULL;
1011 }
1012 }
1013 }
1014
dom_remove_eliminated_ns(xmlNodePtr node,xmlNsPtr eliminatedNs)1015 static void dom_remove_eliminated_ns(xmlNodePtr node, xmlNsPtr eliminatedNs)
1016 {
1017 dom_remove_eliminated_ns_single_element(node, eliminatedNs);
1018
1019 xmlNodePtr base = node;
1020 node = node->children;
1021 while (node != NULL) {
1022 ZEND_ASSERT(node != base);
1023
1024 if (node->type == XML_ELEMENT_NODE) {
1025 dom_remove_eliminated_ns_single_element(node, eliminatedNs);
1026
1027 if (node->children) {
1028 node = node->children;
1029 continue;
1030 }
1031 }
1032
1033 node = php_dom_next_in_tree_order(node, base);
1034 }
1035 }
1036
dom_eliminate_ns(xmlNodePtr nodep,xmlNsPtr nsptr)1037 static void dom_eliminate_ns(xmlNodePtr nodep, xmlNsPtr nsptr)
1038 {
1039 if (nsptr->href != NULL) {
1040 xmlFree((char *) nsptr->href);
1041 nsptr->href = NULL;
1042 }
1043 if (nsptr->prefix != NULL) {
1044 xmlFree((char *) nsptr->prefix);
1045 nsptr->prefix = NULL;
1046 }
1047
1048 /* Remove it from the list and move it to the old ns list */
1049 xmlNsPtr current_ns = nodep->nsDef;
1050 if (current_ns == nsptr) {
1051 nodep->nsDef = nsptr->next;
1052 } else {
1053 do {
1054 if (current_ns->next == nsptr) {
1055 current_ns->next = nsptr->next;
1056 break;
1057 }
1058 current_ns = current_ns->next;
1059 } while (current_ns != NULL);
1060 }
1061 nsptr->next = NULL;
1062 php_libxml_set_old_ns(nodep->doc, nsptr);
1063
1064 dom_remove_eliminated_ns(nodep, nsptr);
1065 }
1066
1067 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElRemAtNS
1068 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-removeattributens
1069 Since: DOM Level 2
1070 */
PHP_METHOD(DOMElement,removeAttributeNS)1071 PHP_METHOD(DOMElement, removeAttributeNS)
1072 {
1073 zval *id;
1074 xmlNode *nodep;
1075 xmlAttr *attrp;
1076 xmlNsPtr nsptr;
1077 dom_object *intern;
1078 size_t name_len, uri_len;
1079 char *name, *uri;
1080
1081 id = ZEND_THIS;
1082 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
1083 RETURN_THROWS();
1084 }
1085
1086 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1087
1088 bool follow_spec = php_dom_follow_spec_intern(intern);
1089 if (follow_spec && uri_len == 0) {
1090 uri = NULL;
1091 }
1092
1093 attrp = xmlHasNsProp(nodep, BAD_CAST name, BAD_CAST uri);
1094
1095 if (!follow_spec) {
1096 nsptr = dom_get_nsdecl(nodep, BAD_CAST name);
1097 if (nsptr != NULL) {
1098 if (xmlStrEqual(BAD_CAST uri, nsptr->href)) {
1099 dom_eliminate_ns(nodep, nsptr);
1100 } else {
1101 return;
1102 }
1103 }
1104 }
1105
1106 if (attrp && attrp->type != XML_ATTRIBUTE_DECL) {
1107 if (php_dom_object_get_data((xmlNodePtr) attrp) == NULL) {
1108 node_list_unlink(attrp->children);
1109 xmlUnlinkNode((xmlNodePtr) attrp);
1110 xmlFreeProp(attrp);
1111 } else {
1112 xmlUnlinkNode((xmlNodePtr) attrp);
1113 }
1114 }
1115 }
1116 /* }}} end dom_element_remove_attribute_ns */
1117
1118 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElGetAtNodeNS
1119 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-getattributenodens
1120 Since: DOM Level 2
1121 */
PHP_METHOD(DOMElement,getAttributeNodeNS)1122 PHP_METHOD(DOMElement, getAttributeNodeNS)
1123 {
1124 zval *id;
1125 xmlNodePtr elemp;
1126 xmlAttrPtr attrp;
1127 dom_object *intern;
1128 size_t uri_len, name_len;
1129 char *uri, *name;
1130
1131 id = ZEND_THIS;
1132 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
1133 RETURN_THROWS();
1134 }
1135
1136 DOM_GET_OBJ(elemp, id, xmlNodePtr, intern);
1137
1138 bool follow_spec = php_dom_follow_spec_intern(intern);
1139 if (follow_spec && uri_len == 0) {
1140 uri = NULL;
1141 }
1142
1143 attrp = xmlHasNsProp(elemp, BAD_CAST name, BAD_CAST uri);
1144
1145 if (attrp == NULL) {
1146 if (!follow_spec && xmlStrEqual(BAD_CAST uri, BAD_CAST DOM_XMLNS_NS_URI)) {
1147 xmlNsPtr nsptr;
1148 nsptr = dom_get_nsdecl(elemp, BAD_CAST name);
1149 if (nsptr != NULL) {
1150 /* Keep parent alive, because we're a fake child. */
1151 GC_ADDREF(&intern->std);
1152 (void) php_dom_create_fake_namespace_decl(elemp, nsptr, return_value, intern);
1153 } else {
1154 RETURN_NULL();
1155 }
1156 } else {
1157 RETURN_NULL();
1158 }
1159 } else {
1160 DOM_RET_OBJ((xmlNodePtr) attrp, intern);
1161 }
1162
1163 }
1164 /* }}} end dom_element_get_attribute_node_ns */
1165
1166 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElSetAtNodeNS
1167 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-setattributenodens
1168 Since: DOM Level 2
1169 */
PHP_METHOD(DOMElement,setAttributeNodeNS)1170 PHP_METHOD(DOMElement, setAttributeNodeNS)
1171 {
1172 dom_element_set_attribute_node_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, /* use_ns */ true, /* modern */ false);
1173 }
1174
PHP_METHOD(DOM_Element,setAttributeNodeNS)1175 PHP_METHOD(DOM_Element, setAttributeNodeNS)
1176 {
1177 dom_element_set_attribute_node_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, /* use_ns */ true, /* modern */ true);
1178 }
1179 /* }}} end dom_element_set_attribute_node_ns */
1180
1181 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-A6C90942
1182 Modern spec URL: https://dom.spec.whatwg.org/#concept-getelementsbytagnamens
1183 Since: DOM Level 2
1184 */
dom_element_get_elements_by_tag_name_ns(INTERNAL_FUNCTION_PARAMETERS,bool modern)1185 static void dom_element_get_elements_by_tag_name_ns(INTERNAL_FUNCTION_PARAMETERS, bool modern)
1186 {
1187 size_t uri_len, name_len;
1188 dom_object *intern, *namednode;
1189 char *uri, *name;
1190
1191 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
1192 RETURN_THROWS();
1193 }
1194
1195 DOM_GET_THIS_INTERN(intern);
1196
1197 if (modern) {
1198 php_dom_create_iterator(return_value, DOM_HTMLCOLLECTION, true);
1199 } else {
1200 php_dom_create_iterator(return_value, DOM_NODELIST, false);
1201 }
1202 namednode = Z_DOMOBJ_P(return_value);
1203 dom_namednode_iter(intern, 0, namednode, NULL, name, name_len, uri ? uri : "", uri_len);
1204 }
1205
PHP_METHOD(DOMElement,getElementsByTagNameNS)1206 PHP_METHOD(DOMElement, getElementsByTagNameNS)
1207 {
1208 dom_element_get_elements_by_tag_name_ns(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
1209 }
1210
PHP_METHOD(DOM_Element,getElementsByTagNameNS)1211 PHP_METHOD(DOM_Element, getElementsByTagNameNS)
1212 {
1213 dom_element_get_elements_by_tag_name_ns(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
1214 }
1215 /* }}} end dom_element_get_elements_by_tag_name_ns */
1216
1217 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElHasAttr
1218 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-hasattribute
1219 Since: DOM Level 2
1220 */
PHP_METHOD(DOMElement,hasAttribute)1221 PHP_METHOD(DOMElement, hasAttribute)
1222 {
1223 zval *id;
1224 xmlNode *nodep;
1225 dom_object *intern;
1226 char *name;
1227 size_t name_len;
1228 xmlNodePtr attr;
1229
1230 id = ZEND_THIS;
1231 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
1232 RETURN_THROWS();
1233 }
1234
1235 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1236
1237 attr = dom_get_attribute_or_nsdecl(intern, nodep, BAD_CAST name, name_len);
1238 if (attr == NULL) {
1239 RETURN_FALSE;
1240 } else {
1241 RETURN_TRUE;
1242 }
1243 }
1244 /* }}} end dom_element_has_attribute */
1245
1246 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElHasAttrNS
1247 Modern spec URL: https://dom.spec.whatwg.org/#dom-element-hasattributens
1248 Since: DOM Level 2
1249 */
PHP_METHOD(DOMElement,hasAttributeNS)1250 PHP_METHOD(DOMElement, hasAttributeNS)
1251 {
1252 zval *id;
1253 xmlNodePtr elemp;
1254 dom_object *intern;
1255 size_t uri_len, name_len;
1256 char *uri, *name;
1257
1258 id = ZEND_THIS;
1259 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) {
1260 RETURN_THROWS();
1261 }
1262
1263 DOM_GET_OBJ(elemp, id, xmlNodePtr, intern);
1264
1265 bool should_free_result = false;
1266 const xmlChar *result = dom_get_attribute_ns(intern, elemp, uri, uri_len, name, &should_free_result);
1267 if (result == NULL) {
1268 RETURN_FALSE;
1269 } else {
1270 if (should_free_result) {
1271 xmlFree(BAD_CAST result);
1272 }
1273 RETURN_TRUE;
1274 }
1275 }
1276 /* }}} end dom_element_has_attribute_ns */
1277
php_set_attribute_id(xmlAttrPtr attrp,bool is_id)1278 static void php_set_attribute_id(xmlAttrPtr attrp, bool is_id) /* {{{ */
1279 {
1280 if (is_id == 1 && attrp->atype != XML_ATTRIBUTE_ID) {
1281 xmlChar *id_val;
1282
1283 id_val = xmlNodeListGetString(attrp->doc, attrp->children, 1);
1284 if (id_val != NULL) {
1285 xmlAddID(NULL, attrp->doc, id_val, attrp);
1286 xmlFree(id_val);
1287 }
1288 } else if (is_id == 0 && attrp->atype == XML_ATTRIBUTE_ID) {
1289 xmlRemoveID(attrp->doc, attrp);
1290 attrp->atype = 0;
1291 }
1292 }
1293 /* }}} */
1294
1295 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElSetIdAttr
1296 Since: DOM Level 3
1297 */
PHP_METHOD(DOMElement,setIdAttribute)1298 PHP_METHOD(DOMElement, setIdAttribute)
1299 {
1300 zval *id;
1301 xmlNode *nodep;
1302 xmlAttrPtr attrp;
1303 dom_object *intern;
1304 char *name;
1305 size_t name_len;
1306 bool is_id;
1307
1308 id = ZEND_THIS;
1309 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sb", &name, &name_len, &is_id) == FAILURE) {
1310 RETURN_THROWS();
1311 }
1312
1313 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1314
1315 attrp = xmlHasNsProp(nodep, BAD_CAST name, NULL);
1316 if (attrp == NULL || attrp->type == XML_ATTRIBUTE_DECL) {
1317 php_dom_throw_error(NOT_FOUND_ERR, dom_get_strict_error(intern->document));
1318 } else {
1319 php_set_attribute_id(attrp, is_id);
1320 }
1321
1322 RETURN_NULL();
1323 }
1324 /* }}} end dom_element_set_id_attribute */
1325
1326 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElSetIdAttrNS
1327 Since: DOM Level 3
1328 */
PHP_METHOD(DOMElement,setIdAttributeNS)1329 PHP_METHOD(DOMElement, setIdAttributeNS)
1330 {
1331 zval *id;
1332 xmlNodePtr elemp;
1333 xmlAttrPtr attrp;
1334 dom_object *intern;
1335 size_t uri_len, name_len;
1336 char *uri, *name;
1337 bool is_id;
1338
1339 id = ZEND_THIS;
1340 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssb", &uri, &uri_len, &name, &name_len, &is_id) == FAILURE) {
1341 RETURN_THROWS();
1342 }
1343
1344 DOM_GET_OBJ(elemp, id, xmlNodePtr, intern);
1345
1346 attrp = xmlHasNsProp(elemp, BAD_CAST name, BAD_CAST uri);
1347 if (attrp == NULL || attrp->type == XML_ATTRIBUTE_DECL) {
1348 php_dom_throw_error(NOT_FOUND_ERR, dom_get_strict_error(intern->document));
1349 } else {
1350 php_set_attribute_id(attrp, is_id);
1351 }
1352
1353 RETURN_NULL();
1354 }
1355 /* }}} end dom_element_set_id_attribute_ns */
1356
1357 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElSetIdAttrNode
1358 Since: DOM Level 3
1359 */
dom_element_set_id_attribute_node(INTERNAL_FUNCTION_PARAMETERS,zend_class_entry * attr_ce)1360 static void dom_element_set_id_attribute_node(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *attr_ce)
1361 {
1362 zval *id, *node;
1363 xmlNode *nodep;
1364 xmlAttrPtr attrp;
1365 dom_object *intern, *attrobj;
1366 bool is_id;
1367
1368 id = ZEND_THIS;
1369 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &node, attr_ce, &is_id) != SUCCESS) {
1370 RETURN_THROWS();
1371 }
1372
1373 DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
1374 DOM_GET_OBJ(attrp, node, xmlAttrPtr, attrobj);
1375
1376 if (attrp->parent != nodep) {
1377 php_dom_throw_error(NOT_FOUND_ERR, dom_get_strict_error(intern->document));
1378 } else {
1379 php_set_attribute_id(attrp, is_id);
1380 }
1381
1382 RETURN_NULL();
1383 }
1384
PHP_METHOD(DOMElement,setIdAttributeNode)1385 PHP_METHOD(DOMElement, setIdAttributeNode)
1386 {
1387 dom_element_set_id_attribute_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_attr_class_entry);
1388 }
1389
PHP_METHOD(DOM_Element,setIdAttributeNode)1390 PHP_METHOD(DOM_Element, setIdAttributeNode)
1391 {
1392 dom_element_set_id_attribute_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_modern_attr_class_entry);
1393 }
1394 /* }}} end dom_element_set_id_attribute_node */
1395
1396 /* {{{ URL:
1397 Since:
1398 */
PHP_METHOD(DOMElement,remove)1399 PHP_METHOD(DOMElement, remove)
1400 {
1401 dom_object *intern;
1402
1403 if (zend_parse_parameters_none() == FAILURE) {
1404 RETURN_THROWS();
1405 }
1406
1407 DOM_GET_THIS_INTERN(intern);
1408
1409 dom_child_node_remove(intern);
1410 }
1411 /* }}} end DOMElement::remove */
1412
PHP_METHOD(DOMElement,after)1413 PHP_METHOD(DOMElement, after)
1414 {
1415 uint32_t argc = 0;
1416 zval *args;
1417 dom_object *intern;
1418
1419 if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &args, &argc) == FAILURE) {
1420 RETURN_THROWS();
1421 }
1422
1423 DOM_GET_THIS_INTERN(intern);
1424
1425 dom_parent_node_after(intern, args, argc);
1426 }
1427
PHP_METHOD(DOMElement,before)1428 PHP_METHOD(DOMElement, before)
1429 {
1430 uint32_t argc = 0;
1431 zval *args;
1432 dom_object *intern;
1433
1434 if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &args, &argc) == FAILURE) {
1435 RETURN_THROWS();
1436 }
1437
1438 DOM_GET_THIS_INTERN(intern);
1439
1440 dom_parent_node_before(intern, args, argc);
1441 }
1442
1443 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-append
1444 Since: DOM Living Standard (DOM4)
1445 */
PHP_METHOD(DOMElement,append)1446 PHP_METHOD(DOMElement, append)
1447 {
1448 uint32_t argc = 0;
1449 zval *args;
1450 dom_object *intern;
1451
1452 if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &args, &argc) == FAILURE) {
1453 RETURN_THROWS();
1454 }
1455
1456 DOM_GET_THIS_INTERN(intern);
1457
1458 dom_parent_node_append(intern, args, argc);
1459 }
1460 /* }}} end DOMElement::append */
1461
1462 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
1463 Since: DOM Living Standard (DOM4)
1464 */
PHP_METHOD(DOMElement,prepend)1465 PHP_METHOD(DOMElement, prepend)
1466 {
1467 uint32_t argc = 0;
1468 zval *args;
1469 dom_object *intern;
1470
1471 if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &args, &argc) == FAILURE) {
1472 RETURN_THROWS();
1473 }
1474
1475 DOM_GET_THIS_INTERN(intern);
1476
1477 dom_parent_node_prepend(intern, args, argc);
1478 }
1479 /* }}} end DOMElement::prepend */
1480
1481 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-replacechildren
1482 Since: DOM Living Standard (DOM4)
1483 */
PHP_METHOD(DOMElement,replaceWith)1484 PHP_METHOD(DOMElement, replaceWith)
1485 {
1486 uint32_t argc = 0;
1487 zval *args;
1488 dom_object *intern;
1489
1490 if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &args, &argc) == FAILURE) {
1491 RETURN_THROWS();
1492 }
1493
1494 DOM_GET_THIS_INTERN(intern);
1495
1496 dom_child_replace_with(intern, args, argc);
1497 }
1498 /* }}} end DOMElement::prepend */
1499
1500 /* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-replacechildren
1501 Since:
1502 */
PHP_METHOD(DOMElement,replaceChildren)1503 PHP_METHOD(DOMElement, replaceChildren)
1504 {
1505 uint32_t argc = 0;
1506 zval *args;
1507 dom_object *intern;
1508
1509 if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &args, &argc) == FAILURE) {
1510 RETURN_THROWS();
1511 }
1512
1513 DOM_GET_THIS_INTERN(intern);
1514
1515 dom_parent_node_replace_children(intern, args, argc);
1516 }
1517 /* }}} */
1518
1519 #define INSERT_ADJACENT_RES_ADOPT_FAILED ((void*) -1)
1520 #define INSERT_ADJACENT_RES_SYNTAX_FAILED INSERT_ADJACENT_RES_ADOPT_FAILED
1521 #define INSERT_ADJACENT_RES_PRE_INSERT_FAILED ((void*) -2)
1522
dom_insert_adjacent(const zend_string * where,xmlNodePtr thisp,dom_object * this_intern,xmlNodePtr otherp)1523 static xmlNodePtr dom_insert_adjacent(const zend_string *where, xmlNodePtr thisp, dom_object *this_intern, xmlNodePtr otherp)
1524 {
1525 if (zend_string_equals_literal_ci(where, "beforebegin")) {
1526 if (thisp->parent == NULL) {
1527 return NULL;
1528 }
1529 if (!php_dom_adopt_node(otherp, this_intern, thisp->doc)) {
1530 return INSERT_ADJACENT_RES_ADOPT_FAILED;
1531 }
1532 if (!php_dom_pre_insert(this_intern->document, otherp, thisp->parent, thisp)) {
1533 return INSERT_ADJACENT_RES_PRE_INSERT_FAILED;
1534 }
1535 } else if (zend_string_equals_literal_ci(where, "afterbegin")) {
1536 if (!php_dom_adopt_node(otherp, this_intern, thisp->doc)) {
1537 return INSERT_ADJACENT_RES_ADOPT_FAILED;
1538 }
1539 if (!php_dom_pre_insert(this_intern->document, otherp, thisp, thisp->children)) {
1540 return INSERT_ADJACENT_RES_PRE_INSERT_FAILED;
1541 }
1542 } else if (zend_string_equals_literal_ci(where, "beforeend")) {
1543 if (!php_dom_adopt_node(otherp, this_intern, thisp->doc)) {
1544 return INSERT_ADJACENT_RES_ADOPT_FAILED;
1545 }
1546 if (!php_dom_pre_insert(this_intern->document, otherp, thisp, NULL)) {
1547 return INSERT_ADJACENT_RES_PRE_INSERT_FAILED;
1548 }
1549 } else if (zend_string_equals_literal_ci(where, "afterend")) {
1550 if (thisp->parent == NULL) {
1551 return NULL;
1552 }
1553 if (!php_dom_adopt_node(otherp, this_intern, thisp->doc)) {
1554 return INSERT_ADJACENT_RES_ADOPT_FAILED;
1555 }
1556 if (!php_dom_pre_insert(this_intern->document, otherp, thisp->parent, thisp->next)) {
1557 return INSERT_ADJACENT_RES_PRE_INSERT_FAILED;
1558 }
1559 } else {
1560 php_dom_throw_error(SYNTAX_ERR, dom_get_strict_error(this_intern->document));
1561 return INSERT_ADJACENT_RES_SYNTAX_FAILED;
1562 }
1563 return otherp;
1564 }
1565
1566 /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-insertadjacentelement
1567 Since:
1568 */
dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAMETERS,zend_class_entry * element_ce)1569 static void dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *element_ce)
1570 {
1571 zend_string *where;
1572 zval *element_zval, *id;
1573 xmlNodePtr thisp, otherp;
1574 dom_object *this_intern, *other_intern;
1575
1576 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SO", &where, &element_zval, element_ce) != SUCCESS) {
1577 RETURN_THROWS();
1578 }
1579
1580 DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, this_intern);
1581 DOM_GET_OBJ(otherp, element_zval, xmlNodePtr, other_intern);
1582
1583 xmlNodePtr result = dom_insert_adjacent(where, thisp, this_intern, otherp);
1584 if (result == NULL) {
1585 RETURN_NULL();
1586 } else if (result != INSERT_ADJACENT_RES_ADOPT_FAILED && result != INSERT_ADJACENT_RES_PRE_INSERT_FAILED) {
1587 DOM_RET_OBJ(otherp, other_intern);
1588 } else {
1589 RETURN_THROWS();
1590 }
1591 }
1592
PHP_METHOD(DOMElement,insertAdjacentElement)1593 PHP_METHOD(DOMElement, insertAdjacentElement)
1594 {
1595 dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_element_class_entry);
1596 }
1597
PHP_METHOD(DOM_Element,insertAdjacentElement)1598 PHP_METHOD(DOM_Element, insertAdjacentElement)
1599 {
1600 dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAM_PASSTHRU, dom_modern_element_class_entry);
1601 }
1602 /* }}} end DOMElement::insertAdjacentElement */
1603
1604 /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-insertadjacenttext
1605 Since:
1606 */
PHP_METHOD(DOMElement,insertAdjacentText)1607 PHP_METHOD(DOMElement, insertAdjacentText)
1608 {
1609 zend_string *where, *data;
1610 dom_object *this_intern;
1611 zval *id;
1612 xmlNodePtr thisp;
1613
1614 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &where, &data) == FAILURE) {
1615 RETURN_THROWS();
1616 }
1617
1618 DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, this_intern);
1619
1620 if (UNEXPECTED(ZEND_SIZE_T_INT_OVFL(ZSTR_LEN(data)))) {
1621 zend_argument_value_error(2, "is too long");
1622 RETURN_THROWS();
1623 }
1624
1625 xmlNodePtr otherp = xmlNewDocTextLen(thisp->doc, (const xmlChar *) ZSTR_VAL(data), ZSTR_LEN(data));
1626 xmlNodePtr result = dom_insert_adjacent(where, thisp, this_intern, otherp);
1627 if (result == NULL || result == INSERT_ADJACENT_RES_ADOPT_FAILED) {
1628 xmlFreeNode(otherp);
1629 }
1630 }
1631 /* }}} end DOMElement::insertAdjacentText */
1632
1633 /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-toggleattribute
1634 Since:
1635 */
PHP_METHOD(DOMElement,toggleAttribute)1636 PHP_METHOD(DOMElement, toggleAttribute)
1637 {
1638 char *qname, *qname_tmp = NULL;
1639 size_t qname_length;
1640 bool force, force_is_null = true;
1641 xmlNodePtr thisp;
1642 zval *id;
1643 dom_object *intern;
1644 bool retval;
1645
1646 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b!", &qname, &qname_length, &force, &force_is_null) == FAILURE) {
1647 RETURN_THROWS();
1648 }
1649
1650 DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, intern);
1651
1652 /* Step 1 */
1653 if (xmlValidateName(BAD_CAST qname, 0) != 0) {
1654 php_dom_throw_error(INVALID_CHARACTER_ERR, true);
1655 RETURN_THROWS();
1656 }
1657
1658 bool follow_spec = php_dom_follow_spec_intern(intern);
1659
1660 /* Step 2 */
1661 if (thisp->doc != NULL && thisp->doc->type == XML_HTML_DOCUMENT_NODE
1662 && ((!follow_spec && thisp->ns == NULL) || (thisp->ns != NULL && xmlStrEqual(thisp->ns->href, BAD_CAST DOM_XHTML_NS_URI)))) {
1663 qname_tmp = zend_str_tolower_dup_ex(qname, qname_length);
1664 if (qname_tmp != NULL) {
1665 qname = qname_tmp;
1666 }
1667 }
1668
1669 /* Step 3 */
1670 xmlNodePtr attribute = dom_get_attribute_or_nsdecl(intern, thisp, BAD_CAST qname, qname_length);
1671
1672 /* Step 4 */
1673 if (attribute == NULL) {
1674 /* Step 4.1 */
1675 if (force_is_null || force) {
1676 if (follow_spec) {
1677 xmlSetNsProp(thisp, NULL, BAD_CAST qname, NULL);
1678 } else {
1679 /* The behaviour for namespaces isn't defined by spec, but this is based on observing browers behaviour.
1680 * It follows the same rules when you'd manually add an attribute using the other APIs. */
1681 int len;
1682 const xmlChar *split = xmlSplitQName3((const xmlChar *) qname, &len);
1683 if (split == NULL || strncmp(qname, "xmlns:", len + 1 /* +1 for matching ':' too */) != 0) {
1684 /* unqualified name, or qualified name with no xml namespace declaration */
1685 dom_create_attribute(thisp, qname, "");
1686 } else {
1687 /* qualified name with xml namespace declaration */
1688 xmlNewNs(thisp, (const xmlChar *) "", (const xmlChar *) (qname + len + 1));
1689 }
1690 }
1691 retval = true;
1692 goto out;
1693 }
1694 /* Step 4.2 */
1695 retval = false;
1696 goto out;
1697 }
1698
1699 /* Step 5 */
1700 if (force_is_null || !force) {
1701 dom_remove_attribute(thisp, attribute);
1702 retval = false;
1703 goto out;
1704 }
1705
1706 /* Step 6 */
1707 retval = true;
1708
1709 out:
1710 if (qname_tmp) {
1711 efree(qname_tmp);
1712 }
1713 RETURN_BOOL(retval);
1714 }
1715 /* }}} end DOMElement::prepend */
1716
1717 #endif
1718