Skip to content

Commit bb4c5f7

Browse files
committed
Fix phpGH-10234: Setting DOMAttr::textContent results in an empty attribute value.
We can't directly call xmlNodeSetContent, because it might encode the string through xmlStringLenGetNodeList for types XML_DOCUMENT_FRAG_NODE, XML_ELEMENT_NODE, XML_ATTRIBUTE_NODE. In these cases we need to use a text node to avoid the encoding. For the other cases, we *can* rely on xmlNodeSetContent because it is either a no-op, or handles the content without encoding and clears the properties field if needed. The test was taken from the issue report, for the test: Co-authored-by: ThomasWeinert <[email protected]> Closes phpGH-10245.
1 parent b33fbbf commit bb4c5f7

File tree

2 files changed

+67
-4
lines changed

2 files changed

+67
-4
lines changed

ext/dom/node.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -769,17 +769,28 @@ int dom_node_text_content_write(dom_object *obj, zval *newval)
769769
return FAILURE;
770770
}
771771

772-
if (nodep->type == XML_ELEMENT_NODE || nodep->type == XML_ATTRIBUTE_NODE) {
772+
const xmlChar *xmlChars = (const xmlChar *) ZSTR_VAL(str);
773+
int type = nodep->type;
774+
775+
/* We can't directly call xmlNodeSetContent, because it might encode the string through
776+
* xmlStringLenGetNodeList for types XML_DOCUMENT_FRAG_NODE, XML_ELEMENT_NODE, XML_ATTRIBUTE_NODE.
777+
* See tree.c:xmlNodeSetContent in libxml.
778+
* In these cases we need to use a text node to avoid the encoding.
779+
* For the other cases, we *can* rely on xmlNodeSetContent because it is either a no-op, or handles
780+
* the content without encoding and clears the properties field if needed. */
781+
if (type == XML_DOCUMENT_FRAG_NODE || type == XML_ELEMENT_NODE || type == XML_ATTRIBUTE_NODE) {
773782
if (nodep->children) {
774783
node_list_unlink(nodep->children);
775784
php_libxml_node_free_list((xmlNodePtr) nodep->children);
776785
nodep->children = NULL;
777786
}
787+
788+
xmlNode *textNode = xmlNewText(xmlChars);
789+
xmlAddChild(nodep, textNode);
790+
} else {
791+
xmlNodeSetContent(nodep, xmlChars);
778792
}
779793

780-
/* we have to use xmlNodeAddContent() to get the same behavior as with xmlNewText() */
781-
xmlNodeSetContent(nodep, (xmlChar *) "");
782-
xmlNodeAddContent(nodep, (xmlChar *) ZSTR_VAL(str));
783794
zend_string_release_ex(str, 0);
784795

785796
return SUCCESS;

ext/dom/tests/gh10234.phpt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
--TEST--
2+
GH-10234 (Setting DOMAttr::textContent results in an empty attribute value.)
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
$document = new DOMDocument();
8+
$document->loadXML('<element attribute="value"/>');
9+
$attribute = $document->documentElement->getAttributeNode('attribute');
10+
11+
var_dump($document->saveHTML());
12+
var_dump($attribute->textContent);
13+
14+
$attribute->textContent = 'new value';
15+
var_dump($attribute->textContent);
16+
var_dump($document->saveHTML());
17+
18+
$attribute->textContent = 'hello & world';
19+
var_dump($attribute->textContent);
20+
var_dump($document->saveHTML());
21+
22+
$attribute->textContent = '<b>hi</b>';
23+
var_dump($attribute->textContent);
24+
var_dump($document->saveHTML());
25+
26+
$document->documentElement->textContent = 'hello & world';
27+
var_dump($document->documentElement->textContent);
28+
var_dump($document->saveHTML());
29+
30+
$document->documentElement->textContent = '<b>hi</b>';
31+
var_dump($document->documentElement->textContent);
32+
var_dump($document->saveHTML());
33+
?>
34+
--EXPECT--
35+
string(38) "<element attribute="value"></element>
36+
"
37+
string(5) "value"
38+
string(9) "new value"
39+
string(42) "<element attribute="new value"></element>
40+
"
41+
string(13) "hello & world"
42+
string(50) "<element attribute="hello &amp; world"></element>
43+
"
44+
string(9) "<b>hi</b>"
45+
string(54) "<element attribute="&lt;b&gt;hi&lt;/b&gt;"></element>
46+
"
47+
string(13) "hello & world"
48+
string(71) "<element attribute="&lt;b&gt;hi&lt;/b&gt;">hello &amp; world</element>
49+
"
50+
string(9) "<b>hi</b>"
51+
string(75) "<element attribute="&lt;b&gt;hi&lt;/b&gt;">&lt;b&gt;hi&lt;/b&gt;</element>
52+
"

0 commit comments

Comments
 (0)