mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Fix bug #81642: DOMChildNode::replaceWith() bug when replacing a node with itself
Closes GH-11363.
This commit is contained in:
parent
b1d8e240e6
commit
23f7002527
2
NEWS
2
NEWS
@ -23,6 +23,8 @@ PHP NEWS
|
||||
xpath query). (nielsdos)
|
||||
. Fixed bug #67440 (append_node of a DOMDocumentFragment does not reconcile
|
||||
namespaces). (nielsdos)
|
||||
. Fixed bug #81642 (DOMChildNode::replaceWith() bug when replacing a node
|
||||
with itself). (nielsdos)
|
||||
|
||||
- Opcache:
|
||||
. Fix allocation loop in zend_shared_alloc_startup(). (nielsdos)
|
||||
|
@ -1234,7 +1234,7 @@ PHP_METHOD(DOMElement, prepend)
|
||||
}
|
||||
/* }}} end DOMElement::prepend */
|
||||
|
||||
/* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
|
||||
/* {{{ URL: https://dom.spec.whatwg.org/#dom-parentnode-replacechildren
|
||||
Since: DOM Living Standard (DOM4)
|
||||
*/
|
||||
PHP_METHOD(DOMElement, replaceWith)
|
||||
@ -1251,8 +1251,7 @@ PHP_METHOD(DOMElement, replaceWith)
|
||||
id = ZEND_THIS;
|
||||
DOM_GET_OBJ(context, id, xmlNodePtr, intern);
|
||||
|
||||
dom_parent_node_after(intern, args, argc);
|
||||
dom_child_node_remove(intern);
|
||||
dom_child_replace_with(intern, args, argc);
|
||||
}
|
||||
/* }}} end DOMElement::prepend */
|
||||
|
||||
|
@ -485,6 +485,32 @@ void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
|
||||
xmlFree(fragment);
|
||||
}
|
||||
|
||||
static zend_result dom_child_removal_preconditions(const xmlNodePtr child, int stricterror)
|
||||
{
|
||||
if (dom_node_is_read_only(child) == SUCCESS ||
|
||||
(child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
|
||||
php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (!child->parent) {
|
||||
php_dom_throw_error(NOT_FOUND_ERR, stricterror);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (dom_node_children_valid(child->parent) == FAILURE) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
xmlNodePtr children = child->parent->children;
|
||||
if (!children) {
|
||||
php_dom_throw_error(NOT_FOUND_ERR, stricterror);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void dom_child_node_remove(dom_object *context)
|
||||
{
|
||||
xmlNode *child = dom_object_get_node(context);
|
||||
@ -493,27 +519,11 @@ void dom_child_node_remove(dom_object *context)
|
||||
|
||||
stricterror = dom_get_strict_error(context->document);
|
||||
|
||||
if (dom_node_is_read_only(child) == SUCCESS ||
|
||||
(child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
|
||||
php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!child->parent) {
|
||||
php_dom_throw_error(NOT_FOUND_ERR, stricterror);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dom_node_children_valid(child->parent) == FAILURE) {
|
||||
if (UNEXPECTED(dom_child_removal_preconditions(child, stricterror) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
children = child->parent->children;
|
||||
if (!children) {
|
||||
php_dom_throw_error(NOT_FOUND_ERR, stricterror);
|
||||
return;
|
||||
}
|
||||
|
||||
while (children) {
|
||||
if (children == child) {
|
||||
xmlUnlinkNode(child);
|
||||
@ -525,4 +535,41 @@ void dom_child_node_remove(dom_object *context)
|
||||
php_dom_throw_error(NOT_FOUND_ERR, stricterror);
|
||||
}
|
||||
|
||||
void dom_child_replace_with(dom_object *context, zval *nodes, int nodesc)
|
||||
{
|
||||
xmlNodePtr child = dom_object_get_node(context);
|
||||
xmlNodePtr parentNode = child->parent;
|
||||
|
||||
int stricterror = dom_get_strict_error(context->document);
|
||||
if (UNEXPECTED(dom_child_removal_preconditions(child, stricterror) != SUCCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
xmlNodePtr insertion_point = child->next;
|
||||
|
||||
xmlNodePtr fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
|
||||
if (UNEXPECTED(fragment == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
xmlNodePtr newchild = fragment->children;
|
||||
xmlDocPtr doc = parentNode->doc;
|
||||
|
||||
if (newchild) {
|
||||
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_fragment_assign_parent_node(parentNode, fragment);
|
||||
dom_reconcile_ns_list(doc, newchild, last);
|
||||
}
|
||||
|
||||
xmlFree(fragment);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -132,6 +132,7 @@ void dom_parent_node_append(dom_object *context, zval *nodes, int nodesc);
|
||||
void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc);
|
||||
void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc);
|
||||
void dom_child_node_remove(dom_object *context);
|
||||
void dom_child_replace_with(dom_object *context, zval *nodes, int nodesc);
|
||||
|
||||
#define DOM_GET_OBJ(__ptr, __id, __prtype, __intern) { \
|
||||
__intern = Z_DOMOBJ_P(__id); \
|
||||
|
49
ext/dom/tests/bug81642.phpt
Normal file
49
ext/dom/tests/bug81642.phpt
Normal file
@ -0,0 +1,49 @@
|
||||
--TEST--
|
||||
Bug #81642 (DOMChildNode::replaceWith() bug when replacing a node with itself)
|
||||
--EXTENSIONS--
|
||||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// Replace with itself
|
||||
$doc = new DOMDocument();
|
||||
$doc->appendChild($target = $doc->createElement('test'));
|
||||
$target->replaceWith($target);
|
||||
var_dump($doc->saveXML());
|
||||
|
||||
// Replace with itself + another element
|
||||
$doc = new DOMDocument();
|
||||
$doc->appendChild($target = $doc->createElement('test'));
|
||||
$target->replaceWith($target, $doc->createElement('foo'));
|
||||
var_dump($doc->saveXML());
|
||||
|
||||
// Replace with text node
|
||||
$doc = new DOMDocument();
|
||||
$doc->appendChild($target = $doc->createElement('test'));
|
||||
$target->replaceWith($target, 'foo');
|
||||
var_dump($doc->saveXML());
|
||||
|
||||
// Replace with text node variant 2
|
||||
$doc = new DOMDocument();
|
||||
$doc->appendChild($target = $doc->createElement('test'));
|
||||
$target->replaceWith('bar', $target, 'foo');
|
||||
var_dump($doc->saveXML());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(30) "<?xml version="1.0"?>
|
||||
<test/>
|
||||
"
|
||||
string(37) "<?xml version="1.0"?>
|
||||
<test/>
|
||||
<foo/>
|
||||
"
|
||||
string(34) "<?xml version="1.0"?>
|
||||
<test/>
|
||||
foo
|
||||
"
|
||||
string(38) "<?xml version="1.0"?>
|
||||
bar
|
||||
<test/>
|
||||
foo
|
||||
"
|
Loading…
Reference in New Issue
Block a user