1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Align DOMChildNode parent checks with spec

Closes GH-11905.
This commit is contained in:
Niels Dossche
2023-08-07 20:46:39 +02:00
parent e157da11f3
commit 23ba4cde53
6 changed files with 98 additions and 36 deletions

1
NEWS
View File

@@ -7,6 +7,7 @@ PHP NEWS
- DOM:
. adoptNode now respects the strict error checking property. (nielsdos)
. Align DOMChildNode parent checks with spec. (nielsdos)
- Opcache:
. Avoid resetting JIT counter handlers from multiple processes/threads.

View File

@@ -46,6 +46,14 @@ PHP 8.3 UPGRADE NOTES
iterating over the WeakMap (reachability via iteration is considered weak).
Previously, such entries would never be automatically removed.
- DOM:
. DOMChildNode::after(), DOMChildNode::before(), DOMChildNode::replaceWith()
on a node that has no parent is now a no-op instead of a hierarchy exception,
which is the behaviour spec demands.
. Using the DOMParentNode and DOMChildNode methods without a document now works
instead of throwing a HIERARCHY_REQUEST_ERR DOMException. This is in line with
the behaviour spec demands.
- FFI:
. C functions that have a return type of void now return null instead of
returning the following object object(FFI\CData:void) { }

View File

@@ -240,8 +240,8 @@ static void dom_fragment_assign_parent_node(xmlNodePtr parentNode, xmlNodePtr fr
static zend_result dom_sanity_check_node_list_for_insertion(php_libxml_ref_obj *document, xmlNodePtr parentNode, zval *nodes, int nodesc)
{
if (document == NULL) {
php_dom_throw_error(HIERARCHY_REQUEST_ERR, 1);
if (UNEXPECTED(parentNode == NULL)) {
/* No error required, this must be a no-op per spec */
return FAILURE;
}
@@ -391,10 +391,9 @@ void dom_parent_node_after(dom_object *context, zval *nodes, uint32_t nodesc)
/* Spec step 1 */
parentNode = prevsib->parent;
/* Spec step 2 */
if (!parentNode) {
int stricterror = dom_get_strict_error(context->document);
php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
/* Sanity check for fragment, includes spec step 2 */
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
return;
}
@@ -409,10 +408,6 @@ void dom_parent_node_after(dom_object *context, zval *nodes, uint32_t nodesc)
doc = prevsib->doc;
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
return;
}
php_libxml_invalidate_node_list_cache_from_doc(doc);
/* Spec step 4: convert nodes into fragment */
@@ -448,10 +443,9 @@ void dom_parent_node_before(dom_object *context, zval *nodes, uint32_t nodesc)
/* Spec step 1 */
parentNode = nextsib->parent;
/* Spec step 2 */
if (!parentNode) {
int stricterror = dom_get_strict_error(context->document);
php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
/* Sanity check for fragment, includes spec step 2 */
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
return;
}
@@ -466,10 +460,6 @@ void dom_parent_node_before(dom_object *context, zval *nodes, uint32_t nodesc)
doc = nextsib->doc;
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
return;
}
php_libxml_invalidate_node_list_cache_from_doc(doc);
/* Spec step 4: convert nodes into fragment */
@@ -537,7 +527,7 @@ void dom_child_node_remove(dom_object *context)
return;
}
php_libxml_invalidate_node_list_cache_from_doc(context->document->ptr);
php_libxml_invalidate_node_list_cache_from_doc(child->doc);
xmlUnlinkNode(child);
}
@@ -550,10 +540,9 @@ void dom_child_replace_with(dom_object *context, zval *nodes, uint32_t nodesc)
/* Spec step 1 */
xmlNodePtr parentNode = child->parent;
/* Spec step 2 */
if (!parentNode) {
int stricterror = dom_get_strict_error(context->document);
php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
/* Sanity check for fragment, includes spec step 2 */
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
return;
}
@@ -571,11 +560,8 @@ void dom_child_replace_with(dom_object *context, zval *nodes, uint32_t nodesc)
viable_next_sibling = viable_next_sibling->next;
}
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
return;
}
php_libxml_invalidate_node_list_cache_from_doc(context->document->ptr);
xmlDocPtr doc = parentNode->doc;
php_libxml_invalidate_node_list_cache_from_doc(doc);
/* Spec step 4: convert nodes into fragment */
xmlNodePtr fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
@@ -586,7 +572,6 @@ void dom_child_replace_with(dom_object *context, zval *nodes, uint32_t nodesc)
/* Spec step 5: perform the replacement */
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. */
@@ -621,7 +606,7 @@ void dom_parent_node_replace_children(dom_object *context, zval *nodes, uint32_t
return;
}
php_libxml_invalidate_node_list_cache_from_doc(context->document->ptr);
php_libxml_invalidate_node_list_cache_from_doc(thisp->doc);
dom_remove_all_children(thisp);

View File

@@ -0,0 +1,44 @@
--TEST--
DOMChildNode methods without a parent
--EXTENSIONS--
dom
--FILE--
<?php
$doc = new DOMDocument;
$doc->loadXML(<<<XML
<?xml version="1.0"?>
<container>
<child/>
</container>
XML);
$container = $doc->documentElement;
$child = $container->firstElementChild;
$test = $doc->createElement('foo');
foreach (['before', 'after', 'replaceWith'] as $method) {
echo "--- $method ---\n";
$test->$method($child);
echo $doc->saveXML();
echo $doc->saveXML($test), "\n";
}
?>
--EXPECT--
--- before ---
<?xml version="1.0"?>
<container>
<child/>
</container>
<foo/>
--- after ---
<?xml version="1.0"?>
<container>
<child/>
</container>
<foo/>
--- replaceWith ---
<?xml version="1.0"?>
<container>
<child/>
</container>
<foo/>

View File

@@ -7,11 +7,14 @@ dom
$cdata = new DOMText;
try {
$cdata->before("string");
} catch (DOMException $e) {
echo $e->getMessage();
}
$cdata->before("string");
$cdata->after("string");
$cdata->replaceWith("string");
$dom = new DOMDocument();
$dom->adoptNode($cdata);
var_dump($dom->saveXML($cdata));
?>
--EXPECT--
Hierarchy Request Error
string(0) ""

View File

@@ -0,0 +1,21 @@
--TEST--
DOMElement: DOMChildNode, DOMParentNode modifications without a document
--EXTENSIONS--
dom
--FILE--
<?php
$element = new DOMElement("p", " Hello World! ");
$element->append("APPENDED");
$element->prepend("PREPENDED");
$element->after("AFTER");
$element->before("BEFORE");
$element->replaceWith("REPLACE");
$doc = new DOMDocument();
$doc->adoptNode($element);
echo $doc->saveXML($element), "\n";
?>
--EXPECT--
<p>PREPENDED Hello World! APPENDED</p>