From e2460c320ed13d9c367b25c1215dd1860f03c6bd Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Thu, 25 Apr 2024 17:31:13 +0100 Subject: [PATCH] Prevent DocumentFragment from causing internal PHP error by using append() (#454) * fix: DocumentFragment append does not cause error closes #453 * ci: try dev master branch * ci: try dev master branch * test: satisfy phpstan * ci: upgrade phpunit to v4 --- .github/workflows/ci.yml | 2 +- src/ParentNode.php | 12 +++++++++--- test/phpunit/DocumentFragmentTest.php | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d198ecd1..49a4fdb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: run: tar -xvf /tmp/github-actions/build.tar ./ - name: PHP Unit tests - uses: php-actions/phpunit@v3 + uses: php-actions/phpunit@v4 env: XDEBUG_MODE: cover with: diff --git a/src/ParentNode.php b/src/ParentNode.php index 8997ee86..2325c311 100644 --- a/src/ParentNode.php +++ b/src/ParentNode.php @@ -60,13 +60,19 @@ protected function __prop_get_children():HTMLCollection { * returns the appended Node object. * + Element.append() can append several nodes and strings, whereas * Node.appendChild() can only append one node. - * @param Node|Element|Text|Comment|string...$nodes + * @param Node|Element|Text|Comment|DocumentFragment|string...$nodes */ public function append(...$nodes):void { // Without this clumsy iteration, PHP 8.1 throws "free(): double free detected in tcache 2" foreach($nodes as $node) { - /** @phpstan-ignore-next-line libxml's DOMNode does not define append() */ - parent::append($node); +// And without this clumsy if/else, PHP 8.3 throws "double free or corruption (!prev)" + if(is_string($node)) { + /** @phpstan-ignore-next-line libxml's DOMNode does not define append() */ + parent::append($node); + } + else { + parent::appendChild($node); + } } } diff --git a/test/phpunit/DocumentFragmentTest.php b/test/phpunit/DocumentFragmentTest.php index 8ef87f9b..2dd91ed0 100644 --- a/test/phpunit/DocumentFragmentTest.php +++ b/test/phpunit/DocumentFragmentTest.php @@ -21,4 +21,18 @@ public function testGetElementById():void { $sut->appendChild($nodeWithId); self::assertSame($nodeWithId, $sut->getElementById("test")); } + + public function testAppendMultipleNodesThenAddToParentElement():void { + $document = new HTMLDocument(); + $sut = $document->createDocumentFragment(); + $expectedString = ""; + for($i = 0; $i < 10; $i++) { + $textNode = $document->createTextNode("Node$i"); + $sut->append($textNode); + $expectedString .= "Node$i"; + } + + $document->documentElement->append($sut); + self::assertSame($expectedString, $document->textContent); + } }