mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fix GH-11625: DOMElement::replaceWith() doesn't replace node with DOMDocumentFragment but just deletes node or causes wrapping <></> depending on libxml2 version
Depending on the libxml2 version, the behaviour is either to not render the fragment correctly, or to wrap it inside <></>. Fix it by unpacking fragments manually. This has the side effect that we need to move the unlinking check in the replacement function to earlier because the empty child list is now possible in non-error cases. Also fixes a mistake in the linked list management. Closes GH-11627.
This commit is contained in:
parent
0d07b6d647
commit
15ff830373
3 changed files with 92 additions and 7 deletions
5
NEWS
5
NEWS
|
@ -20,6 +20,11 @@ PHP NEWS
|
||||||
- Date:
|
- Date:
|
||||||
. Fixed bug GH-11368 (Date modify returns invalid datetime). (Derick)
|
. Fixed bug GH-11368 (Date modify returns invalid datetime). (Derick)
|
||||||
|
|
||||||
|
- DOM:
|
||||||
|
. Fixed bug GH-11625 (DOMElement::replaceWith() doesn't replace node with
|
||||||
|
DOMDocumentFragment but just deletes node or causes wrapping <></>
|
||||||
|
depending on libxml2 version). (nielsdos)
|
||||||
|
|
||||||
- Fileinfo:
|
- Fileinfo:
|
||||||
. Fixed bug GH-11298 (finfo returns wrong mime type for xz files). (Anatol)
|
. Fixed bug GH-11298 (finfo returns wrong mime type for xz files). (Anatol)
|
||||||
|
|
||||||
|
|
|
@ -183,7 +183,15 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newNode->parent != NULL) {
|
if (newNode->type == XML_DOCUMENT_FRAG_NODE) {
|
||||||
|
/* Unpack document fragment nodes, the behaviour differs for different libxml2 versions. */
|
||||||
|
newNode = newNode->children;
|
||||||
|
if (UNEXPECTED(newNode == NULL)) {
|
||||||
|
/* No nodes to add, nothing to do here */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xmlUnlinkNode(newNode);
|
||||||
|
} else if (newNode->parent != NULL) {
|
||||||
xmlUnlinkNode(newNode);
|
xmlUnlinkNode(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +378,7 @@ static void dom_pre_insert(xmlNodePtr insertion_point, xmlNodePtr parentNode, xm
|
||||||
insertion_point->prev->next = newchild;
|
insertion_point->prev->next = newchild;
|
||||||
newchild->prev = insertion_point->prev;
|
newchild->prev = insertion_point->prev;
|
||||||
}
|
}
|
||||||
insertion_point->prev = newchild;
|
insertion_point->prev = fragment->last;
|
||||||
if (parentNode->children == insertion_point) {
|
if (parentNode->children == insertion_point) {
|
||||||
parentNode->children = newchild;
|
parentNode->children = newchild;
|
||||||
}
|
}
|
||||||
|
@ -555,14 +563,14 @@ void dom_child_replace_with(dom_object *context, zval *nodes, int nodesc)
|
||||||
xmlNodePtr newchild = fragment->children;
|
xmlNodePtr newchild = fragment->children;
|
||||||
xmlDocPtr doc = parentNode->doc;
|
xmlDocPtr doc = parentNode->doc;
|
||||||
|
|
||||||
|
/* Unlink and free it unless it became a part of the fragment. */
|
||||||
|
if (child->parent != fragment) {
|
||||||
|
xmlUnlinkNode(child);
|
||||||
|
}
|
||||||
|
|
||||||
if (newchild) {
|
if (newchild) {
|
||||||
xmlNodePtr last = fragment->last;
|
xmlNodePtr last = fragment->last;
|
||||||
|
|
||||||
/* Unlink and free it unless it became a part of the fragment. */
|
|
||||||
if (child->parent != fragment) {
|
|
||||||
xmlUnlinkNode(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
dom_pre_insert(insertion_point, parentNode, newchild, fragment);
|
dom_pre_insert(insertion_point, parentNode, newchild, fragment);
|
||||||
|
|
||||||
dom_fragment_assign_parent_node(parentNode, fragment);
|
dom_fragment_assign_parent_node(parentNode, fragment);
|
||||||
|
|
72
ext/dom/tests/gh11625.phpt
Normal file
72
ext/dom/tests/gh11625.phpt
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
--TEST--
|
||||||
|
GH-11625 (DOMElement::replaceWith() doesn't replace node with DOMDocumentFragment but just deletes node or causes wrapping <></> depending on libxml2 version)
|
||||||
|
--EXTENSIONS--
|
||||||
|
dom
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test($mutator) {
|
||||||
|
$html = <<<XML
|
||||||
|
<body>
|
||||||
|
<div></div><div></div>
|
||||||
|
</body>
|
||||||
|
XML;
|
||||||
|
|
||||||
|
$dom = new DOMDocument();
|
||||||
|
$dom->loadXML($html);
|
||||||
|
|
||||||
|
$divs = iterator_to_array($dom->getElementsByTagName('div')->getIterator());
|
||||||
|
$i = 0;
|
||||||
|
foreach ($divs as $div) {
|
||||||
|
$mutator($dom, $div, $i);
|
||||||
|
echo $dom->saveHTML();
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "--- Single replacement ---\n";
|
||||||
|
|
||||||
|
test(function($dom, $div, $i) {
|
||||||
|
$fragment = $dom->createDocumentFragment();
|
||||||
|
$fragment->appendXML("<p>Hi $i!</p>");
|
||||||
|
$div->replaceWith($fragment);
|
||||||
|
});
|
||||||
|
|
||||||
|
echo "--- Multiple replacement ---\n";
|
||||||
|
|
||||||
|
test(function($dom, $div, $i) {
|
||||||
|
$fragment = $dom->createDocumentFragment();
|
||||||
|
$fragment->appendXML("<p>Hi $i!</p>");
|
||||||
|
$div->replaceWith($fragment, $dom->createElement('x'), "hello");
|
||||||
|
});
|
||||||
|
|
||||||
|
echo "--- Empty fragment replacement ---\n";
|
||||||
|
|
||||||
|
test(function($dom, $div, $i) {
|
||||||
|
$fragment = $dom->createDocumentFragment();
|
||||||
|
$div->replaceWith($fragment);
|
||||||
|
});
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
--- Single replacement ---
|
||||||
|
<body>
|
||||||
|
<p>Hi 0!</p><div></div>
|
||||||
|
</body>
|
||||||
|
<body>
|
||||||
|
<p>Hi 0!</p><p>Hi 1!</p>
|
||||||
|
</body>
|
||||||
|
--- Multiple replacement ---
|
||||||
|
<body>
|
||||||
|
<p>Hi 0!</p><x></x>hello<div></div>
|
||||||
|
</body>
|
||||||
|
<body>
|
||||||
|
<p>Hi 0!</p><x></x>hello<p>Hi 1!</p><x></x>hello
|
||||||
|
</body>
|
||||||
|
--- Empty fragment replacement ---
|
||||||
|
<body>
|
||||||
|
<div></div>
|
||||||
|
</body>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
Loading…
Add table
Add a link
Reference in a new issue