From edcd94d5816ac072f34cd3a93f59905575bbfe39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 8 Jul 2026 11:27:30 +0200 Subject: [PATCH 1/4] ext/intl: don't include C++ ICU headers from C translation units (#22636) php_intl.c is compiled as C but transitively includes formatter_data.h and listformatter_class.h, which (since 8.6) include and unconditionally. On ICU >= 64 those C++ headers are a no-op in a C compile, but ICU 63 (Debian Buster) has an unguarded "#include " at the top of unistr.h, so the C compile fails with "fatal error: cstddef: No such file or directory". The C path only uses the "typedef void" shim (NumberFormat*/ListFormatter* are just void*), so it needs no ICU header at all. Move the C++ include inside the existing #ifdef __cplusplus guard. No-op on newer ICU. --- ext/intl/formatter/formatter_data.h | 3 +-- ext/intl/listformatter/listformatter_class.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ext/intl/formatter/formatter_data.h b/ext/intl/formatter/formatter_data.h index 1208970471bf..46a82cb9bd0f 100644 --- a/ext/intl/formatter/formatter_data.h +++ b/ext/intl/formatter/formatter_data.h @@ -23,9 +23,8 @@ extern "C" { } #endif -#include - #ifdef __cplusplus +#include using icu::NumberFormat; #else typedef void NumberFormat; diff --git a/ext/intl/listformatter/listformatter_class.h b/ext/intl/listformatter/listformatter_class.h index 7e7fd29207fc..bdf21b6886e0 100644 --- a/ext/intl/listformatter/listformatter_class.h +++ b/ext/intl/listformatter/listformatter_class.h @@ -21,9 +21,8 @@ #include "intl_error.h" #include "intl_data.h" -#include - #ifdef __cplusplus +#include using icu::ListFormatter; #else typedef void ListFormatter; From ff480bce5c44e3bfe62bec6a689d62d5cdc20793 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Wed, 8 Jul 2026 20:10:26 +0800 Subject: [PATCH 2/4] ext/dom: Fix Dom\DtdNamedNodeMap index overflow in dimension access (#22630) Dom\DtdNamedNodeMap dimension access could overflow the index when reading DTD entities or notations. This commit fix it. --- NEWS | 3 ++ ext/dom/dom_iterators.c | 12 +++++- ext/dom/php_dom.h | 2 +- ...edNodeMap_dimension_index_overflow_64.phpt | 41 +++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt diff --git a/NEWS b/NEWS index 8971e7d317a3..cd396479e3e2 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,9 @@ PHP NEWS - DOM: . Fixed bug GH-22570 (Stack overflow when serializing a deeply nested Dom\XMLDocument). (iliaal) + . Fixed Dom\DtdNamedNodeMap integer dimension access so negative indexes + return NULL and indexes outside the int range throw ValueError instead of + returning the first entity or notation. (Weilin Du) - Exif: . Fixed bug GH-11020 (exif_read_data() emits a spurious "Illegal IFD size" diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index f97a9ec825d5..7566dd8b61a8 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -79,14 +79,22 @@ void dom_free_notation(xmlEntityPtr entity) /* {{{ */ } /* }}} */ -xmlNodePtr php_dom_libxml_hash_iter(xmlHashTable *ht, int index) +xmlNodePtr php_dom_libxml_hash_iter(xmlHashTable *ht, zend_long index) { int htsize; + if (index < 0) { + return NULL; + } + if (UNEXPECTED(ZEND_LONG_INT_OVFL(index))) { + zend_value_error("must be between 0 and %d", INT_MAX); + return NULL; + } + if ((htsize = xmlHashSize(ht)) > 0 && index < htsize) { nodeIterator iter; iter.cur = 0; - iter.index = index; + iter.index = (int) index; iter.node = NULL; xmlHashScan(ht, itemHashScanner, &iter); return iter.node; diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 1b19aeee3baa..6f4b5075b659 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -127,7 +127,7 @@ bool dom_node_is_read_only(const xmlNode *node); bool dom_node_children_valid(const xmlNode *node); xmlNodePtr create_notation(xmlDtdPtr parent_dtd, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); void dom_free_notation(xmlEntityPtr entity); -xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index); +xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, zend_long index); zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref); void dom_set_doc_classmap(php_libxml_ref_obj *document, zend_class_entry *basece, zend_class_entry *ce); xmlNodePtr php_dom_create_fake_namespace_decl(xmlNodePtr nodep, xmlNsPtr original, zval *return_value, dom_object *parent_intern); diff --git a/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt b/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt new file mode 100644 index 000000000000..cc2d7a06a2ca --- /dev/null +++ b/ext/dom/tests/modern/xml/DtdNamedNodeMap_dimension_index_overflow_64.phpt @@ -0,0 +1,41 @@ +--TEST-- +Dom\DtdNamedNodeMap dimension access handles invalid integer indexes +--EXTENSIONS-- +dom +--SKIPIF-- + +--FILE-- + + +]> + +XML); + +$overflow = 4294967296; + +function dump_access(Closure $callback): void { + try { + var_dump($callback()?->nodeName); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } +} + +dump_access(fn() => $doc->doctype->entities[-1]); +dump_access(fn() => $doc->doctype->entities[$overflow]); + +dump_access(fn() => $doc->doctype->notations[-1]); +dump_access(fn() => $doc->doctype->notations[$overflow]); +?> +--EXPECT-- +NULL +must be between 0 and 2147483647 +NULL +must be between 0 and 2147483647 From c993aa64f260545ee4eef0173e260cb02d41d0d2 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 8 Jul 2026 14:33:07 +0100 Subject: [PATCH 3/4] Zend: add test for <=> comparing against different types (#22634) --- .../comparison/spaceship_type_compare.phpt | 536 ++++++++++++++++++ 1 file changed, 536 insertions(+) create mode 100644 Zend/tests/comparison/spaceship_type_compare.phpt diff --git a/Zend/tests/comparison/spaceship_type_compare.phpt b/Zend/tests/comparison/spaceship_type_compare.phpt new file mode 100644 index 000000000000..7382a593cc84 --- /dev/null +++ b/Zend/tests/comparison/spaceship_type_compare.phpt @@ -0,0 +1,536 @@ +--TEST-- +Compare types via <=> operator +--FILE-- + $r) { + 0 => "EQUAL", + 1 => match ($r <=> $l) { + -1 => "GREATER THAN", + 1 => "UNCOMPARABLE", + }, + -1 => "LESS THAN", + }; +} + +class test { +} + +$values = [ + 'null' => null, + 'false' => false, + 'true' => true, + 'i-5' => -5, + 'i0' => 0, + 'i10' => 10, + 'f-5' => -5.0, + 'f0' => 0.0, + 'f2.5' => 2.5, + 'f10' => 10.0, + 's""' => "", + 's"str"' => "str", + 's"-5"' => "-5", + 's"0"' => "0", + 's"2.5"' => "2.5", + 's"10"' => "10", + 'a[]' => [], + 'a[1, 2, 3]' => [1, 2, 3], + 'c"stdClass"' => new stdClass(), + 'c"test"' => new test(), + 'r"STDOUT"' => STDOUT, + 'r"STDERR"' => STDERR, +]; + +foreach($values as $l_name => $l) { + foreach($values as $r_name => $r) { + echo $l_name, ' ', cmp($l, $r), ' ', $r_name, "\n"; + } +} + +?> +--EXPECT-- +null EQUAL null +null EQUAL false +null LESS THAN true +null LESS THAN i-5 +null EQUAL i0 +null LESS THAN i10 +null LESS THAN f-5 +null EQUAL f0 +null LESS THAN f2.5 +null LESS THAN f10 +null EQUAL s"" +null LESS THAN s"str" +null LESS THAN s"-5" +null LESS THAN s"0" +null LESS THAN s"2.5" +null LESS THAN s"10" +null EQUAL a[] +null LESS THAN a[1, 2, 3] +null LESS THAN c"stdClass" +null LESS THAN c"test" +null LESS THAN r"STDOUT" +null LESS THAN r"STDERR" +false EQUAL null +false EQUAL false +false LESS THAN true +false LESS THAN i-5 +false EQUAL i0 +false LESS THAN i10 +false LESS THAN f-5 +false EQUAL f0 +false LESS THAN f2.5 +false LESS THAN f10 +false EQUAL s"" +false LESS THAN s"str" +false LESS THAN s"-5" +false EQUAL s"0" +false LESS THAN s"2.5" +false LESS THAN s"10" +false EQUAL a[] +false LESS THAN a[1, 2, 3] +false LESS THAN c"stdClass" +false LESS THAN c"test" +false LESS THAN r"STDOUT" +false LESS THAN r"STDERR" +true GREATER THAN null +true GREATER THAN false +true EQUAL true +true EQUAL i-5 +true GREATER THAN i0 +true EQUAL i10 +true EQUAL f-5 +true GREATER THAN f0 +true EQUAL f2.5 +true EQUAL f10 +true GREATER THAN s"" +true EQUAL s"str" +true EQUAL s"-5" +true GREATER THAN s"0" +true EQUAL s"2.5" +true EQUAL s"10" +true GREATER THAN a[] +true EQUAL a[1, 2, 3] +true EQUAL c"stdClass" +true EQUAL c"test" +true EQUAL r"STDOUT" +true EQUAL r"STDERR" +i-5 GREATER THAN null +i-5 GREATER THAN false +i-5 EQUAL true +i-5 EQUAL i-5 +i-5 LESS THAN i0 +i-5 LESS THAN i10 +i-5 EQUAL f-5 +i-5 LESS THAN f0 +i-5 LESS THAN f2.5 +i-5 LESS THAN f10 +i-5 GREATER THAN s"" +i-5 LESS THAN s"str" +i-5 EQUAL s"-5" +i-5 LESS THAN s"0" +i-5 LESS THAN s"2.5" +i-5 LESS THAN s"10" +i-5 LESS THAN a[] +i-5 LESS THAN a[1, 2, 3] +i-5 LESS THAN c"stdClass" +i-5 LESS THAN c"test" +i-5 LESS THAN r"STDOUT" +i-5 LESS THAN r"STDERR" +i0 EQUAL null +i0 EQUAL false +i0 LESS THAN true +i0 GREATER THAN i-5 +i0 EQUAL i0 +i0 LESS THAN i10 +i0 GREATER THAN f-5 +i0 EQUAL f0 +i0 LESS THAN f2.5 +i0 LESS THAN f10 +i0 GREATER THAN s"" +i0 LESS THAN s"str" +i0 GREATER THAN s"-5" +i0 EQUAL s"0" +i0 LESS THAN s"2.5" +i0 LESS THAN s"10" +i0 LESS THAN a[] +i0 LESS THAN a[1, 2, 3] +i0 LESS THAN c"stdClass" +i0 LESS THAN c"test" +i0 LESS THAN r"STDOUT" +i0 LESS THAN r"STDERR" +i10 GREATER THAN null +i10 GREATER THAN false +i10 EQUAL true +i10 GREATER THAN i-5 +i10 GREATER THAN i0 +i10 EQUAL i10 +i10 GREATER THAN f-5 +i10 GREATER THAN f0 +i10 GREATER THAN f2.5 +i10 EQUAL f10 +i10 GREATER THAN s"" +i10 LESS THAN s"str" +i10 GREATER THAN s"-5" +i10 GREATER THAN s"0" +i10 GREATER THAN s"2.5" +i10 EQUAL s"10" +i10 LESS THAN a[] +i10 LESS THAN a[1, 2, 3] +i10 GREATER THAN c"stdClass" +i10 GREATER THAN c"test" +i10 GREATER THAN r"STDOUT" +i10 GREATER THAN r"STDERR" +f-5 GREATER THAN null +f-5 GREATER THAN false +f-5 EQUAL true +f-5 EQUAL i-5 +f-5 LESS THAN i0 +f-5 LESS THAN i10 +f-5 EQUAL f-5 +f-5 LESS THAN f0 +f-5 LESS THAN f2.5 +f-5 LESS THAN f10 +f-5 GREATER THAN s"" +f-5 LESS THAN s"str" +f-5 EQUAL s"-5" +f-5 LESS THAN s"0" +f-5 LESS THAN s"2.5" +f-5 LESS THAN s"10" +f-5 LESS THAN a[] +f-5 LESS THAN a[1, 2, 3] +f-5 LESS THAN c"stdClass" +f-5 LESS THAN c"test" +f-5 LESS THAN r"STDOUT" +f-5 LESS THAN r"STDERR" +f0 EQUAL null +f0 EQUAL false +f0 LESS THAN true +f0 GREATER THAN i-5 +f0 EQUAL i0 +f0 LESS THAN i10 +f0 GREATER THAN f-5 +f0 EQUAL f0 +f0 LESS THAN f2.5 +f0 LESS THAN f10 +f0 GREATER THAN s"" +f0 LESS THAN s"str" +f0 GREATER THAN s"-5" +f0 EQUAL s"0" +f0 LESS THAN s"2.5" +f0 LESS THAN s"10" +f0 LESS THAN a[] +f0 LESS THAN a[1, 2, 3] +f0 LESS THAN c"stdClass" +f0 LESS THAN c"test" +f0 LESS THAN r"STDOUT" +f0 LESS THAN r"STDERR" +f2.5 GREATER THAN null +f2.5 GREATER THAN false +f2.5 EQUAL true +f2.5 GREATER THAN i-5 +f2.5 GREATER THAN i0 +f2.5 LESS THAN i10 +f2.5 GREATER THAN f-5 +f2.5 GREATER THAN f0 +f2.5 EQUAL f2.5 +f2.5 LESS THAN f10 +f2.5 GREATER THAN s"" +f2.5 LESS THAN s"str" +f2.5 GREATER THAN s"-5" +f2.5 GREATER THAN s"0" +f2.5 EQUAL s"2.5" +f2.5 LESS THAN s"10" +f2.5 LESS THAN a[] +f2.5 LESS THAN a[1, 2, 3] +f2.5 GREATER THAN c"stdClass" +f2.5 GREATER THAN c"test" +f2.5 GREATER THAN r"STDOUT" +f2.5 LESS THAN r"STDERR" +f10 GREATER THAN null +f10 GREATER THAN false +f10 EQUAL true +f10 GREATER THAN i-5 +f10 GREATER THAN i0 +f10 EQUAL i10 +f10 GREATER THAN f-5 +f10 GREATER THAN f0 +f10 GREATER THAN f2.5 +f10 EQUAL f10 +f10 GREATER THAN s"" +f10 LESS THAN s"str" +f10 GREATER THAN s"-5" +f10 GREATER THAN s"0" +f10 GREATER THAN s"2.5" +f10 EQUAL s"10" +f10 LESS THAN a[] +f10 LESS THAN a[1, 2, 3] +f10 GREATER THAN c"stdClass" +f10 GREATER THAN c"test" +f10 GREATER THAN r"STDOUT" +f10 GREATER THAN r"STDERR" +s"" EQUAL null +s"" EQUAL false +s"" LESS THAN true +s"" LESS THAN i-5 +s"" LESS THAN i0 +s"" LESS THAN i10 +s"" LESS THAN f-5 +s"" LESS THAN f0 +s"" LESS THAN f2.5 +s"" LESS THAN f10 +s"" EQUAL s"" +s"" LESS THAN s"str" +s"" LESS THAN s"-5" +s"" LESS THAN s"0" +s"" LESS THAN s"2.5" +s"" LESS THAN s"10" +s"" LESS THAN a[] +s"" LESS THAN a[1, 2, 3] +s"" LESS THAN c"stdClass" +s"" LESS THAN c"test" +s"" LESS THAN r"STDOUT" +s"" LESS THAN r"STDERR" +s"str" GREATER THAN null +s"str" GREATER THAN false +s"str" EQUAL true +s"str" GREATER THAN i-5 +s"str" GREATER THAN i0 +s"str" GREATER THAN i10 +s"str" GREATER THAN f-5 +s"str" GREATER THAN f0 +s"str" GREATER THAN f2.5 +s"str" GREATER THAN f10 +s"str" GREATER THAN s"" +s"str" EQUAL s"str" +s"str" GREATER THAN s"-5" +s"str" GREATER THAN s"0" +s"str" GREATER THAN s"2.5" +s"str" GREATER THAN s"10" +s"str" LESS THAN a[] +s"str" LESS THAN a[1, 2, 3] +s"str" LESS THAN c"stdClass" +s"str" LESS THAN c"test" +s"str" LESS THAN r"STDOUT" +s"str" LESS THAN r"STDERR" +s"-5" GREATER THAN null +s"-5" GREATER THAN false +s"-5" EQUAL true +s"-5" EQUAL i-5 +s"-5" LESS THAN i0 +s"-5" LESS THAN i10 +s"-5" EQUAL f-5 +s"-5" LESS THAN f0 +s"-5" LESS THAN f2.5 +s"-5" LESS THAN f10 +s"-5" GREATER THAN s"" +s"-5" LESS THAN s"str" +s"-5" EQUAL s"-5" +s"-5" LESS THAN s"0" +s"-5" LESS THAN s"2.5" +s"-5" LESS THAN s"10" +s"-5" LESS THAN a[] +s"-5" LESS THAN a[1, 2, 3] +s"-5" LESS THAN c"stdClass" +s"-5" LESS THAN c"test" +s"-5" LESS THAN r"STDOUT" +s"-5" LESS THAN r"STDERR" +s"0" GREATER THAN null +s"0" EQUAL false +s"0" LESS THAN true +s"0" GREATER THAN i-5 +s"0" EQUAL i0 +s"0" LESS THAN i10 +s"0" GREATER THAN f-5 +s"0" EQUAL f0 +s"0" LESS THAN f2.5 +s"0" LESS THAN f10 +s"0" GREATER THAN s"" +s"0" LESS THAN s"str" +s"0" GREATER THAN s"-5" +s"0" EQUAL s"0" +s"0" LESS THAN s"2.5" +s"0" LESS THAN s"10" +s"0" LESS THAN a[] +s"0" LESS THAN a[1, 2, 3] +s"0" LESS THAN c"stdClass" +s"0" LESS THAN c"test" +s"0" LESS THAN r"STDOUT" +s"0" LESS THAN r"STDERR" +s"2.5" GREATER THAN null +s"2.5" GREATER THAN false +s"2.5" EQUAL true +s"2.5" GREATER THAN i-5 +s"2.5" GREATER THAN i0 +s"2.5" LESS THAN i10 +s"2.5" GREATER THAN f-5 +s"2.5" GREATER THAN f0 +s"2.5" EQUAL f2.5 +s"2.5" LESS THAN f10 +s"2.5" GREATER THAN s"" +s"2.5" LESS THAN s"str" +s"2.5" GREATER THAN s"-5" +s"2.5" GREATER THAN s"0" +s"2.5" EQUAL s"2.5" +s"2.5" LESS THAN s"10" +s"2.5" LESS THAN a[] +s"2.5" LESS THAN a[1, 2, 3] +s"2.5" LESS THAN c"stdClass" +s"2.5" LESS THAN c"test" +s"2.5" GREATER THAN r"STDOUT" +s"2.5" LESS THAN r"STDERR" +s"10" GREATER THAN null +s"10" GREATER THAN false +s"10" EQUAL true +s"10" GREATER THAN i-5 +s"10" GREATER THAN i0 +s"10" EQUAL i10 +s"10" GREATER THAN f-5 +s"10" GREATER THAN f0 +s"10" GREATER THAN f2.5 +s"10" EQUAL f10 +s"10" GREATER THAN s"" +s"10" LESS THAN s"str" +s"10" GREATER THAN s"-5" +s"10" GREATER THAN s"0" +s"10" GREATER THAN s"2.5" +s"10" EQUAL s"10" +s"10" LESS THAN a[] +s"10" LESS THAN a[1, 2, 3] +s"10" LESS THAN c"stdClass" +s"10" LESS THAN c"test" +s"10" GREATER THAN r"STDOUT" +s"10" GREATER THAN r"STDERR" +a[] EQUAL null +a[] EQUAL false +a[] LESS THAN true +a[] GREATER THAN i-5 +a[] GREATER THAN i0 +a[] GREATER THAN i10 +a[] GREATER THAN f-5 +a[] GREATER THAN f0 +a[] GREATER THAN f2.5 +a[] GREATER THAN f10 +a[] GREATER THAN s"" +a[] GREATER THAN s"str" +a[] GREATER THAN s"-5" +a[] GREATER THAN s"0" +a[] GREATER THAN s"2.5" +a[] GREATER THAN s"10" +a[] EQUAL a[] +a[] LESS THAN a[1, 2, 3] +a[] LESS THAN c"stdClass" +a[] LESS THAN c"test" +a[] GREATER THAN r"STDOUT" +a[] GREATER THAN r"STDERR" +a[1, 2, 3] GREATER THAN null +a[1, 2, 3] GREATER THAN false +a[1, 2, 3] EQUAL true +a[1, 2, 3] GREATER THAN i-5 +a[1, 2, 3] GREATER THAN i0 +a[1, 2, 3] GREATER THAN i10 +a[1, 2, 3] GREATER THAN f-5 +a[1, 2, 3] GREATER THAN f0 +a[1, 2, 3] GREATER THAN f2.5 +a[1, 2, 3] GREATER THAN f10 +a[1, 2, 3] GREATER THAN s"" +a[1, 2, 3] GREATER THAN s"str" +a[1, 2, 3] GREATER THAN s"-5" +a[1, 2, 3] GREATER THAN s"0" +a[1, 2, 3] GREATER THAN s"2.5" +a[1, 2, 3] GREATER THAN s"10" +a[1, 2, 3] GREATER THAN a[] +a[1, 2, 3] EQUAL a[1, 2, 3] +a[1, 2, 3] LESS THAN c"stdClass" +a[1, 2, 3] LESS THAN c"test" +a[1, 2, 3] GREATER THAN r"STDOUT" +a[1, 2, 3] GREATER THAN r"STDERR" +c"stdClass" GREATER THAN null +c"stdClass" GREATER THAN false +c"stdClass" EQUAL true +c"stdClass" GREATER THAN i-5 +c"stdClass" GREATER THAN i0 +c"stdClass" LESS THAN i10 +c"stdClass" GREATER THAN f-5 +c"stdClass" GREATER THAN f0 +c"stdClass" LESS THAN f2.5 +c"stdClass" LESS THAN f10 +c"stdClass" GREATER THAN s"" +c"stdClass" GREATER THAN s"str" +c"stdClass" GREATER THAN s"-5" +c"stdClass" GREATER THAN s"0" +c"stdClass" GREATER THAN s"2.5" +c"stdClass" GREATER THAN s"10" +c"stdClass" GREATER THAN a[] +c"stdClass" GREATER THAN a[1, 2, 3] +c"stdClass" EQUAL c"stdClass" +c"stdClass" UNCOMPARABLE c"test" +c"stdClass" GREATER THAN r"STDOUT" +c"stdClass" GREATER THAN r"STDERR" +c"test" GREATER THAN null +c"test" GREATER THAN false +c"test" EQUAL true +c"test" GREATER THAN i-5 +c"test" GREATER THAN i0 +c"test" LESS THAN i10 +c"test" GREATER THAN f-5 +c"test" GREATER THAN f0 +c"test" LESS THAN f2.5 +c"test" LESS THAN f10 +c"test" GREATER THAN s"" +c"test" GREATER THAN s"str" +c"test" GREATER THAN s"-5" +c"test" GREATER THAN s"0" +c"test" GREATER THAN s"2.5" +c"test" GREATER THAN s"10" +c"test" GREATER THAN a[] +c"test" GREATER THAN a[1, 2, 3] +c"test" UNCOMPARABLE c"stdClass" +c"test" EQUAL c"test" +c"test" GREATER THAN r"STDOUT" +c"test" GREATER THAN r"STDERR" +r"STDOUT" GREATER THAN null +r"STDOUT" GREATER THAN false +r"STDOUT" EQUAL true +r"STDOUT" GREATER THAN i-5 +r"STDOUT" GREATER THAN i0 +r"STDOUT" LESS THAN i10 +r"STDOUT" GREATER THAN f-5 +r"STDOUT" GREATER THAN f0 +r"STDOUT" LESS THAN f2.5 +r"STDOUT" LESS THAN f10 +r"STDOUT" GREATER THAN s"" +r"STDOUT" GREATER THAN s"str" +r"STDOUT" GREATER THAN s"-5" +r"STDOUT" GREATER THAN s"0" +r"STDOUT" LESS THAN s"2.5" +r"STDOUT" LESS THAN s"10" +r"STDOUT" LESS THAN a[] +r"STDOUT" LESS THAN a[1, 2, 3] +r"STDOUT" LESS THAN c"stdClass" +r"STDOUT" LESS THAN c"test" +r"STDOUT" EQUAL r"STDOUT" +r"STDOUT" LESS THAN r"STDERR" +r"STDERR" GREATER THAN null +r"STDERR" GREATER THAN false +r"STDERR" EQUAL true +r"STDERR" GREATER THAN i-5 +r"STDERR" GREATER THAN i0 +r"STDERR" LESS THAN i10 +r"STDERR" GREATER THAN f-5 +r"STDERR" GREATER THAN f0 +r"STDERR" GREATER THAN f2.5 +r"STDERR" LESS THAN f10 +r"STDERR" GREATER THAN s"" +r"STDERR" GREATER THAN s"str" +r"STDERR" GREATER THAN s"-5" +r"STDERR" GREATER THAN s"0" +r"STDERR" GREATER THAN s"2.5" +r"STDERR" LESS THAN s"10" +r"STDERR" LESS THAN a[] +r"STDERR" LESS THAN a[1, 2, 3] +r"STDERR" LESS THAN c"stdClass" +r"STDERR" LESS THAN c"test" +r"STDERR" GREATER THAN r"STDOUT" +r"STDERR" EQUAL r"STDERR" From 35881e12982933fd7eaea30da10994e91c84e1e5 Mon Sep 17 00:00:00 2001 From: Vazha Aptsiauri <37383700+Afcyy@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:10:01 +0400 Subject: [PATCH 4/4] sapi/cli: support HTTP QUERY method in built-in server (#22615) Co-authored-by: Vazha Aptsiauri --- UPGRADING | 4 ++ sapi/cli/php_http_parser.c | 2 + sapi/cli/php_http_parser.h | 1 + .../tests/php_cli_server_query_method.phpt | 40 +++++++++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 sapi/cli/tests/php_cli_server_query_method.phpt diff --git a/UPGRADING b/UPGRADING index b9c659ccc405..6a1f1b12e4a8 100644 --- a/UPGRADING +++ b/UPGRADING @@ -297,6 +297,10 @@ PHP 8.6 UPGRADE NOTES 3. Changes in SAPI modules ======================================== +- CLI: + . The built-in development server now accepts requests using the QUERY HTTP + method instead of returning 501 Not Implemented. + ======================================== 4. Deprecated Functionality ======================================== diff --git a/sapi/cli/php_http_parser.c b/sapi/cli/php_http_parser.c index c7c2ad0caaea..ac3c19d5d963 100644 --- a/sapi/cli/php_http_parser.c +++ b/sapi/cli/php_http_parser.c @@ -82,6 +82,7 @@ static const char *method_strings[] = , "POST" , "PUT" , "PATCH" + , "QUERY" , "CONNECT" , "OPTIONS" , "TRACE" @@ -521,6 +522,7 @@ size_t php_http_parser_execute (php_http_parser *parser, case 'N': parser->method = PHP_HTTP_NOTIFY; break; case 'O': parser->method = PHP_HTTP_OPTIONS; break; case 'P': parser->method = PHP_HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break; + case 'Q': parser->method = PHP_HTTP_QUERY; break; case 'R': parser->method = PHP_HTTP_REPORT; break; case 'S': parser->method = PHP_HTTP_SUBSCRIBE; /* or SEARCH */ break; case 'T': parser->method = PHP_HTTP_TRACE; break; diff --git a/sapi/cli/php_http_parser.h b/sapi/cli/php_http_parser.h index 345ca405edd0..d7006b6d04d7 100644 --- a/sapi/cli/php_http_parser.h +++ b/sapi/cli/php_http_parser.h @@ -79,6 +79,7 @@ enum php_http_method , PHP_HTTP_POST , PHP_HTTP_PUT , PHP_HTTP_PATCH + , PHP_HTTP_QUERY /* pathological */ , PHP_HTTP_CONNECT , PHP_HTTP_OPTIONS diff --git a/sapi/cli/tests/php_cli_server_query_method.phpt b/sapi/cli/tests/php_cli_server_query_method.phpt new file mode 100644 index 000000000000..58ce95bfd1e3 --- /dev/null +++ b/sapi/cli/tests/php_cli_server_query_method.phpt @@ -0,0 +1,40 @@ +--TEST-- +Support HTTP QUERY method +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +HTTP/1.1 200 OK +Host: %s +Date: %s +Connection: close +X-Powered-By: %s +Content-type: text/html; charset=UTF-8 + +string(5) "QUERY"