Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/test-linux/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ runs:
--offline \
--show-diff \
--show-slow 1000 \
--set-timeout 120
--set-timeout 120 ext/dom
- uses: actions/upload-artifact@v3
if: always() && inputs.testArtifacts != null
with:
Expand Down
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ PHP NEWS
. Fixed bug GH-11507 (String concatenation performance regression in 8.3).
(nielsdos)

- DOM:
. Implemented DOMDocument::adoptNode(). Previously this always threw a
"not yet implemented" exception. (nielsdos)

- Fileinfo:
. Fix GH-11408 (Unable to build PHP 8.3.0 alpha 1 / fileinfo extension).
(nielsdos)
Expand Down
2 changes: 2 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ PHP 8.3 UPGRADE NOTES

- Dom:
. Changed DOMCharacterData::appendData() tentative return type to true.
. Implemented DOMDocument::adoptNode(). Previously this always threw a
"not yet implemented" exception.

- Gd:
. Changed imagerotate signature, removed the `ignore_transparent` argument
Expand Down
63 changes: 59 additions & 4 deletions ext/dom/document.c
Original file line number Diff line number Diff line change
Expand Up @@ -1051,18 +1051,73 @@ PHP_METHOD(DOMDocument, getElementById)
}
/* }}} end dom_document_get_element_by_id */

static void php_dom_transfer_document_ref(xmlNodePtr node, dom_object *dom_object_document, xmlDocPtr document)
{
if (node->children) {
php_dom_transfer_document_ref(node->children, dom_object_document, document);
}
while (node) {
php_libxml_node_ptr *iteration_object_ptr = node->_private;
if (iteration_object_ptr) {
php_libxml_node_object *iteration_object = iteration_object_ptr->_private;
ZEND_ASSERT(iteration_object != NULL);
/* Must increase refcount first because we could be the last reference holder, and the document may be equal. */
dom_object_document->document->refcount++;
php_libxml_decrement_doc_ref(iteration_object);
iteration_object->document = dom_object_document->document;
}
node = node->next;
}
}

/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-Document3-adoptNode
Since: DOM Level 3
Modern spec URL: https://dom.spec.whatwg.org/#dom-document-adoptnode
*/
PHP_METHOD(DOMDocument, adoptNode)
{
zval *nodep = NULL;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &nodep, dom_node_class_entry) == FAILURE) {
zval *node_zval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &node_zval, dom_node_class_entry) == FAILURE) {
RETURN_THROWS();
}

DOM_NOT_IMPLEMENTED();
xmlNodePtr nodep;
dom_object *dom_object_nodep;
DOM_GET_OBJ(nodep, node_zval, xmlNodePtr, dom_object_nodep);

if (UNEXPECTED(nodep->type == XML_DOCUMENT_NODE
|| nodep->type == XML_HTML_DOCUMENT_NODE
|| nodep->type == XML_DOCUMENT_TYPE_NODE
|| nodep->type == XML_DTD_NODE
|| nodep->type == XML_ENTITY_NODE
|| nodep->type == XML_NOTATION_NODE)) {
php_dom_throw_error(NOT_SUPPORTED_ERR, true);
return;
}

xmlDocPtr new_document;
dom_object *dom_object_new_document;
zval *new_document_zval = ZEND_THIS;
DOM_GET_OBJ(new_document, new_document_zval, xmlDocPtr, dom_object_new_document);

php_libxml_invalidate_node_list_cache_from_doc(nodep->doc);

if (nodep->doc != new_document) {
php_libxml_invalidate_node_list_cache_from_doc(new_document);

/* Note for ATTRIBUTE_NODE: specified is always true in ext/dom,
* and since this unlink it; the owner element will be unset (i.e. parentNode). */
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ws issue

int ret = xmlDOMWrapAdoptNode(NULL, nodep->doc, nodep, new_document, NULL, /* options, unused */ 0);
if (UNEXPECTED(ret != 0)) {
RETURN_FALSE;
}

php_dom_transfer_document_ref(nodep, dom_object_new_document, new_document);
} else {
xmlUnlinkNode(nodep);
}

RETURN_OBJ_COPY(&dom_object_nodep->std);
}
/* }}} end dom_document_adopt_node */

Expand Down
137 changes: 130 additions & 7 deletions ext/dom/tests/DOMDocument_adoptNode.phpt
Original file line number Diff line number Diff line change
@@ -1,18 +1,141 @@
--TEST--
DOMDocument::adoptNode not implemented
Tests DOMDocument::adoptNode()
--EXTENSIONS--
dom
--FILE--
<?php

