From 889a3cf817e3a4eea7ae297561bf8cfbb629eef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Fri, 14 Nov 2025 21:32:05 +0100 Subject: [PATCH 1/2] Fix GH-20366 Do not throw ValueError on null-bytes --- ext/uri/php_uri.c | 10 ++-- ext/uri/php_uri_common.c | 4 +- ext/uri/tests/035.phpt | 39 -------------- .../modification/path_error_null_byte.phpt | 18 +++++++ ..._byte1.phpt => basic_error_null_byte.phpt} | 4 +- .../parsing/basic_error_null_byte2.phpt | 14 ----- .../resolve_error_null_byte.phpt | 18 +++++++ .../fragment_success_null_byte.phpt | 19 +++++++ .../modification/host_error_null_byte.phpt | 18 +++++++ .../password_success_null_byte.phpt | 20 +++++++ .../modification/path_success_null_byte.phpt | 19 +++++++ .../modification/query_success_null_byte.phpt | 19 +++++++ .../modification/scheme_error_null_byte.phpt | 18 +++++++ .../username_success_null_byte.phpt | 20 +++++++ .../parsing/basic_error_null_byte2.phpt | 14 ----- ...l_byte1.phpt => host_error_null_byte.phpt} | 4 +- .../parsing/password_success_null_byte.phpt | 31 +++++++++++ .../parsing/path_success_null_byte.phpt | 31 +++++++++++ .../parsing/query_success_null_byte.phpt | 31 +++++++++++ .../parsing/scheme_error_null_byte.phpt | 14 +++++ .../parsing/username_success_null_byte.phpt | 31 +++++++++++ .../resolve_error_host_null_byte.phpt | 18 +++++++ .../resolve_success_path_null_byte.phpt | 53 +++++++++++++++++++ 23 files changed, 389 insertions(+), 78 deletions(-) delete mode 100644 ext/uri/tests/035.phpt create mode 100644 ext/uri/tests/rfc3986/modification/path_error_null_byte.phpt rename ext/uri/tests/rfc3986/parsing/{basic_error_null_byte1.phpt => basic_error_null_byte.phpt} (63%) delete mode 100644 ext/uri/tests/rfc3986/parsing/basic_error_null_byte2.phpt create mode 100644 ext/uri/tests/rfc3986/reference_resolution/resolve_error_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/modification/fragment_success_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/modification/host_error_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/modification/password_success_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/modification/path_success_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/modification/query_success_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/modification/scheme_error_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/modification/username_success_null_byte.phpt delete mode 100644 ext/uri/tests/whatwg/parsing/basic_error_null_byte2.phpt rename ext/uri/tests/whatwg/parsing/{basic_error_null_byte1.phpt => host_error_null_byte.phpt} (63%) create mode 100644 ext/uri/tests/whatwg/parsing/password_success_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/parsing/path_success_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/parsing/query_success_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/parsing/scheme_error_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/parsing/username_success_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/reference_resolution/resolve_error_host_null_byte.phpt create mode 100644 ext/uri/tests/whatwg/reference_resolution/resolve_success_path_null_byte.phpt diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index 4a1207de89942..29b26f7b8ce27 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -377,7 +377,7 @@ static void create_rfc3986_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor zend_object *base_url_object = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_PATH_STR(uri_str) + Z_PARAM_STR(uri_str) Z_PARAM_OPTIONAL Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, php_uri_ce_rfc3986_uri) ZEND_PARSE_PARAMETERS_END(); @@ -490,7 +490,7 @@ static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor) zval *errors = NULL; ZEND_PARSE_PARAMETERS_START(1, 3) - Z_PARAM_PATH_STR(uri_str) + Z_PARAM_STR(uri_str) Z_PARAM_OPTIONAL Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, php_uri_ce_whatwg_url) Z_PARAM_ZVAL(errors) @@ -553,7 +553,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, withUserInfo) zend_string *value; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR_OR_NULL(value) + Z_PARAM_STR_OR_NULL(value) ZEND_PARSE_PARAMETERS_END(); zval zv; @@ -769,7 +769,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, resolve) zend_string *uri_str; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR(uri_str) + Z_PARAM_STR(uri_str) ZEND_PARSE_PARAMETERS_END(); php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, @@ -956,7 +956,7 @@ PHP_METHOD(Uri_WhatWg_Url, resolve) zval *errors = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_PATH_STR(uri_str) + Z_PARAM_STR(uri_str) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(errors) ZEND_PARSE_PARAMETERS_END(); diff --git a/ext/uri/php_uri_common.c b/ext/uri/php_uri_common.c index 780cc95074159..da73bc59bf9cf 100644 --- a/ext/uri/php_uri_common.c +++ b/ext/uri/php_uri_common.c @@ -96,7 +96,7 @@ void php_uri_property_write_str_helper(INTERNAL_FUNCTION_PARAMETERS, php_uri_pro zend_string *value; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR(value) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); zval zv; @@ -110,7 +110,7 @@ void php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAMETERS, php zend_string *value; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR_OR_NULL(value) + Z_PARAM_STR_OR_NULL(value) ZEND_PARSE_PARAMETERS_END(); zval zv; diff --git a/ext/uri/tests/035.phpt b/ext/uri/tests/035.phpt deleted file mode 100644 index 3c39870373742..0000000000000 --- a/ext/uri/tests/035.phpt +++ /dev/null @@ -1,39 +0,0 @@ ---TEST-- -Test URI parsing containing null bytes ---EXTENSIONS-- -uri ---FILE-- -getMessage() . "\n"; -} - -$uri = new Uri\Rfc3986\Uri("https://example.com"); -try { - $uri->withHost("exam\0ple.com"); -} catch (Error $e) { - echo $e->getMessage() . "\n"; -} - -try { - new Uri\WhatWg\Url("https://exam\0ple.com"); -} catch (Error $e) { - echo $e->getMessage() . "\n"; -} - -$url = new Uri\WhatWg\Url("https://example.com"); -try { - $url->withHost("exam\0ple.com"); -} catch (Error $e) { - echo $e->getMessage() . "\n"; -} - -?> ---EXPECT-- -Uri\Rfc3986\Uri::__construct(): Argument #1 ($uri) must not contain any null bytes -Uri\Rfc3986\Uri::withHost(): Argument #1 ($host) must not contain any null bytes -Uri\WhatWg\Url::__construct(): Argument #1 ($uri) must not contain any null bytes -Uri\WhatWg\Url::withHost(): Argument #1 ($host) must not contain any null bytes diff --git a/ext/uri/tests/rfc3986/modification/path_error_null_byte.phpt b/ext/uri/tests/rfc3986/modification/path_error_null_byte.phpt new file mode 100644 index 0000000000000..d02e3e8575f2d --- /dev/null +++ b/ext/uri/tests/rfc3986/modification/path_error_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\Rfc3986\Uri component modification - path - null byte +--EXTENSIONS-- +uri +--FILE-- +withPath("/\0foo"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\InvalidUriException: The specified path is malformed diff --git a/ext/uri/tests/rfc3986/parsing/basic_error_null_byte1.phpt b/ext/uri/tests/rfc3986/parsing/basic_error_null_byte.phpt similarity index 63% rename from ext/uri/tests/rfc3986/parsing/basic_error_null_byte1.phpt rename to ext/uri/tests/rfc3986/parsing/basic_error_null_byte.phpt index 5695b8487cd34..91d194e2ff5e5 100644 --- a/ext/uri/tests/rfc3986/parsing/basic_error_null_byte1.phpt +++ b/ext/uri/tests/rfc3986/parsing/basic_error_null_byte.phpt @@ -5,10 +5,10 @@ Test Uri\Rfc3986\Uri parsing - basic - URI contains null byte try { new Uri\Rfc3986\Uri("https://exam\0ple.com"); -} catch (ValueError $e) { +} catch (Throwable $e) { echo $e::class, ": ", $e->getMessage(), PHP_EOL; } ?> --EXPECT-- -ValueError: Uri\Rfc3986\Uri::__construct(): Argument #1 ($uri) must not contain any null bytes +Uri\InvalidUriException: The specified URI is malformed diff --git a/ext/uri/tests/rfc3986/parsing/basic_error_null_byte2.phpt b/ext/uri/tests/rfc3986/parsing/basic_error_null_byte2.phpt deleted file mode 100644 index 85c779cc5aff7..0000000000000 --- a/ext/uri/tests/rfc3986/parsing/basic_error_null_byte2.phpt +++ /dev/null @@ -1,14 +0,0 @@ ---TEST-- -Test Uri\Rfc3986\Uri parsing - basic - URI contains null byte ---FILE-- -getMessage(), PHP_EOL; -} - -?> ---EXPECT-- -ValueError: Uri\Rfc3986\Uri::parse(): Argument #1 ($uri) must not contain any null bytes diff --git a/ext/uri/tests/rfc3986/reference_resolution/resolve_error_null_byte.phpt b/ext/uri/tests/rfc3986/reference_resolution/resolve_error_null_byte.phpt new file mode 100644 index 0000000000000..16b2f61dce78b --- /dev/null +++ b/ext/uri/tests/rfc3986/reference_resolution/resolve_error_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\Rfc3986\Uri reference resolution - resolve() - null byte +--EXTENSIONS-- +uri +--FILE-- +resolve("/f\0o"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\InvalidUriException: The specified URI is malformed diff --git a/ext/uri/tests/whatwg/modification/fragment_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/fragment_success_null_byte.phpt new file mode 100644 index 0000000000000..faaf41796c746 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/fragment_success_null_byte.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - fragment - null byte +--EXTENSIONS-- +uri +--FILE-- +withFragment("frag\0ment"); + +var_dump($url1->getFragment()); +var_dump($url2->getFragment()); +var_dump($url2->toAsciiString()); + +?> +--EXPECT-- +NULL +string(11) "frag%00ment" +string(32) "https://example.com/#frag%00ment" diff --git a/ext/uri/tests/whatwg/modification/host_error_null_byte.phpt b/ext/uri/tests/whatwg/modification/host_error_null_byte.phpt new file mode 100644 index 0000000000000..84a6bc1ebdbc6 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/host_error_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - host - null byte +--EXTENSIONS-- +uri +--FILE-- +withHost("h\0st"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\WhatWg\InvalidUrlException: The specified host is malformed (DomainInvalidCodePoint) diff --git a/ext/uri/tests/whatwg/modification/password_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/password_success_null_byte.phpt new file mode 100644 index 0000000000000..2216fa4e8e845 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/password_success_null_byte.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - password - null byte +--EXTENSIONS-- +uri +--FILE-- +withPassword("pass\0word"); + +var_dump($url1->getPassword()); +var_dump($url2->getPassword()); +var_dump($url2->toAsciiString()); + + +?> +--EXPECT-- +NULL +string(11) "pass%00word" +string(33) "https://:pass%00word@example.com/" diff --git a/ext/uri/tests/whatwg/modification/path_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/path_success_null_byte.phpt new file mode 100644 index 0000000000000..c09a3aa2810f4 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/path_success_null_byte.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - path - null byte +--EXTENSIONS-- +uri +--FILE-- +withPath("/p\0th\0"); + +var_dump($url1->getPath()); +var_dump($url2->getPath()); +var_dump($url2->toAsciiString()); + +?> +--EXPECT-- +string(1) "/" +string(10) "/p%00th%00" +string(29) "https://example.com/p%00th%00" diff --git a/ext/uri/tests/whatwg/modification/query_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/query_success_null_byte.phpt new file mode 100644 index 0000000000000..81232d8b2aa2d --- /dev/null +++ b/ext/uri/tests/whatwg/modification/query_success_null_byte.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - query - null byte +--EXTENSIONS-- +uri +--FILE-- +withQuery("f\0o=bar&baz=q\0x"); + +var_dump($url1->getQuery()); +var_dump($url2->getQuery()); +var_dump($url2->toAsciiString()); + +?> +--EXPECT-- +NULL +string(19) "f%00o=bar&baz=q%00x" +string(40) "https://example.com/?f%00o=bar&baz=q%00x" diff --git a/ext/uri/tests/whatwg/modification/scheme_error_null_byte.phpt b/ext/uri/tests/whatwg/modification/scheme_error_null_byte.phpt new file mode 100644 index 0000000000000..ab2845ae64937 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/scheme_error_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - scheme - null byte +--EXTENSIONS-- +uri +--FILE-- +withScheme("sch\0me"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\WhatWg\InvalidUrlException: The specified scheme is malformed diff --git a/ext/uri/tests/whatwg/modification/username_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/username_success_null_byte.phpt new file mode 100644 index 0000000000000..86f6a62e0f200 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/username_success_null_byte.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - username - null byte +--EXTENSIONS-- +uri +--FILE-- +withUsername("usern\0me"); + +var_dump($url1->getUsername()); +var_dump($url2->getUsername()); +var_dump($url2->toAsciiString()); + + +?> +--EXPECT-- +NULL +string(10) "usern%00me" +string(31) "https://usern%00me@example.com/" diff --git a/ext/uri/tests/whatwg/parsing/basic_error_null_byte2.phpt b/ext/uri/tests/whatwg/parsing/basic_error_null_byte2.phpt deleted file mode 100644 index 6aa631c74e93e..0000000000000 --- a/ext/uri/tests/whatwg/parsing/basic_error_null_byte2.phpt +++ /dev/null @@ -1,14 +0,0 @@ ---TEST-- -Test Uri\WhatWg\Url parsing - basic - URL contains null byte ---FILE-- -getMessage(), PHP_EOL; -} - -?> ---EXPECT-- -ValueError: Uri\WhatWg\Url::parse(): Argument #1 ($uri) must not contain any null bytes diff --git a/ext/uri/tests/whatwg/parsing/basic_error_null_byte1.phpt b/ext/uri/tests/whatwg/parsing/host_error_null_byte.phpt similarity index 63% rename from ext/uri/tests/whatwg/parsing/basic_error_null_byte1.phpt rename to ext/uri/tests/whatwg/parsing/host_error_null_byte.phpt index db5cd075a6fa0..f450d26c41648 100644 --- a/ext/uri/tests/whatwg/parsing/basic_error_null_byte1.phpt +++ b/ext/uri/tests/whatwg/parsing/host_error_null_byte.phpt @@ -5,10 +5,10 @@ Test Uri\WhatWg\Url parsing - basic - URL contains null byte try { new Uri\WhatWg\Url("https://exam\0ple.com"); -} catch (ValueError $e) { +} catch (Throwable $e) { echo $e::class, ": ", $e->getMessage(), PHP_EOL; } ?> --EXPECT-- -ValueError: Uri\WhatWg\Url::__construct(): Argument #1 ($uri) must not contain any null bytes +Uri\WhatWg\InvalidUrlException: The specified URI is malformed (DomainInvalidCodePoint) diff --git a/ext/uri/tests/whatwg/parsing/password_success_null_byte.phpt b/ext/uri/tests/whatwg/parsing/password_success_null_byte.phpt new file mode 100644 index 0000000000000..9dada6a9f387e --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/password_success_null_byte.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - password - null byte +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + string(8) "username" + ["password"]=> + string(7) "%00pass" + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(37) "https://username:%00pass@example.com/" diff --git a/ext/uri/tests/whatwg/parsing/path_success_null_byte.phpt b/ext/uri/tests/whatwg/parsing/path_success_null_byte.phpt new file mode 100644 index 0000000000000..d20242dcee53a --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/path_success_null_byte.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - path - null byte +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(8) "/pa%00th" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(27) "https://example.com/pa%00th" diff --git a/ext/uri/tests/whatwg/parsing/query_success_null_byte.phpt b/ext/uri/tests/whatwg/parsing/query_success_null_byte.phpt new file mode 100644 index 0000000000000..bf1364365156b --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/query_success_null_byte.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - query - null byte +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + string(9) "fo%00=bar" + ["fragment"]=> + NULL +} +string(30) "https://example.com/?fo%00=bar" diff --git a/ext/uri/tests/whatwg/parsing/scheme_error_null_byte.phpt b/ext/uri/tests/whatwg/parsing/scheme_error_null_byte.phpt new file mode 100644 index 0000000000000..5674c1f330932 --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/scheme_error_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - scheme - null byte +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\WhatWg\InvalidUrlException: The specified URI is malformed (MissingSchemeNonRelativeUrl) diff --git a/ext/uri/tests/whatwg/parsing/username_success_null_byte.phpt b/ext/uri/tests/whatwg/parsing/username_success_null_byte.phpt new file mode 100644 index 0000000000000..d99c3cefdc153 --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/username_success_null_byte.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - username - null byte +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + string(11) "user%00name" + ["password"]=> + string(4) "pass" + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(37) "https://user%00name:pass@example.com/" diff --git a/ext/uri/tests/whatwg/reference_resolution/resolve_error_host_null_byte.phpt b/ext/uri/tests/whatwg/reference_resolution/resolve_error_host_null_byte.phpt new file mode 100644 index 0000000000000..ed31e0e5daead --- /dev/null +++ b/ext/uri/tests/whatwg/reference_resolution/resolve_error_host_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\WhatWg\Url reference resolution - resolve() - null byte +--EXTENSIONS-- +uri +--FILE-- +resolve("https://ex\0mple.com"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\WhatWg\InvalidUrlException: The specified URI is malformed (DomainInvalidCodePoint) diff --git a/ext/uri/tests/whatwg/reference_resolution/resolve_success_path_null_byte.phpt b/ext/uri/tests/whatwg/reference_resolution/resolve_success_path_null_byte.phpt new file mode 100644 index 0000000000000..abdcec98e8421 --- /dev/null +++ b/ext/uri/tests/whatwg/reference_resolution/resolve_success_path_null_byte.phpt @@ -0,0 +1,53 @@ +--TEST-- +Test Uri\WhatWg\Url reference resolution - resolve() - null byte in path +--EXTENSIONS-- +uri +--FILE-- +resolve("/f\0o"); + +var_dump($url1); +var_dump($url2); +var_dump($url2->toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#2 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(6) "/f%00o" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(25) "https://example.com/f%00o" From 139983f30537cd2c593cc3a33f34fabef15cc1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 19 Nov 2025 20:39:15 +0100 Subject: [PATCH 2/2] Add news [skip-ci] --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 4e7e49df81742..253e597cf2d4b 100644 --- a/NEWS +++ b/NEWS @@ -61,6 +61,10 @@ PHP NEWS . Fix assertion failures resulting in crashes with stream filter object parameters. (ndossche) +- URI: + . Fixed bug GH-20366 (ext/uri incorrectly throws ValueError when encountering + null byte). (kocsismate) + 20 Nov 2025, PHP 8.5.0 - Core: