Skip to content

Commit ad4cb0e

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: dom: fix attribute namespaces from foreign content in the HTML parser
2 parents eb34f89 + d84d188 commit ad4cb0e

3 files changed

Lines changed: 68 additions & 4 deletions

File tree

NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ PHP NEWS
1616
. Fixed use-after-free when re-constructing a DOMXPath whose php:function
1717
registrations are freed while still reachable from the cycle collector.
1818
(Ilia Alshanetsky)
19+
. Fixed Dom\HTMLDocument::getElementById() not finding ids of SVG and
20+
MathML elements. (Ilia Alshanetsky)
21+
. Fixed Dom\HTMLDocument giving attributes the namespace of their element
22+
when a fragment is parsed with an xlink, xml or xmlns context element.
23+
(Ilia Alshanetsky)
1924

2025
- Intl:
2126
. Fixed cloning IntlDateFormatter and MessageFormatter losing PHP-side state

ext/dom/html5_parser.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
239239
lxml_attr->children = lxml_attr->last = lxml_text;
240240
lxml_text->parent = (xmlNodePtr) lxml_attr;
241241

242-
if (attr->node.ns == LXB_NS_XMLNS) {
242+
if (attr->node.ns == LXB_NS_XMLNS && (attr->node.prefix || strcmp((const char *) local_name, "xmlns") == 0)) {
243243
if (strcmp((const char *) local_name, "xmlns") != 0) {
244244
if (prefixed_xmlns_ns == NULL) {
245245
prefixed_xmlns_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xmlns", DOM_XMLNS_NS_URI);
@@ -249,13 +249,13 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
249249
lxml_attr->ns = php_dom_libxml_ns_mapper_ensure_prefixless_xmlns_ns(ns_mapper);
250250
}
251251
lxml_attr->ns->_private = (void *) php_dom_ns_is_xmlns_magic_token;
252-
} else if (attr->node.ns == LXB_NS_XLINK) {
252+
} else if (attr->node.prefix && attr->node.ns == LXB_NS_XLINK) {
253253
if (xlink_ns == NULL) {
254254
xlink_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xlink", DOM_XLINK_NS_URI);
255255
xlink_ns->_private = (void *) php_dom_ns_is_xlink_magic_token;
256256
}
257257
lxml_attr->ns = xlink_ns;
258-
} else if (attr->node.ns == LXB_NS_XML) {
258+
} else if (attr->node.prefix && attr->node.ns == LXB_NS_XML) {
259259
if (xml_ns == NULL) {
260260
xml_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xml", DOM_XML_NS_URI);
261261
xml_ns->_private = (void *) php_dom_ns_is_xml_magic_token;
@@ -272,7 +272,7 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
272272
last_added_attr = lxml_attr;
273273

274274
/* xmlIsID does some other stuff too that is irrelevant here. */
275-
if (local_name_length == 2 && local_name[0] == 'i' && local_name[1] == 'd' && attr->node.ns == LXB_NS_HTML) {
275+
if (local_name_length == 2 && local_name[0] == 'i' && local_name[1] == 'd' && lxml_attr->ns == NULL) {
276276
if (xmlAddID(NULL, lxml_doc, value, lxml_attr) == 0) {
277277
/* If the ID already exists, the ID attribute still needs to be marked as an ID. */
278278
lxml_attr->atype = XML_ATTRIBUTE_ID;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
Unprefixed attributes in foreign content are in no namespace
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
$html = '<!DOCTYPE html><html><body><svg id="s" xlink:href="#a" xml:lang="en" xmlns:xlink="urn:x"><rect xml:id="r"/></svg><math id="m"></math><p id="p"></p></body></html>';
8+
$doc = Dom\HTMLDocument::createFromString($html, LIBXML_NOERROR);
9+
10+
var_dump([
11+
'svg #s' => $doc->getElementById('s')?->tagName,
12+
'math #m' => $doc->getElementById('m')?->tagName,
13+
'html #p' => $doc->getElementById('p')?->tagName,
14+
'xml:id #r' => $doc->getElementById('r')?->tagName,
15+
]);
16+
17+
foreach ($doc->getElementById('s')->attributes as $attr) {
18+
echo $attr->name, ' => ', var_export($attr->namespaceURI, true), "\n";
19+
}
20+
21+
$contexts = [
22+
'http://www.w3.org/1999/xlink' => 'z',
23+
'http://www.w3.org/XML/1998/namespace' => 'z',
24+
'http://www.w3.org/2000/xmlns/' => 'xmlns',
25+
];
26+
foreach ($contexts as $uri => $name) {
27+
$fragment_doc = Dom\HTMLDocument::createEmpty();
28+
$context = $fragment_doc->createElementNS($uri, $name);
29+
$fragment_doc->appendChild($context);
30+
$context->innerHTML = '<z id="q" xlink:href="#a"></z>';
31+
32+
echo $uri, "\n ", $context->innerHTML, "\n ";
33+
var_dump($fragment_doc->getElementById('q')?->tagName);
34+
}
35+
?>
36+
--EXPECT--
37+
array(4) {
38+
["svg #s"]=>
39+
string(3) "svg"
40+
["math #m"]=>
41+
string(4) "math"
42+
["html #p"]=>
43+
string(1) "P"
44+
["xml:id #r"]=>
45+
NULL
46+
}
47+
id => NULL
48+
xlink:href => 'http://www.w3.org/1999/xlink'
49+
xml:lang => 'http://www.w3.org/XML/1998/namespace'
50+
xmlns:xlink => 'http://www.w3.org/2000/xmlns/'
51+
http://www.w3.org/1999/xlink
52+
<z id="q" xlink:href="#a"></z>
53+
string(1) "Z"
54+
http://www.w3.org/XML/1998/namespace
55+
<z id="q" xlink:href="#a"></z>
56+
string(1) "Z"
57+
http://www.w3.org/2000/xmlns/
58+
<z id="q" xlink:href="#a"></z>
59+
string(1) "Z"

0 commit comments

Comments
 (0)