$dom = new DOMDocument();
$dom->loadXML("<root />");
$doc1 = new DOMDocument();
$doc1->loadXML("<p><b>hi<i attrib=\"1\">x</i></b>world</p>");
$doc2 = new DOMDocument();
$doc2->loadXML("<div/>");

$b_tag_element = $doc1->firstChild->firstChild;
$i_tag_element = $b_tag_element->lastChild;

echo "-- Owner document check before adopting --\n";
var_dump($i_tag_element->ownerDocument === $doc1);
var_dump($i_tag_element->ownerDocument === $doc2);

echo "-- Trying to append child from other document --\n";
try {
$dom->adoptNode($dom->documentElement);
} catch (\Error $e) {
echo $e->getMessage() . \PHP_EOL;
$doc2->firstChild->appendChild($b_tag_element); // Should fail because it's another document
} catch (\DOMException $e) {
echo $e->getMessage(), "\n";
}

echo "-- Adopting --\n";
$adopted = $doc2->adoptNode($b_tag_element);
var_dump($adopted->textContent);
var_dump($doc1->saveXML());
var_dump($doc2->saveXML());

echo "-- Appending the adopted node --\n";

$doc2->firstChild->appendChild($adopted);
var_dump($doc2->saveXML());
var_dump($i_tag_element->ownerDocument === $doc1);
var_dump($i_tag_element->ownerDocument === $doc2);

echo "-- Adopt node to the original document --\n";

$adopted = $doc1->adoptNode($doc1->firstChild->firstChild);
var_dump($adopted->textContent);
var_dump($doc1->saveXML());

echo "-- Adopt a document --\n";

try {
$doc1->adoptNode($doc1);
} catch (\DOMException $e) {
echo $e->getMessage(), "\n";
}

echo "-- Adopt an attribute --\n";

$doc3 = new DOMDocument();
$doc3->loadXML('<p align="center">hi</p>');
$attribute = $doc3->firstChild->attributes->item(0);
var_dump($attribute->parentNode !== NULL);
$adopted = $doc3->adoptNode($attribute);
var_dump($adopted->parentNode === NULL);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ook ergens appenden en uitprinten


echo "-- Adopt an entity reference --\n";

$doc4 = new DOMDocument();
$doc4->loadXML(<<<'XML'
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE set PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN" "http://www.docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY my_entity '<p>hi</p>'> ]>
<p/>
XML, LIBXML_NOENT);
$p_tag_element = $doc4->firstChild->nextSibling;
$entity_reference = $doc4->createEntityReference('my_entity');
$p_tag_element->appendChild($entity_reference);
var_dump($doc4->saveXML());
$doc3->adoptNode($entity_reference);
var_dump($doc4->saveXML());
$doc3->firstChild->appendChild($entity_reference);
var_dump($doc3->saveXML());

echo "-- Adopt a node and destroy the new document --\n";
$doc1 = new DOMDocument();
$doc1->appendChild($doc1->createElement('child'));
$doc2 = new DOMDocument();
$doc2->appendChild($doc2->createElement('container'));
$doc2->documentElement->appendChild($child = $doc2->adoptNode($doc1->documentElement));
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ook docs uitprinten

unset($doc2);
var_dump($child->nodeName);
unset($doc1);
var_dump($child->nodeName);

?>
--EXPECT--
Not yet implemented
-- Owner document check before adopting --
bool(true)
bool(false)
-- Trying to append child from other document --
Wrong Document Error
-- Adopting --
string(3) "hix"
string(35) "<?xml version="1.0"?>
<p>world</p>
"
string(29) "<?xml version="1.0"?>
<div/>
"
-- Appending the adopted node --
string(62) "<?xml version="1.0"?>
<div><b>hi<i attrib="1">x</i></b></div>
"
bool(false)
bool(true)
-- Adopt node to the original document --
string(5) "world"
string(27) "<?xml version="1.0"?>
<p/>
"
-- Adopt a document --
Not Supported Error
-- Adopt an attribute --
bool(true)
bool(true)
-- Adopt an entity reference --
string(202) "<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE set PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN" "http://www.docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY my_entity "<p>hi</p>">
]>
<p>&my_entity;</p>
"
string(188) "<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE set PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN" "http://www.docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY my_entity "<p>hi</p>">
]>
<p/>
"
string(43) "<?xml version="1.0"?>
<p>hi&my_entity;</p>
"
-- Adopt a node and destroy the new document --
string(5) "child"
string(5) "child"