aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2025-10-26 22:35:11 +0100
committerGravatar GitHub <noreply@github.com> 2025-10-26 22:35:11 +0100
commit6440f9c9a91160103b7c2c369761ada31926c02a (patch)
tree0af0d1b3a8d392d81dbac65a002267e3d8ff6446 /app
parent1217b6de34cc5f23cc73d8d37a51c4616a3780ab (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')
-rw-r--r--app/Models/Entry.php70
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)) {