From 6f08cda1b9493f6e99bc66dc1673b9f8443e63a1 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:10:55 +0200 Subject: [PATCH 1/5] Add regression tests --- ...ent_createAttributeNS_prefix_conflict.phpt | 56 ++++++++++++++++ ..._importNode_attribute_prefix_conflict.phpt | 65 +++++++++++++++++++ ...lement_setAttributeNS_prefix_conflict.phpt | 32 +++++++++ 3 files changed, 153 insertions(+) create mode 100644 ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt create mode 100644 ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt create mode 100644 ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt diff --git a/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt b/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt new file mode 100644 index 0000000000000..e06da45fd051e --- /dev/null +++ b/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt @@ -0,0 +1,56 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +echo "--- setAttributeNode variation (you shouldn't do this, but we test this anyway) ---\n"; + +// Adheres to DOM Core Level 3 + +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns2', 'hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns3', 'hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns4', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns2', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns3', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns4', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +$doc = new DOMDocument(); +$doc->appendChild($doc->createElement('container')); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +echo "--- setAttributeNodeNS variation ---\n"; + +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns2', 'hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns3', 'hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns4', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns2', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns3', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns4', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECTF-- +--- setAttributeNode variation (you shouldn't do this, but we test this anyway) --- +NULL + +Fatal error: Uncaught DOMException: Namespace Error in %s:%d +Stack trace: +#0 %s(%d): DOMDocument->createAttributeNS('http://php.net/...', 'hello') +#1 {main} + thrown in %s on line %d diff --git a/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt b/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt new file mode 100644 index 0000000000000..54de02ceac226 --- /dev/null +++ b/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt @@ -0,0 +1,65 @@ +--TEST-- +DOMDocument::importNode() with attribute prefix name conflict +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); +$dom2->loadXML(''); +$attribute = $dom1->documentElement->getAttributeNode('foo:bar'); +$imported = $dom2->importNode($attribute); +$dom2->documentElement->setAttributeNodeNS($imported); + +echo $dom1->saveXML(); +echo $dom2->saveXML(); + +echo "--- Non-default namespace test case with a default namespace in the destination ---\n"; + +$dom1 = new DOMDocument(); +$dom2 = new DOMDocument(); +$dom1->loadXML(''); +$dom2->loadXML(''); +$attribute = $dom1->documentElement->getAttributeNode('foo:bar'); +$imported = $dom2->importNode($attribute); +$dom2->documentElement->setAttributeNodeNS($imported); + +echo $dom1->saveXML(); +echo $dom2->saveXML(); + +echo "--- Default namespace test case ---\n"; + +// We don't expect the namespace to be imported because default namespaces on the same element don't apply to attributes +// but the attribute should be imported +$dom1 = new DOMDocument(); +$dom2 = new DOMDocument(); +$dom1->loadXML(''); +$dom2->loadXML(''); +$attribute = $dom1->documentElement->getAttributeNode('bar'); +$imported = $dom2->importNode($attribute); +$dom2->documentElement->setAttributeNodeNS($imported); + +echo $dom1->saveXML(); +echo $dom2->saveXML(); + +?> +--EXPECT-- +--- Non-default namespace test case without a default namespace in the destination --- + + + + +--- Non-default namespace test case with a default namespace in the destination --- + + + + +--- Default namespace test case --- + + + + diff --git a/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt b/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt new file mode 100644 index 0000000000000..f79a13cc11593 --- /dev/null +++ b/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt @@ -0,0 +1,32 @@ +--TEST-- +DOMElement::setAttributeNS() with prefix name conflict +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); +$dom->documentElement->setAttributeNS('http://php.net/2', 'foo:bar', 'no1'); +echo $dom->saveXML(); +$dom->documentElement->setAttributeNS('http://php.net/2', 'bar', 'no2'); +echo $dom->saveXML(); + +echo "--- Default namespace test case ---\n"; + +$dom = new DOMDocument(); +$dom->loadXML(''); +$dom->documentElement->setAttributeNS('http://php.net/2', 'bar', 'no1'); +echo $dom->saveXML(); +$dom->documentElement->setAttributeNS('http://php.net/2', 'bar', 'no2'); +echo $dom->saveXML(); +?> +--EXPECTF-- +--- Non-default namespace test case --- + +Fatal error: Uncaught DOMException: Namespace Error in %s:%d +Stack trace: +#0 %s(%d): DOMElement->setAttributeNS('http://php.net/...', 'foo:bar', 'no1') +#1 {main} + thrown in %s on line %d From 8965426a99a3c5c14e216ea8c3a3b05530082086 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:11:58 +0200 Subject: [PATCH 2/5] Fix various namespace prefix conflict resolution bugs The output could still be improved by removing redundant namespace declarations, but that's another issue. At least the output is correct now. --- ext/dom/document.c | 4 +- ext/dom/element.c | 58 ++---------------- ext/dom/php_dom.c | 59 ++++++++++++------- ext/dom/php_dom.h | 1 + ...ent_createAttributeNS_prefix_conflict.phpt | 38 ++++++++++-- ..._importNode_attribute_prefix_conflict.phpt | 4 +- ...lement_setAttributeNS_prefix_conflict.phpt | 17 +++--- 7 files changed, 90 insertions(+), 91 deletions(-) diff --git a/ext/dom/document.c b/ext/dom/document.c index bfb06d7e4cca4..9f8b315d9f9a7 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -805,7 +805,7 @@ PHP_METHOD(DOMDocument, importNode) xmlNodePtr root = xmlDocGetRootElement(docp); nsptr = xmlSearchNsByHref (nodep->doc, root, nodep->ns->href); - if (nsptr == NULL) { + if (nsptr == NULL || nsptr->prefix == NULL) { int errorcode; nsptr = dom_get_ns(root, (char *) nodep->ns->href, &errorcode, (char *) nodep->ns->prefix); } @@ -910,7 +910,7 @@ PHP_METHOD(DOMDocument, createAttributeNS) nodep = (xmlNodePtr) xmlNewDocProp(docp, (xmlChar *) localname, NULL); if (nodep != NULL && uri_len > 0) { nsptr = xmlSearchNsByHref(nodep->doc, root, (xmlChar *) uri); - if (nsptr == NULL) { + if (nsptr == NULL || nsptr->prefix == NULL) { nsptr = dom_get_ns(root, uri, &errorcode, prefix); } xmlSetNs(nodep, nsptr); diff --git a/ext/dom/element.c b/ext/dom/element.c index 8fb19d9e2eaed..fabc3c514bf96 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -655,45 +655,6 @@ PHP_METHOD(DOMElement, getAttributeNS) } /* }}} end dom_element_get_attribute_ns */ -static xmlNsPtr _dom_new_reconNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) /* {{{ */ -{ - xmlNsPtr def; - xmlChar prefix[50]; - int counter = 1; - - if ((tree == NULL) || (ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { - return NULL; - } - - /* Code taken from libxml2 (2.6.20) xmlNewReconciliedNs - * - * Find a close prefix which is not already in use. - * Let's strip namespace prefixes longer than 20 chars ! - */ - if (ns->prefix == NULL) - snprintf((char *) prefix, sizeof(prefix), "default"); - else - snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix); - - def = xmlSearchNs(doc, tree, prefix); - while (def != NULL) { - if (counter > 1000) return(NULL); - if (ns->prefix == NULL) - snprintf((char *) prefix, sizeof(prefix), "default%d", counter++); - else - snprintf((char *) prefix, sizeof(prefix), "%.20s%d", - (char *)ns->prefix, counter++); - def = xmlSearchNs(doc, tree, prefix); - } - - /* - * OK, now we are ready to create a new one. - */ - def = xmlNewNs(tree, ns->href, prefix); - return(def); -} -/* }}} */ - /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElSetAttrNS Since: DOM Level 2 */ @@ -756,27 +717,18 @@ PHP_METHOD(DOMElement, setAttributeNS) tmpnsptr = tmpnsptr->next; } if (tmpnsptr == NULL) { - nsptr = _dom_new_reconNs(elemp->doc, elemp, nsptr); + nsptr = dom_get_ns_resolve_prefix_conflict(elemp, (const char *) nsptr->href); } } } if (nsptr == NULL) { - if (prefix == NULL) { - if (is_xmlns == 1) { - xmlNewNs(elemp, (xmlChar *)value, NULL); - xmlReconciliateNs(elemp->doc, elemp); - } else { - errorcode = NAMESPACE_ERR; - } + if (is_xmlns == 1) { + xmlNewNs(elemp, (xmlChar *)value, prefix == NULL ? NULL : (xmlChar *)localname); } else { - if (is_xmlns == 1) { - xmlNewNs(elemp, (xmlChar *)value, (xmlChar *)localname); - } else { - nsptr = dom_get_ns(elemp, uri, &errorcode, prefix); - } - xmlReconciliateNs(elemp->doc, elemp); + nsptr = dom_get_ns(elemp, uri, &errorcode, prefix); } + xmlReconciliateNs(elemp->doc, elemp); } else { if (is_xmlns == 1) { if (nsptr->href) { diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 9e036214bde53..bada817e301e8 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -32,10 +32,6 @@ #define PHP_XPATH 1 #define PHP_XPTR 2 -/* libxml2 doesn't expose this constant as part of their public API. - * See xmlDOMReconcileNSOptions in tree.c */ -#define PHP_LIBXML2_DOM_RECONNS_REMOVEREDUND (1 << 0) - /* {{{ class entries */ PHP_DOM_EXPORT zend_class_entry *dom_node_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_domexception_class_entry; @@ -1473,8 +1469,7 @@ static void dom_libxml_reconcile_ensure_namespaces_are_declared(xmlNodePtr nodep * Although libxml2 currently does not use this for the reconciliation, it still * makes sense to do this just in case libxml2's internal change in the future. */ xmlDOMWrapCtxt dummy_ctxt = {0}; - bool remove_redundant = nodep->nsDef == NULL && nodep->ns != NULL; - xmlDOMWrapReconcileNamespaces(&dummy_ctxt, nodep, /* options */ remove_redundant ? PHP_LIBXML2_DOM_RECONNS_REMOVEREDUND : 0); + xmlDOMWrapReconcileNamespaces(&dummy_ctxt, nodep, /* options */ 0); } void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */ @@ -1557,6 +1552,35 @@ int dom_check_qname(char *qname, char **localname, char **prefix, int uri_len, i } /* }}} */ +/* Creates a new namespace declaration with a random prefix with the given uri on the tree. + * This is used to resolve a namespace prefix conflict in cases where spec does not want a + * namespace error in case of conflicts, but demands a resolution. */ +xmlNsPtr dom_get_ns_resolve_prefix_conflict(xmlNodePtr tree, const char *uri) +{ + ZEND_ASSERT(tree != NULL); + xmlDocPtr doc = tree->doc; + + if (UNEXPECTED(doc == NULL)) { + return NULL; + } + + /* Code adapted from libxml2 (2.10.4) */ + char prefix[50]; + int counter = 1; + snprintf(prefix, sizeof(prefix), "default"); + xmlNsPtr nsptr = xmlSearchNs(doc, tree, (const xmlChar *) prefix); + while (nsptr != NULL) { + if (counter > 1000) { + return NULL; + } + snprintf(prefix, sizeof(prefix), "default%d", counter++); + nsptr = xmlSearchNs(doc, tree, (const xmlChar *) prefix); + } + + /* Search yielded no conflict */ + return xmlNewNs(tree, (const xmlChar *) uri, (const xmlChar *) prefix); +} + /* http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS @@ -1574,28 +1598,21 @@ xmlNsPtr dom_get_ns(xmlNodePtr nodep, char *uri, int *errorcode, char *prefix) { if (! ((prefix && !strcmp (prefix, "xml") && strcmp(uri, (char *)XML_XML_NAMESPACE)) || (prefix && !strcmp (prefix, "xmlns") && strcmp(uri, (char *)DOM_XMLNS_NAMESPACE)) || (prefix && !strcmp(uri, (char *)DOM_XMLNS_NAMESPACE) && strcmp (prefix, "xmlns")))) { - /* Reuse the old namespaces from doc->oldNs if possible, before creating a new one. - * This will prevent the oldNs list from growing with duplicates. */ - xmlDocPtr doc = nodep->doc; - if (doc && doc->oldNs != NULL) { - nsptr = doc->oldNs; - do { - if (xmlStrEqual(nsptr->prefix, (xmlChar *)prefix) && xmlStrEqual(nsptr->href, (xmlChar *)uri)) { - goto out; - } - nsptr = nsptr->next; - } while (nsptr); - } - /* Couldn't reuse one, create a new one. */ nsptr = xmlNewNs(nodep, (xmlChar *)uri, (xmlChar *)prefix); if (UNEXPECTED(nsptr == NULL)) { - goto err; + /* Either memory allocation failure, or it's because of a prefix conflict. + * We'll assume a conflict and try again. If it was a memory allocation failure we'll just fail again, whatever. + * This isn't needed for every caller (such as createElementNS & DOMElement::__construct), but isn't harmful and simplifies the mental model "when do I use which function?". + * This branch will also be taken unlikely anyway as in those cases it'll be for allocation failure. */ + nsptr = dom_get_ns_resolve_prefix_conflict(nodep, uri); + if (UNEXPECTED(nsptr == NULL)) { + goto err; + } } } else { goto err; } -out: *errorcode = 0; return nsptr; err: diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index b4a6a2d01e83b..4d415256788af 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -151,6 +151,7 @@ zend_string *dom_node_concatenated_name_helper(size_t name_len, const char *name zend_string *dom_node_get_node_name_attribute_or_element(const xmlNode *nodep); bool php_dom_is_node_connected(const xmlNode *node); bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, xmlDocPtr new_document); +xmlNsPtr dom_get_ns_resolve_prefix_conflict(xmlNodePtr tree, const char *uri); /* parentnode */ void dom_parent_node_prepend(dom_object *context, zval *nodes, uint32_t nodesc); diff --git a/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt b/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt index e06da45fd051e..8007481cbc06d 100644 --- a/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt +++ b/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt @@ -45,12 +45,38 @@ var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http echo $doc->saveXML(), "\n"; ?> ---EXPECTF-- +--EXPECT-- --- setAttributeNode variation (you shouldn't do this, but we test this anyway) --- NULL +string(18) "http://php.net/ns1" +string(18) "http://php.net/ns2" +string(18) "http://php.net/ns3" + + -Fatal error: Uncaught DOMException: Namespace Error in %s:%d -Stack trace: -#0 %s(%d): DOMDocument->createAttributeNS('http://php.net/...', 'hello') -#1 {main} - thrown in %s on line %d +string(18) "http://php.net/ns4" +string(18) "http://php.net/ns1" +string(18) "http://php.net/ns2" +string(18) "http://php.net/ns3" + + + +NULL +string(18) "http://php.net/ns1" + + + +--- setAttributeNodeNS variation --- +string(18) "http://php.net/ns1" +NULL +NULL +NULL + + + +string(18) "http://php.net/ns1" +string(18) "http://php.net/ns2" +string(18) "http://php.net/ns3" +string(18) "http://php.net/ns4" + + diff --git a/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt b/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt index 54de02ceac226..d00fedbfb3d6c 100644 --- a/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt +++ b/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt @@ -52,12 +52,12 @@ echo $dom2->saveXML(); - + --- Non-default namespace test case with a default namespace in the destination --- - + --- Default namespace test case --- diff --git a/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt b/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt index f79a13cc11593..fc491b59ea31d 100644 --- a/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt +++ b/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt @@ -22,11 +22,14 @@ echo $dom->saveXML(); $dom->documentElement->setAttributeNS('http://php.net/2', 'bar', 'no2'); echo $dom->saveXML(); ?> ---EXPECTF-- +--EXPECT-- --- Non-default namespace test case --- - -Fatal error: Uncaught DOMException: Namespace Error in %s:%d -Stack trace: -#0 %s(%d): DOMElement->setAttributeNS('http://php.net/...', 'foo:bar', 'no1') -#1 {main} - thrown in %s on line %d + + + + +--- Default namespace test case --- + + + + From 12c1447136466d775ae69b6f8a63c708781806b5 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:34:45 +0200 Subject: [PATCH 3/5] Address review comments and split tests --- ext/dom/document.c | 2 +- ...ent_createAttributeNS_prefix_conflict.phpt | 82 ------------------- .../setAttributeNS_with_prefix.phpt | 36 ++++++++ .../setAttributeNS_without_prefix.phpt | 36 ++++++++ .../setAttribute_mixed_prefix.phpt | 20 +++++ .../setAttribute_with_prefix.phpt | 36 ++++++++ .../setAttribute_without_prefix.phpt | 36 ++++++++ 7 files changed, 165 insertions(+), 83 deletions(-) delete mode 100644 ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt create mode 100644 ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_with_prefix.phpt create mode 100644 ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_without_prefix.phpt create mode 100644 ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_mixed_prefix.phpt create mode 100644 ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_with_prefix.phpt create mode 100644 ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_without_prefix.phpt diff --git a/ext/dom/document.c b/ext/dom/document.c index 9f8b315d9f9a7..f254d87e7d63c 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -911,7 +911,7 @@ PHP_METHOD(DOMDocument, createAttributeNS) if (nodep != NULL && uri_len > 0) { nsptr = xmlSearchNsByHref(nodep->doc, root, (xmlChar *) uri); if (nsptr == NULL || nsptr->prefix == NULL) { - nsptr = dom_get_ns(root, uri, &errorcode, prefix); + nsptr = dom_get_ns(root, uri, &errorcode, prefix ? prefix : "default"); } xmlSetNs(nodep, nsptr); } diff --git a/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt b/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt deleted file mode 100644 index 8007481cbc06d..0000000000000 --- a/ext/dom/tests/DOMDocument_createAttributeNS_prefix_conflict.phpt +++ /dev/null @@ -1,82 +0,0 @@ ---TEST-- -DOMDocument::createAttributeNS() with prefix name conflict ---EXTENSIONS-- -dom ---FILE-- -appendChild($doc->createElement('container')); - -echo "--- setAttributeNode variation (you shouldn't do this, but we test this anyway) ---\n"; - -// Adheres to DOM Core Level 3 - -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns2', 'hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns3', 'hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns4', 'hello'))?->namespaceURI); -echo $doc->saveXML(), "\n"; - -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns2', 'foo:hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns3', 'foo:hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns4', 'foo:hello'))?->namespaceURI); -echo $doc->saveXML(), "\n"; - -$doc = new DOMDocument(); -$doc->appendChild($doc->createElement('container')); -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); -echo $doc->saveXML(), "\n"; - -echo "--- setAttributeNodeNS variation ---\n"; - -var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns2', 'hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns3', 'hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns4', 'hello'))?->namespaceURI); -echo $doc->saveXML(), "\n"; - -var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns2', 'foo:hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns3', 'foo:hello'))?->namespaceURI); -var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns4', 'foo:hello'))?->namespaceURI); -echo $doc->saveXML(), "\n"; - -?> ---EXPECT-- ---- setAttributeNode variation (you shouldn't do this, but we test this anyway) --- -NULL -string(18) "http://php.net/ns1" -string(18) "http://php.net/ns2" -string(18) "http://php.net/ns3" - - - -string(18) "http://php.net/ns4" -string(18) "http://php.net/ns1" -string(18) "http://php.net/ns2" -string(18) "http://php.net/ns3" - - - -NULL -string(18) "http://php.net/ns1" - - - ---- setAttributeNodeNS variation --- -string(18) "http://php.net/ns1" -NULL -NULL -NULL - - - -string(18) "http://php.net/ns1" -string(18) "http://php.net/ns2" -string(18) "http://php.net/ns3" -string(18) "http://php.net/ns4" - - diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_with_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_with_prefix.phpt new file mode 100644 index 0000000000000..1ca679d576d2f --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_with_prefix.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNodeNS variation, with prefix +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns2', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns3', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns4', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL + + + +NULL + + + +NULL + + + +NULL + + diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_without_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_without_prefix.phpt new file mode 100644 index 0000000000000..6ab6c2292a787 --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_without_prefix.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNodeNS variation, without prefix +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns2', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns3', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns4', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL + + + +NULL + + + +NULL + + + +NULL + + diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_mixed_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_mixed_prefix.phpt new file mode 100644 index 0000000000000..a53d7304dc87e --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_mixed_prefix.phpt @@ -0,0 +1,20 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNode variation (DOM Level 3), mixed +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL +string(18) "http://php.net/ns1" + + diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_with_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_with_prefix.phpt new file mode 100644 index 0000000000000..161eadd353ba6 --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_with_prefix.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNode variation (DOM Level 3), with prefix +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns2', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns3', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns4', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL + + + +string(18) "http://php.net/ns1" + + + +string(18) "http://php.net/ns2" + + + +string(18) "http://php.net/ns3" + + diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_without_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_without_prefix.phpt new file mode 100644 index 0000000000000..34717ff6ab5be --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_without_prefix.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNode variation (DOM Level 3), without prefix +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns2', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns3', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns4', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL + + + +string(18) "http://php.net/ns1" + + + +string(18) "http://php.net/ns2" + + + +string(18) "http://php.net/ns3" + + From f61b77f500b92493027953c9367665fa23fb030a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 5 Aug 2023 20:00:34 +0200 Subject: [PATCH 4/5] Modify test to workaround bug 80927 --- .../namespace_definition_crash_in_attribute.phpt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt b/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt index 64f2fbfa007a9..cb22cdc435705 100644 --- a/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt +++ b/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt @@ -28,8 +28,6 @@ var_dump($child_attr2->namespaceURI); var_dump($attr3->textContent); var_dump($attr3->namespaceURI); -$doc->documentElement->remove(); - unset($child_attr1); unset($child_attr2); var_dump($attr3->namespaceURI); @@ -39,9 +37,9 @@ echo $doc->saveXML($attr3->parentNode), "\n"; ?> --EXPECT-- - + - + string(15) "hello content 2" string(0) "" string(8) "some:ns2" @@ -49,5 +47,6 @@ NULL string(0) "" string(7) "some:ns" string(7) "some:ns" - hello="" + default1:hello="" + From 650917e576c7bc652d3343cc11dab610e6c1f87f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 14 Aug 2023 21:56:28 +0200 Subject: [PATCH 5/5] Restore test to original --- .../namespace_definition_crash_in_attribute.phpt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt b/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt index cb22cdc435705..b43f7c34bae1d 100644 --- a/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt +++ b/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt @@ -28,6 +28,8 @@ var_dump($child_attr2->namespaceURI); var_dump($attr3->textContent); var_dump($attr3->namespaceURI); +$doc->documentElement->remove(); + unset($child_attr1); unset($child_attr2); var_dump($attr3->namespaceURI); @@ -49,4 +51,3 @@ string(7) "some:ns" string(7) "some:ns" default1:hello="" -