Skip to content

Commit ed54d6d

Browse files
committed
Fix XML serializer errata: xmlns="" serialization should be allowed
The spec doesn't want to serialize xmlns:foo="", but the description of the step that checks this does not take into account that xmlns="" must be allowed. This patch corrects this errata. Closes phpGH-15894.
1 parent 5121aca commit ed54d6d

File tree

3 files changed

+39
-8
lines changed

3 files changed

+39
-8
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.4.0RC1
44

5+
- DOM:
6+
. Fix XML serializer errata: xmlns="" serialization should be allowed.
7+
(nielsdos)
8+
59
- MBString:
610
. Fixed bug GH-15824 (mb_detect_encoding(): Argument $encodings contains
711
invalid encoding "UTF8"). (Yuya Hamada)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
XML serializer spec errata: xmlns="" serialization should be allowed
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
8+
// Should be allowed
9+
$dom = Dom\XMLDocument::createFromString('<root><x xmlns=""/></root>');
10+
var_dump($dom->documentElement->innerHTML);
11+
12+
// Should not be allowed
13+
$dom = Dom\XMLDocument::createFromString('<root><x/></root>');
14+
$x = $dom->documentElement->firstChild;
15+
$x->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:a', '');
16+
try {
17+
var_dump($dom->documentElement->innerHTML);
18+
} catch (DOMException $e) {
19+
echo $e->getMessage(), "\n";
20+
}
21+
22+
?>
23+
--EXPECT--
24+
string(13) "<x xmlns=""/>"
25+
The resulting XML serialization is not well-formed

ext/dom/xml_serializer.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ static int dom_xml_serialize_attribute_node_value(xmlOutputBufferPtr out, xmlAtt
600600
/* These steps are from the attribute serialization algorithm's well-formed checks.
601601
* Note that this does not return a boolean but an int to be compatible with the TRY/TRY_CLEANUP interface
602602
* that we do for compatibility with libxml's interfaces. */
603-
static zend_always_inline int dom_xml_check_xmlns_attribute_requirements(const xmlAttr *attr)
603+
static zend_always_inline int dom_xml_check_xmlns_attribute_requirements(const xmlAttr *attr, const xmlChar *candidate_prefix)
604604
{
605605
const xmlChar *attr_value = dom_get_attribute_value(attr);
606606

@@ -609,8 +609,9 @@ static zend_always_inline int dom_xml_check_xmlns_attribute_requirements(const x
609609
return -1;
610610
}
611611

612-
/* 3.5.2.3. If the require well-formed flag is set and the value of attr's value attribute is the empty string */
613-
if (*attr_value == '\0') {
612+
/* 3.5.2.3. If the require well-formed flag is set and the value of attr's value attribute is the empty string.
613+
* Errata: an "xmlns" attribute is allowed but not one with a prefix, so the idea in the spec is right but the description isn't. */
614+
if (*attr_value == '\0' && candidate_prefix != NULL) {
614615
return -1;
615616
}
616617

@@ -790,15 +791,16 @@ static int dom_xml_serialize_attributes(
790791
}
791792
}
792793

793-
if (require_well_formed) {
794-
/* 3.5.2.2 and 3.5.2.3 are done by this call. */
795-
TRY_OR_CLEANUP(dom_xml_check_xmlns_attribute_requirements(attr));
796-
}
797-
798794
/* 3.5.2.4. the attr's prefix matches the string "xmlns", then let candidate prefix be the string "xmlns". */
799795
if (attr->ns->prefix != NULL && strcmp((const char *) attr->ns->prefix, "xmlns") == 0) {
800796
candidate_prefix = BAD_CAST "xmlns";
801797
}
798+
799+
/* Errata: step 3.5.2.3 can only really be checked if we already know the candidate prefix. */
800+
if (require_well_formed) {
801+
/* 3.5.2.2 and 3.5.2.3 are done by this call. */
802+
TRY_OR_CLEANUP(dom_xml_check_xmlns_attribute_requirements(attr, candidate_prefix));
803+
}
802804
}
803805
/* 3.5.3. Otherwise, the attribute namespace in not the XMLNS namespace. Run these steps: */
804806
else if (candidate_prefix == NULL) { /* https://github.com/w3c/DOM-Parsing/issues/29 */

0 commit comments

Comments
 (0)