From d53f6b58b32769f7f5d8a0131c061bf603211906 Mon Sep 17 00:00:00 2001 From: divinity76 Date: Sun, 17 Mar 2024 23:46:20 +0100 Subject: [PATCH 1/4] [1.10] Fix xpath php-string-to-javascript-string (#576) * fix xpath php-string-to-javascript-string TL;DR: addslashes() is not the correct way to convert a php-string to a javascript string. json_encode() is. For example, addslashes will fail on the PHP string "foo".chr(10)."bar" , the old addslashes() will convert it into "foo bar" which is a javascript syntax error. Previously this code would fail: $str = "foo".chr(10)."bar"; $xps = new XPathSelector("//span[contains(text(),'" . $str . "')]"); var_dump($xps->expressionCount()); it would generate a javascript syntax error: string(134) "document.evaluate("//span[contains(text(),\'foo bar\')]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshot Length" now it generates legal javascript: string(135) "document.evaluate("\/\/span[contains(text(),'foo\nbar')]", document , null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength" * styling * prettier run-time error messages --- src/Dom/Selector/XPathSelector.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Dom/Selector/XPathSelector.php b/src/Dom/Selector/XPathSelector.php index 5d984def..71981ee2 100644 --- a/src/Dom/Selector/XPathSelector.php +++ b/src/Dom/Selector/XPathSelector.php @@ -19,18 +19,11 @@ public function __construct(string $expression) public function expressionCount(): string { - return \sprintf( - 'document.evaluate("%s", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength', - \addslashes($this->expression) - ); + return 'document.evaluate('.\json_encode($this->expression, \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE).', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength'; } public function expressionFindOne(int $position): string { - return \sprintf( - 'document.evaluate("%s[%d]", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue', - \addslashes($this->expression), - $position - ); + return 'document.evaluate('.\json_encode($this->expression."[{$position}]", \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE).', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue'; } } From e0b45865d5626bb7a458a83eb39fd56f0da71df8 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sun, 17 Mar 2024 22:46:28 +0000 Subject: [PATCH 2/4] Apply fixes from StyleCI --- src/Page.php | 2 +- src/PageUtils/PageNavigation.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Page.php b/src/Page.php index 0ee66595..3e7913e9 100644 --- a/src/Page.php +++ b/src/Page.php @@ -448,7 +448,7 @@ private function waitForReloadGenerator($eventName, $loaderId) yield $delay; - // else if frame has still the previous loader, wait for the new one + // else if frame has still the previous loader, wait for the new one } else { yield $delay; } diff --git a/src/PageUtils/PageNavigation.php b/src/PageUtils/PageNavigation.php index aa45010b..edc2cd8e 100644 --- a/src/PageUtils/PageNavigation.php +++ b/src/PageUtils/PageNavigation.php @@ -171,16 +171,16 @@ private function navigationComplete($eventName) if ($this->page->hasLifecycleEvent($eventName)) { return true; - // or else just wait for the new event to trigger + // or else just wait for the new event to trigger } else { yield $delay; } - // else if frame has still the previous loader, wait for the new one + // else if frame has still the previous loader, wait for the new one } elseif ($this->frame->getLatestLoaderId() == $this->previousLoaderId) { yield $delay; - // else if a new loader is present that means that a new navigation started + // else if a new loader is present that means that a new navigation started } else { // if strict then throw or else replace the old navigation with the new one if ($this->strict) { From 269ae8ca9149e7ce9d4a9d5af9f842c8653d835a Mon Sep 17 00:00:00 2001 From: divinity76 Date: Sun, 17 Mar 2024 23:46:51 +0100 Subject: [PATCH 3/4] add "use HeadlessChromium\Dom\Selector\XPathSelector;" (#573) makes it easier to follow sample code, i had to look it up in the source code myself. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5e08f939..1cacdd9d 100644 --- a/README.md +++ b/README.md @@ -799,6 +799,8 @@ selectors, you can pass an instance of the required `Selector`. Wait for element by XPath selector: ```php +use HeadlessChromium\Dom\Selector\XPathSelector; + $page = $browser->createPage(); $page->navigate('http://example.com')->waitForNavigation(); From ee45a7b3d1af9a48b0946da5863749b541fa489b Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sun, 17 Mar 2024 22:49:33 +0000 Subject: [PATCH 4/4] Release 1.10.1 --- CHANGELOG.md | 5 +++++ LICENSE | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5d7c702..15f732ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # CHANGELOG +## 1.10.1 (2024-03-17) + +* Fixed encoding bugs in `XPathSelector` + + ## 1.10.0 (2023-12-10) * Add `Add Node::setHTML` method diff --git a/LICENSE b/LICENSE index 269b2393..664d299c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,8 @@ The MIT License (MIT) Copyright (c) 2017-2020 Soufiane Ghzal -Copyright (c) 2020-2023 Graham Campbell -Copyright (c) 2020-2023 Enrico Dias +Copyright (c) 2020-2024 Graham Campbell +Copyright (c) 2020-2024 Enrico Dias Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal