simplexml: filter addChild() result by the created element's namespace - #23599
simplexml: filter addChild() result by the created element's namespace#23599iliaal wants to merge 1 commit into
Conversation
0a411a4 to
10af2d1
Compare
addChild() built the returned SimpleXMLElement with the prefix the caller passed in, not the one the new node ended up in, so a child added through that object was filtered against the wrong namespace and was invisible by property name. Take the prefix from newnode->ns instead. The filter keys on the prefix rather than the href because node_as_zval() installs no filter at all for a prefixless namespace, and switching to href would start filtering the default-namespace case that today has none. Closes phpGH-23599
| } | ||
|
|
||
| node_as_zval_str(sxe, newnode, return_value, SXE_ITER_NONE, localname, prefix, 0); | ||
| node_as_zval_str(sxe, newnode, return_value, SXE_ITER_NONE, localname, |
There was a problem hiding this comment.
Only filter when the caller asked for a namespace: fixes the two broken forms without changing what addChild('kid') under a prefixed parent can read, which would otherwise be a BC break on a stable branch.
diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c
--- a/ext/simplexml/simplexml.c
+++ b/ext/simplexml/simplexml.c
@@ -1679,6 +1679,7 @@ PHP_METHOD(SimpleXMLElement, addChild)
xmlNodePtr node, newnode;
xmlNsPtr nsptr = NULL;
xmlChar *localname, *prefix = NULL;
+ const xmlChar *retprefix = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!s!",
&qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
@@ -1727,8 +1728,11 @@ PHP_METHOD(SimpleXMLElement, addChild)
}
}
- node_as_zval_str(sxe, newnode, return_value, SXE_ITER_NONE, localname,
- newnode->ns ? newnode->ns->prefix : NULL, 1);
+ if ((prefix != NULL || nsuri != NULL) && newnode->ns != NULL) {
+ retprefix = newnode->ns->prefix;
+ }
+
+ node_as_zval_str(sxe, newnode, return_value, SXE_ITER_NONE, localname, retprefix, 1);will need to change test expectations.
There was a problem hiding this comment.
Adopted, pushed as 38a7cdc.
Two notes. addChild('kid') under a prefixed parent doesn't read today either: a NULL iter.nsprefix isn't "no filter", match_ns() with a NULL name matches only nodes with no namespace or a null prefix. Your gate keeps that broken, which is fine for 8.4.
Mine broke attribute reads rather than child reads: addAttribute() uses a NULL nsptr, so any prefix filter hides them. Your gate still flips addChild('kid', null, $uri) + addAttribute() from readable to not; pinned in the test.
addChild() passed the caller's prefix to node_as_zval_str() with isprefix set to 0, so the returned element filtered its children by comparing that prefix against the namespace href and matched nothing. Take the prefix from the created node and mark it as one, but only when the caller asked for a namespace, so a plain addChild() keeps the unfiltered view that its attributes and non-namespaced children rely on. Closes phpGH-23599
10af2d1 to
38a7cdc
Compare
SimpleXMLElement::addChild()built the returned element with the prefix the caller passed in rather than the one the new node ended up in, so a child added through that returned object was filtered against the wrong namespace and could not be reached by property name. Taking the prefix fromnewnode->nsfixes all three cases: an explicita:kidwith a matching uri, a barekidwith a uri, and a barekidunder a prefixed parent wherexmlNewChildinherits the parent's prefix.The filter keys on the prefix rather than the href deliberately.
node_as_zval()installs no filter at all when the prefix is null or empty, so switching to href matching would start filtering the default-namespace case that currently has none.