diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c index 9d6e90ab72186..676d19da740b5 100644 --- a/ext/dom/parentnode.c +++ b/ext/dom/parentnode.c @@ -182,7 +182,15 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod 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); } @@ -371,7 +379,7 @@ static void dom_pre_insert(xmlNodePtr insertion_point, xmlNodePtr parentNode, xm insertion_point->prev->next = newchild; newchild->prev = insertion_point->prev; } - insertion_point->prev = newchild; + insertion_point->prev = fragment->last; if (parentNode->children == insertion_point) { parentNode->children = newchild; } @@ -565,15 +573,15 @@ void dom_child_replace_with(dom_object *context, zval *nodes, uint32_t nodesc) xmlNodePtr newchild = fragment->children; xmlDocPtr doc = parentNode->doc; + /* Unlink it unless it became a part of the fragment. + * Freeing will be taken care of by the lifetime of the returned dom object. */ + if (child->parent != fragment) { + xmlUnlinkNode(child); + } + if (newchild) { xmlNodePtr last = fragment->last; - /* Unlink it unless it became a part of the fragment. - * Freeing will be taken care of by the lifetime of the returned dom object. */ - if (child->parent != fragment) { - xmlUnlinkNode(child); - } - dom_pre_insert(insertion_point, parentNode, newchild, fragment); dom_fragment_assign_parent_node(parentNode, fragment); diff --git a/ext/dom/tests/gh11625.phpt b/ext/dom/tests/gh11625.phpt new file mode 100644 index 0000000000000..40e34d32b808d --- /dev/null +++ b/ext/dom/tests/gh11625.phpt @@ -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-- + +
+ +Hi 0!
+ +Hi 0!
Hi 1!
+ +Hi 0!
Hi 0!
Hi 1!