Commit d1fdbbacfb1 for php
commit d1fdbbacfb10cca1361fb4fdcabc5d2c9d4433bf
Author: Keyvan Minoukadeh <fivefilters@fivefilters.org>
Date: Mon Oct 12 02:11:43 2026 +0200
Fix GH-24260: querySelectorAll() returns duplicate elements for selector lists
Close GH-24267
diff --git a/NEWS b/NEWS
index a6c157395c9..4b34324de64 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,8 @@ PHP NEWS
- DOM:
. Fixed bug GH-23352 (UAF reading an attribute value node retained across
DOMDocument::adoptNode()). (David Carlier)
+ . Fixed bug GH-24260 (querySelectorAll() returns duplicate elements for
+ selector lists). (fivefilters)
- FPM:
. Fixed bug GH-24229 (fcgi_close() passes shutdown() a literal 1, which is
diff --git a/ext/dom/parentnode/css_selectors.c b/ext/dom/parentnode/css_selectors.c
index 37f9d698e85..43012c4ebb9 100644
--- a/ext/dom/parentnode/css_selectors.c
+++ b/ext/dom/parentnode/css_selectors.c
@@ -240,7 +240,7 @@ void dom_parent_node_query_selector_all(xmlNodePtr thisp, dom_object *intern, zv
selectors_str,
dom_query_selector_find_array_callback,
&ctx,
- LXB_SELECTORS_OPT_DEFAULT
+ LXB_SELECTORS_OPT_MATCH_FIRST
) != LXB_STATUS_OK) {
zend_array_destroy(list);
RETURN_THROWS();
diff --git a/ext/dom/tests/modern/css_selectors/gh24260.phpt b/ext/dom/tests/modern/css_selectors/gh24260.phpt
new file mode 100644
index 00000000000..d1c40806729
--- /dev/null
+++ b/ext/dom/tests/modern/css_selectors/gh24260.phpt
@@ -0,0 +1,29 @@
+--TEST--
+GH-24260 (querySelectorAll() returns duplicate elements for selector lists)
+--EXTENSIONS--
+dom
+--FILE--
+<?php
+
+$dom = Dom\HTMLDocument::createFromString(
+ '<!DOCTYPE html><div><p class="a b">one</p><p class="b">two</p></div>'
+);
+
+foreach ([$dom, $dom->querySelector('div')] as $context) {
+ foreach (['.a, .b', '.a, .b, .a.b', 'p, :is(.a, .b)'] as $selector) {
+ $texts = [];
+ foreach ($context->querySelectorAll($selector) as $node) {
+ $texts[] = $node->textContent;
+ }
+ echo $selector, ': ', implode(' ', $texts), "\n";
+ }
+}
+
+?>
+--EXPECT--
+.a, .b: one two
+.a, .b, .a.b: one two
+p, :is(.a, .b): one two
+.a, .b: one two
+.a, .b, .a.b: one two
+p, :is(.a, .b): one two