diff options
| author | 2025-10-26 22:35:11 +0100 | |
|---|---|---|
| committer | 2025-10-26 22:35:11 +0100 | |
| commit | 6440f9c9a91160103b7c2c369761ada31926c02a (patch) | |
| tree | 0af0d1b3a8d392d81dbac65a002267e3d8ff6446 /app/Models/Entry.php | |
| parent | 1217b6de34cc5f23cc73d8d37a51c4616a3780ab (diff) | |
Fix DOM fatal error while filtering retrieved full content (#8161)
https://github.com/FreshRSS/FreshRSS/pull/8132 was not sufficient.
Fix *PHP Fatal error: Uncaught Error: Couldn't fetch DOMElement. Node no longer exists*
Diffstat (limited to 'app/Models/Entry.php')
| -rw-r--r-- | app/Models/Entry.php | 70 |
1 files changed, 47 insertions, 23 deletions
diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 13fcae4cf..62d4019d8 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -961,25 +961,37 @@ HTML; if ($nodes != false) { $filter_xpath = $path_entries_filter === '' ? '' : (new Gt\CssXPath\Translator($path_entries_filter, 'descendant-or-self::'))->asXPath(); foreach ($nodes as $node) { - if (!($node instanceof DOMElement)) { - continue; - } - if ($filter_xpath !== '' && ($filterednodes = $xpath->query($filter_xpath, $node)) !== false) { - // Remove unwanted elements once before sanitizing, for CSS selectors to also match original content - foreach ($filterednodes as $filterednode) { - if ($filterednode === $node) { - continue 2; - } - if (!($filterednode instanceof DOMElement) || $filterednode->parentNode === null) { - continue; + try { + if (!($node instanceof DOMElement)) { + continue; + } + if ($filter_xpath !== '' && ($filterednodes = $xpath->query($filter_xpath, $node)) !== false) { + // Remove unwanted elements once before sanitizing, for CSS selectors to also match original content + foreach ($filterednodes as $filterednode) { + try { + if ($filterednode === $node) { + continue 2; + } + if (!($filterednode instanceof DOMElement) || $filterednode->ownerDocument !== $doc || $filterednode->parentNode === null) { + continue; + } + $filterednode->remove(); + } catch (Error $e) { // @phpstan-ignore catch.neverThrown + if (!str_contains($e->getMessage(), 'Node no longer exists')) { + throw $e; + } + } } - $filterednode->parentNode->removeChild($filterednode); + } + if ($node->ownerDocument !== $doc || $node->parentNode === null) { + continue; + } + $html .= $doc->saveHTML($node) . "\n"; + } catch (Error $e) { + if (!str_contains($e->getMessage(), 'Node no longer exists')) { + throw $e; } } - if ($node->parentNode === null) { - continue; - } - $html .= $doc->saveHTML($node) . "\n"; } } @@ -995,11 +1007,17 @@ HTML; $xpath = new DOMXPath($doc); $filterednodes = $xpath->query((new Gt\CssXPath\Translator($path_entries_filter, '//'))->asXPath()) ?: []; foreach ($filterednodes as $filterednode) { - if (!($filterednode instanceof DOMElement) || $filterednode->parentNode === null) { - continue; + try { + if (!($filterednode instanceof DOMElement) || $filterednode->ownerDocument !== $doc || $filterednode->parentNode === null) { + continue; + } + $filterednode->remove(); + $modified = true; + } catch (Error $e) { // @phpstan-ignore catch.neverThrown + if (!str_contains($e->getMessage(), 'Node no longer exists')) { + throw $e; + } } - $filterednode->parentNode->removeChild($filterednode); - $modified = true; } if ($modified) { $html = $doc->saveHTML($doc->getElementsByTagName('body')->item(0) ?? $doc->firstElementChild) ?: $html; @@ -1067,10 +1085,16 @@ HTML; $xpath = new DOMXPath($doc); $filterednodes = $xpath->query((new Gt\CssXPath\Translator($feed->attributeString('path_entries_filter'), '//'))->asXPath()) ?: []; foreach ($filterednodes as $filterednode) { - if (!($filterednode instanceof DOMElement) || $filterednode->parentNode === null) { - continue; + try { + if (!($filterednode instanceof DOMElement) || $filterednode->ownerDocument !== $doc || $filterednode->parentNode === null) { + continue; + } + $filterednode->remove(); + } catch (Error $e) { // @phpstan-ignore catch.neverThrown + if (!str_contains($e->getMessage(), 'Node no longer exists')) { + throw $e; + } } - $filterednode->parentNode->removeChild($filterednode); } $html = $doc->saveHTML($doc->getElementsByTagName('body')->item(0) ?? $doc->firstElementChild); if (!is_string($html)) { |
