mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Merge branch 'PHP-8.2'
* PHP-8.2: Fix GH-11288 and GH-11289 and GH-11290 and GH-9142: DOMExceptions and segfaults with replaceWith
This commit is contained in:
@@ -124,6 +124,23 @@ int dom_parent_node_child_element_count(dom_object *obj, zval *retval)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static bool dom_is_node_in_list(const zval *nodes, int nodesc, const xmlNodePtr node_to_find)
|
||||
{
|
||||
for (int i = 0; i < nodesc; i++) {
|
||||
if (Z_TYPE(nodes[i]) == IS_OBJECT) {
|
||||
const zend_class_entry *ce = Z_OBJCE(nodes[i]);
|
||||
|
||||
if (instanceof_function(ce, dom_node_class_entry)) {
|
||||
if (dom_object_get_node(Z_DOMOBJ_P(nodes + i)) == node_to_find) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNode, zval *nodes, int nodesc)
|
||||
{
|
||||
int i;
|
||||
@@ -177,17 +194,16 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod
|
||||
goto hierarchy_request_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* xmlNewDocText function will always returns same address to the second parameter if the parameters are greater than or equal to three.
|
||||
* If it's text, that's fine, but if it's an object, it can cause invalid pointer because many new nodes point to the same memory address.
|
||||
* So we must copy the new node to avoid this situation.
|
||||
*/
|
||||
if (nodesc > 1) {
|
||||
/* Citing from the docs (https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/libxml2-tree.html#xmlAddChild):
|
||||
* "Add a new node to @parent, at the end of the child (or property) list merging adjacent TEXT nodes (in which case @cur is freed)".
|
||||
* So we must take a copy if this situation arises to prevent a use-after-free. */
|
||||
bool will_free = newNode->type == XML_TEXT_NODE && fragment->last && fragment->last->type == XML_TEXT_NODE;
|
||||
if (will_free) {
|
||||
newNode = xmlCopyNode(newNode, 1);
|
||||
}
|
||||
|
||||
if (!xmlAddChild(fragment, newNode)) {
|
||||
if (nodesc > 1) {
|
||||
if (will_free) {
|
||||
xmlFreeNode(newNode);
|
||||
}
|
||||
goto hierarchy_request_err;
|
||||
@@ -303,25 +319,64 @@ void dom_parent_node_prepend(dom_object *context, zval *nodes, int nodesc)
|
||||
xmlFree(fragment);
|
||||
}
|
||||
|
||||
static void dom_pre_insert(xmlNodePtr insertion_point, xmlNodePtr parentNode, xmlNodePtr newchild, xmlNodePtr fragment)
|
||||
{
|
||||
if (!insertion_point) {
|
||||
/* Place it as last node */
|
||||
if (parentNode->children) {
|
||||
/* There are children */
|
||||
fragment->last->prev = parentNode->last;
|
||||
newchild->prev = parentNode->last->prev;
|
||||
parentNode->last->next = newchild;
|
||||
} else {
|
||||
/* No children, because they moved out when they became a fragment */
|
||||
parentNode->children = newchild;
|
||||
parentNode->last = newchild;
|
||||
}
|
||||
} else {
|
||||
/* Insert fragment before insertion_point */
|
||||
fragment->last->next = insertion_point;
|
||||
if (insertion_point->prev) {
|
||||
insertion_point->prev->next = newchild;
|
||||
newchild->prev = insertion_point->prev;
|
||||
}
|
||||
insertion_point->prev = newchild;
|
||||
if (parentNode->children == insertion_point) {
|
||||
parentNode->children = newchild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
|
||||
{
|
||||
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-after */
|
||||
|
||||
xmlNode *prevsib = dom_object_get_node(context);
|
||||
xmlNodePtr newchild, parentNode;
|
||||
xmlNode *fragment, *nextsib;
|
||||
xmlNode *fragment;
|
||||
xmlDoc *doc;
|
||||
bool afterlastchild;
|
||||
|
||||
int stricterror = dom_get_strict_error(context->document);
|
||||
|
||||
if (!prevsib->parent) {
|
||||
php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
|
||||
/* 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);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Spec step 3: find first following child not in nodes; otherwise null */
|
||||
xmlNodePtr viable_next_sibling = prevsib->next;
|
||||
while (viable_next_sibling) {
|
||||
if (!dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
|
||||
break;
|
||||
}
|
||||
viable_next_sibling = viable_next_sibling->next;
|
||||
}
|
||||
|
||||
doc = prevsib->doc;
|
||||
parentNode = prevsib->parent;
|
||||
nextsib = prevsib->next;
|
||||
afterlastchild = (nextsib == NULL);
|
||||
|
||||
/* Spec step 4: convert nodes into fragment */
|
||||
fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
|
||||
|
||||
if (fragment == NULL) {
|
||||
@@ -331,40 +386,9 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
|
||||
newchild = fragment->children;
|
||||
|
||||
if (newchild) {
|
||||
/* first node and last node are both both parameters to DOMElement::after() method so nextsib and prevsib are null. */
|
||||
if (!parentNode->children) {
|
||||
prevsib = nextsib = NULL;
|
||||
} else if (afterlastchild) {
|
||||
/*
|
||||
* The new node will be inserted after last node, prevsib is last node.
|
||||
* The first node is the parameter to DOMElement::after() if parentNode->children == prevsib is true
|
||||
* and prevsib does not change, otherwise prevsib is parentNode->last (first node).
|
||||
*/
|
||||
prevsib = parentNode->children == prevsib ? prevsib : parentNode->last;
|
||||
} else {
|
||||
/*
|
||||
* The new node will be inserted after first node, prevsib is first node.
|
||||
* The first node is not the parameter to DOMElement::after() if parentNode->children == prevsib is true
|
||||
* and prevsib does not change otherwise prevsib is null to mean that parentNode->children is the new node.
|
||||
*/
|
||||
prevsib = parentNode->children == prevsib ? prevsib : NULL;
|
||||
}
|
||||
/* Step 5: place fragment into the parent before viable_next_sibling */
|
||||
dom_pre_insert(viable_next_sibling, parentNode, newchild, fragment);
|
||||
|
||||
if (prevsib) {
|
||||
fragment->last->next = prevsib->next;
|
||||
if (prevsib->next) {
|
||||
prevsib->next->prev = fragment->last;
|
||||
}
|
||||
prevsib->next = newchild;
|
||||
} else {
|
||||
parentNode->children = newchild;
|
||||
if (nextsib) {
|
||||
fragment->last->next = nextsib;
|
||||
nextsib->prev = fragment->last;
|
||||
}
|
||||
}
|
||||
|
||||
newchild->prev = prevsib;
|
||||
dom_fragment_assign_parent_node(parentNode, fragment);
|
||||
dom_reconcile_ns(doc, newchild);
|
||||
}
|
||||
@@ -374,17 +398,34 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
|
||||
|
||||
void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
|
||||
{
|
||||
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-before */
|
||||
|
||||
xmlNode *nextsib = dom_object_get_node(context);
|
||||
xmlNodePtr newchild, prevsib, parentNode;
|
||||
xmlNode *fragment, *afternextsib;
|
||||
xmlNodePtr newchild, parentNode;
|
||||
xmlNode *fragment;
|
||||
xmlDoc *doc;
|
||||
bool beforefirstchild;
|
||||
|
||||
/* 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);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Spec step 3: find first following child not in nodes; otherwise null */
|
||||
xmlNodePtr viable_previous_sibling = nextsib->prev;
|
||||
while (viable_previous_sibling) {
|
||||
if (!dom_is_node_in_list(nodes, nodesc, viable_previous_sibling)) {
|
||||
break;
|
||||
}
|
||||
viable_previous_sibling = viable_previous_sibling->prev;
|
||||
}
|
||||
|
||||
doc = nextsib->doc;
|
||||
prevsib = nextsib->prev;
|
||||
afternextsib = nextsib->next;
|
||||
parentNode = nextsib->parent;
|
||||
beforefirstchild = !prevsib;
|
||||
|
||||
/* Spec step 4: convert nodes into fragment */
|
||||
fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
|
||||
|
||||
if (fragment == NULL) {
|
||||
@@ -394,37 +435,14 @@ void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
|
||||
newchild = fragment->children;
|
||||
|
||||
if (newchild) {
|
||||
/* first node and last node are both both parameters to DOMElement::before() method so nextsib is null. */
|
||||
if (!parentNode->children) {
|
||||
nextsib = NULL;
|
||||
} else if (beforefirstchild) {
|
||||
/*
|
||||
* The new node will be inserted before first node, nextsib is first node and afternextsib is last node.
|
||||
* The first node is not the parameter to DOMElement::before() if parentNode->children == nextsib is true
|
||||
* and nextsib does not change, otherwise nextsib is the last node.
|
||||
*/
|
||||
nextsib = parentNode->children == nextsib ? nextsib : afternextsib;
|
||||
/* Step 5: if viable_previous_sibling is null, set it to the parent's first child, otherwise viable_previous_sibling's next sibling */
|
||||
if (!viable_previous_sibling) {
|
||||
viable_previous_sibling = parentNode->children;
|
||||
} else {
|
||||
/*
|
||||
* The new node will be inserted before last node, prevsib is first node and nestsib is last node.
|
||||
* The first node is not the parameter to DOMElement::before() if parentNode->children == prevsib is true
|
||||
* but last node may be, so use prevsib->next to determine the value of nextsib, otherwise nextsib does not change.
|
||||
*/
|
||||
nextsib = parentNode->children == prevsib ? prevsib->next : nextsib;
|
||||
viable_previous_sibling = viable_previous_sibling->next;
|
||||
}
|
||||
|
||||
if (parentNode->children == nextsib) {
|
||||
parentNode->children = newchild;
|
||||
} else {
|
||||
prevsib->next = newchild;
|
||||
}
|
||||
|
||||
fragment->last->next = nextsib;
|
||||
if (nextsib) {
|
||||
nextsib->prev = fragment->last;
|
||||
}
|
||||
|
||||
newchild->prev = prevsib;
|
||||
/* Step 6: place fragment into the parent after viable_previous_sibling */
|
||||
dom_pre_insert(viable_previous_sibling, parentNode, newchild, fragment);
|
||||
|
||||
dom_fragment_assign_parent_node(parentNode, fragment);
|
||||
dom_reconcile_ns(doc, newchild);
|
||||
|
||||
@@ -8,84 +8,84 @@ $doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before($target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "1 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before($target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "2 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before($doc->documentElement->lastChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "3 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before($doc->documentElement->firstChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "4 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before($target, $doc->documentElement->lastChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "5 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before($doc->documentElement->lastChild, $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "6 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before($target, $doc->documentElement->firstChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "7 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before($doc->documentElement->firstChild, $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "8 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before('bar','baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "9 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before('bar','baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "10 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before($target, 'bar','baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "11 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before('bar', $target, 'baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "12 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before('bar', 'baz', $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "13 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
|
||||
@@ -93,19 +93,19 @@ $doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before($target, 'bar','baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "14 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before('bar', $target, 'baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "15 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before('bar', 'baz', $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "16 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
|
||||
@@ -113,21 +113,21 @@ $doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before('bar', $target, $doc->documentElement->lastChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "17 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before($target, 'bar', $doc->documentElement->lastChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "18 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->before($target, $doc->documentElement->lastChild, 'bar');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "19 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
|
||||
@@ -136,43 +136,43 @@ $doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before('bar', $doc->documentElement->firstChild, $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "20 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before($doc->documentElement->firstChild, 'bar', $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "21 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before($doc->documentElement->firstChild, $target, 'bar');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "22 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
<a>foo<last/></a>
|
||||
<a>foo<last/></a>
|
||||
<a><last/>foo</a>
|
||||
<a>foo<last/></a>
|
||||
<a>foo<last/></a>
|
||||
<a><last/>foo</a>
|
||||
<a><last/>foo</a>
|
||||
<a>foo<last/></a>
|
||||
<a>barbazfoo<last/></a>
|
||||
<a>foobarbaz<last/></a>
|
||||
<a>foobarbaz<last/></a>
|
||||
<a>barfoobaz<last/></a>
|
||||
<a>barbazfoo<last/></a>
|
||||
<a>foo<last/>barbaz</a>
|
||||
<a>foobar<last/>baz</a>
|
||||
<a>foobarbaz<last/></a>
|
||||
<a>barfoo<last/></a>
|
||||
<a>foobar<last/></a>
|
||||
<a>foo<last/>bar</a>
|
||||
<a>barfoo<last/></a>
|
||||
<a>foobar<last/></a>
|
||||
<a>foo<last/>bar</a>
|
||||
1 <a>foo<last/></a>
|
||||
2 <a>foo<last/></a>
|
||||
3 <a><last/>foo</a>
|
||||
4 <a>foo<last/></a>
|
||||
5 <a>foo<last/></a>
|
||||
6 <a><last/>foo</a>
|
||||
7 <a><last/>foo</a>
|
||||
8 <a>foo<last/></a>
|
||||
9 <a>barbazfoo<last/></a>
|
||||
10 <a>foobarbaz<last/></a>
|
||||
11 <a>foobarbaz<last/></a>
|
||||
12 <a>barfoobaz<last/></a>
|
||||
13 <a>barbazfoo<last/></a>
|
||||
14 <a>foo<last/>barbaz</a>
|
||||
15 <a>foobar<last/>baz</a>
|
||||
16 <a>foobarbaz<last/></a>
|
||||
17 <a>barfoo<last/></a>
|
||||
18 <a>foobar<last/></a>
|
||||
19 <a>foo<last/>bar</a>
|
||||
20 <a>barfoo<last/></a>
|
||||
21 <a>foobar<last/></a>
|
||||
22 <a>foo<last/>bar</a>
|
||||
|
||||
@@ -8,84 +8,84 @@ $doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after($target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "1 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after($target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "2 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after($doc->documentElement->lastChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "3 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after($doc->documentElement->firstChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "4 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after($target, $doc->documentElement->lastChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "5 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after($doc->documentElement->lastChild, $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "6 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after($target, $doc->documentElement->firstChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "7 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after($doc->documentElement->firstChild, $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "8 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after('bar','baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "9 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after('bar','baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "10 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after($target, 'bar','baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "11 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after('bar', $target, 'baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "12 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after('bar', 'baz', $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "13 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
|
||||
@@ -93,19 +93,19 @@ $doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after($target, 'bar','baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "14 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after('bar', $target, 'baz');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "15 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after('bar', 'baz', $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "16 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
|
||||
@@ -113,21 +113,21 @@ $doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after('bar', $target, $doc->documentElement->lastChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "17 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after($target, 'bar', $doc->documentElement->lastChild);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "18 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->firstChild;
|
||||
$target->after($target, $doc->documentElement->lastChild, 'bar');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "19 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
|
||||
@@ -136,43 +136,43 @@ $doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after('bar', $doc->documentElement->firstChild, $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "20 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after($doc->documentElement->firstChild, 'bar', $target);
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "21 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->after($doc->documentElement->firstChild, $target, 'bar');
|
||||
echo $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
echo "22 ", $doc->saveXML($doc->documentElement).PHP_EOL;
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
<a>foo<last/></a>
|
||||
<a>foo<last/></a>
|
||||
<a>foo<last/></a>
|
||||
<a><last/>foo</a>
|
||||
<a>foo<last/></a>
|
||||
<a><last/>foo</a>
|
||||
<a><last/>foo</a>
|
||||
<a>foo<last/></a>
|
||||
<a>foobarbaz<last/></a>
|
||||
<a>foo<last/>barbaz</a>
|
||||
<a>foobarbaz<last/></a>
|
||||
<a>barfoobaz<last/></a>
|
||||
<a>barbazfoo<last/></a>
|
||||
<a>foo<last/>barbaz</a>
|
||||
<a>foobar<last/>baz</a>
|
||||
<a>foobarbaz<last/></a>
|
||||
<a>barfoo<last/></a>
|
||||
<a>foobar<last/></a>
|
||||
<a>foo<last/>bar</a>
|
||||
<a>barfoo<last/></a>
|
||||
<a>foobar<last/></a>
|
||||
<a>foo<last/>bar</a>
|
||||
1 <a>foo<last/></a>
|
||||
2 <a>foo<last/></a>
|
||||
3 <a>foo<last/></a>
|
||||
4 <a><last/>foo</a>
|
||||
5 <a>foo<last/></a>
|
||||
6 <a><last/>foo</a>
|
||||
7 <a><last/>foo</a>
|
||||
8 <a>foo<last/></a>
|
||||
9 <a>foobarbaz<last/></a>
|
||||
10 <a>foo<last/>barbaz</a>
|
||||
11 <a>foobarbaz<last/></a>
|
||||
12 <a>barfoobaz<last/></a>
|
||||
13 <a>barbazfoo<last/></a>
|
||||
14 <a>foo<last/>barbaz</a>
|
||||
15 <a>foobar<last/>baz</a>
|
||||
16 <a>foobarbaz<last/></a>
|
||||
17 <a>barfoo<last/></a>
|
||||
18 <a>foobar<last/></a>
|
||||
19 <a>foo<last/>bar</a>
|
||||
20 <a>barfoo<last/></a>
|
||||
21 <a>foobar<last/></a>
|
||||
22 <a>foo<last/>bar</a>
|
||||
|
||||
120
ext/dom/tests/bug80602_3.phpt
Normal file
120
ext/dom/tests/bug80602_3.phpt
Normal file
@@ -0,0 +1,120 @@
|
||||
--TEST--
|
||||
Bug #80602 (Segfault when using DOMChildNode::before()) - use-after-free variation
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
$target->before('bar', $doc->documentElement->firstChild, 'baz');
|
||||
echo $doc->saveXML($doc->documentElement), "\n";
|
||||
var_dump($target);
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/></a>');
|
||||
$target = $doc->documentElement->lastChild;
|
||||
// Note: after instead of before
|
||||
$target->after('bar', $doc->documentElement->firstChild, 'baz');
|
||||
echo $doc->saveXML($doc->documentElement), "\n";
|
||||
var_dump($target);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
<a>barfoobaz<last/></a>
|
||||
object(DOMElement)#3 (23) {
|
||||
["schemaTypeInfo"]=>
|
||||
NULL
|
||||
["tagName"]=>
|
||||
string(4) "last"
|
||||
["firstElementChild"]=>
|
||||
NULL
|
||||
["lastElementChild"]=>
|
||||
NULL
|
||||
["childElementCount"]=>
|
||||
int(0)
|
||||
["previousElementSibling"]=>
|
||||
NULL
|
||||
["nextElementSibling"]=>
|
||||
NULL
|
||||
["nodeName"]=>
|
||||
string(4) "last"
|
||||
["nodeValue"]=>
|
||||
string(0) ""
|
||||
["nodeType"]=>
|
||||
int(1)
|
||||
["parentNode"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["childNodes"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["firstChild"]=>
|
||||
NULL
|
||||
["lastChild"]=>
|
||||
NULL
|
||||
["previousSibling"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["nextSibling"]=>
|
||||
NULL
|
||||
["attributes"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["ownerDocument"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["namespaceURI"]=>
|
||||
NULL
|
||||
["prefix"]=>
|
||||
string(0) ""
|
||||
["localName"]=>
|
||||
string(4) "last"
|
||||
["baseURI"]=>
|
||||
string(%d) %s
|
||||
["textContent"]=>
|
||||
string(0) ""
|
||||
}
|
||||
<a><last/>barfoobaz</a>
|
||||
object(DOMElement)#2 (23) {
|
||||
["schemaTypeInfo"]=>
|
||||
NULL
|
||||
["tagName"]=>
|
||||
string(4) "last"
|
||||
["firstElementChild"]=>
|
||||
NULL
|
||||
["lastElementChild"]=>
|
||||
NULL
|
||||
["childElementCount"]=>
|
||||
int(0)
|
||||
["previousElementSibling"]=>
|
||||
NULL
|
||||
["nextElementSibling"]=>
|
||||
NULL
|
||||
["nodeName"]=>
|
||||
string(4) "last"
|
||||
["nodeValue"]=>
|
||||
string(0) ""
|
||||
["nodeType"]=>
|
||||
int(1)
|
||||
["parentNode"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["childNodes"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["firstChild"]=>
|
||||
NULL
|
||||
["lastChild"]=>
|
||||
NULL
|
||||
["previousSibling"]=>
|
||||
NULL
|
||||
["nextSibling"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["attributes"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["ownerDocument"]=>
|
||||
string(22) "(object value omitted)"
|
||||
["namespaceURI"]=>
|
||||
NULL
|
||||
["prefix"]=>
|
||||
string(0) ""
|
||||
["localName"]=>
|
||||
string(4) "last"
|
||||
["baseURI"]=>
|
||||
string(%d) %s
|
||||
["textContent"]=>
|
||||
string(0) ""
|
||||
}
|
||||
33
ext/dom/tests/bug80602_4.phpt
Normal file
33
ext/dom/tests/bug80602_4.phpt
Normal file
@@ -0,0 +1,33 @@
|
||||
--TEST--
|
||||
Bug #80602 (Segfault when using DOMChildNode::before()) - after text merge variation
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML('<a>foo<last/>bar</a>');
|
||||
$foo = $doc->firstChild->firstChild;
|
||||
$bar = $doc->firstChild->lastChild;
|
||||
|
||||
$foo->after($bar);
|
||||
|
||||
var_dump($doc->saveXML());
|
||||
|
||||
$foo->nodeValue = "x";
|
||||
|
||||
var_dump($doc->saveXML());
|
||||
|
||||
$bar->nodeValue = "y";
|
||||
|
||||
var_dump($doc->saveXML());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(43) "<?xml version="1.0"?>
|
||||
<a>foobar<last/></a>
|
||||
"
|
||||
string(41) "<?xml version="1.0"?>
|
||||
<a>xbar<last/></a>
|
||||
"
|
||||
string(39) "<?xml version="1.0"?>
|
||||
<a>xy<last/></a>
|
||||
"
|
||||
67
ext/dom/tests/gh11288.phpt
Normal file
67
ext/dom/tests/gh11288.phpt
Normal file
@@ -0,0 +1,67 @@
|
||||
--TEST--
|
||||
GH-11288 (Error: Couldn't fetch DOMElement introduced in 8.2.6, 8.1.19)
|
||||
--FILE--
|
||||
<?php
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<span class="unwrap_me"><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></span>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML($html);
|
||||
|
||||
$spans = iterator_to_array($dom->getElementsByTagName('span')->getIterator());
|
||||
foreach ($spans as $span) {
|
||||
if ('unwrap_me' === $span->getAttribute('class')) {
|
||||
$fragment = $dom->createDocumentFragment();
|
||||
$fragment->append(...$span->childNodes);
|
||||
$span->parentNode?->replaceChild($fragment, $span);
|
||||
}
|
||||
}
|
||||
|
||||
var_dump(str_replace("\n", "", $dom->saveHTML()));
|
||||
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<span class="unwrap_me"><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></span>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML($html);
|
||||
|
||||
$spans = iterator_to_array($dom->getElementsByTagName('span')->getIterator());
|
||||
foreach ($spans as $span) {
|
||||
if ('unwrap_me' === $span->getAttribute('class')) {
|
||||
$span->replaceWith(...$span->childNodes);
|
||||
}
|
||||
}
|
||||
|
||||
var_dump(str_replace("\n", "", $dom->saveHTML()));
|
||||
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<span class="unwrap_me"><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></span>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML($html);
|
||||
|
||||
$spans = iterator_to_array($dom->getElementsByTagName('span')->getIterator());
|
||||
foreach ($spans as $span) {
|
||||
if ('unwrap_me' === $span->getAttribute('class')) {
|
||||
$span->replaceWith('abc');
|
||||
}
|
||||
}
|
||||
|
||||
var_dump(str_replace("\n", "", $dom->saveHTML()));
|
||||
?>
|
||||
--EXPECT--
|
||||
string(108) "<!DOCTYPE HTML><html><body><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></body></html>"
|
||||
string(108) "<!DOCTYPE HTML><html><body><i><span class="foo">Lorem</span></i><span class="foo">ipsum</span></body></html>"
|
||||
string(44) "<!DOCTYPE HTML><html><body>abc</body></html>"
|
||||
28
ext/dom/tests/gh11289.phpt
Normal file
28
ext/dom/tests/gh11289.phpt
Normal file
@@ -0,0 +1,28 @@
|
||||
--TEST--
|
||||
GH-11289 (DOMException: Not Found Error introduced in 8.2.6, 8.1.19)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div></div>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML($html);
|
||||
|
||||
$divs = iterator_to_array($dom->getElementsByTagName('div')->getIterator());
|
||||
foreach ($divs as $div) {
|
||||
$fragment = $dom->createDocumentFragment();
|
||||
$fragment->appendXML('<p>Hi!</p>');
|
||||
$div->replaceWith(...$fragment->childNodes);
|
||||
}
|
||||
|
||||
var_dump(str_replace("\n", "", $dom->saveHTML()));
|
||||
?>
|
||||
--EXPECT--
|
||||
string(55) "<!DOCTYPE HTML><html><body> <p>Hi!</p></body></html>"
|
||||
27
ext/dom/tests/gh11290.phpt
Normal file
27
ext/dom/tests/gh11290.phpt
Normal file
@@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
GH-11290 (DOMElement::replaceWith causes crash)
|
||||
--FILE--
|
||||
<?php
|
||||
$html = <<<HTML
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<p><span class="unwrap_me">Lorem</span><span class="unwrap_me">ipsum</span><span class="unwrap_me">dolor</span></p>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML($html);
|
||||
|
||||
$spans = iterator_to_array($dom->getElementsByTagName('span')->getIterator());
|
||||
foreach ($spans as $span) {
|
||||
if ('unwrap_me' === $span->getAttribute('class')) {
|
||||
$span->replaceWith(...$span->childNodes);
|
||||
}
|
||||
}
|
||||
|
||||
var_dump(str_replace("\n", "", $dom->saveHTML()));
|
||||
?>
|
||||
--EXPECT--
|
||||
string(67) "<!DOCTYPE HTML><html><body> <p>Loremipsumdolor</p></body></html>"
|
||||
20
ext/dom/tests/gh9142.phpt
Normal file
20
ext/dom/tests/gh9142.phpt
Normal file
@@ -0,0 +1,20 @@
|
||||
--TEST--
|
||||
GH-9142 (DOMChildNode replaceWith() double-free error when replacing elements not separated by any whitespace)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$document = '<var>One</var><var>Two</var>';
|
||||
|
||||
($dom = new DOMDocument('1.0', 'UTF-8'))->loadHTML($document);
|
||||
|
||||
foreach ((new DOMXPath($dom))->query('//var') as $var) {
|
||||
$var->replaceWith($dom->createElement('p', $var->nodeValue));
|
||||
}
|
||||
|
||||
var_dump($dom->saveHTML());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(154) "<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<html><body><p>One</p><p>Two</p></body></html>
|
||||
"
|
||||
Reference in New Issue
Block a user