Commit 9eeb1e8f7e9 for php

commit 9eeb1e8f7e944e77597831568aea8c78e4198405
Author: NickSdot <32384907+NickSdot@users.noreply.github.com>
Date:   Mon Sep 28 02:12:06 2026 +0700

    ext/uri: fixed url path resolution (#23817)

diff --git a/ext/uri/tests/whatwg/builder/path_success_hashmark_with_base.phpt b/ext/uri/tests/whatwg/builder/path_success_hashmark_with_base.phpt
new file mode 100644
index 00000000000..0f385b2d73f
--- /dev/null
+++ b/ext/uri/tests/whatwg/builder/path_success_hashmark_with_base.phpt
@@ -0,0 +1,53 @@
+--TEST--
+Test Uri\WhatWg\UrlBuilder::setPath() - success - hashmark with base URL
+--FILE--
+<?php
+
+$base = new Uri\WhatWg\Url('https://user:pass@example.com:123/base/path?oldQuery#oldFragment');
+
+$errors = [];
+
+$url = new Uri\WhatWg\UrlBuilder()
+    ->setPath('newPath#value')
+    ->build($base, $errors);
+
+var_dump($url->toAsciiString());
+var_dump($url);
+var_dump($errors);
+var_dump($url->equals(new Uri\WhatWg\Url($url->toAsciiString())));
+var_dump($url->equals(new Uri\WhatWg\Url('newPath%23value', $base), Uri\UriComparisonMode::IncludeFragment));
+
+?>
+--EXPECTF--
+string(54) "https://user:pass@example.com:123/base/newPath%23value"
+object(Uri\WhatWg\Url)#%d (%d) {
+  ["scheme"]=>
+  string(5) "https"
+  ["username"]=>
+  string(4) "user"
+  ["password"]=>
+  string(4) "pass"
+  ["host"]=>
+  string(11) "example.com"
+  ["port"]=>
+  int(123)
+  ["path"]=>
+  string(21) "/base/newPath%23value"
+  ["query"]=>
+  NULL
+  ["fragment"]=>
+  NULL
+}
+array(1) {
+  [0]=>
+  object(Uri\WhatWg\UrlValidationError)#%d (%d) {
+    ["context"]=>
+    string(6) "#value"
+    ["type"]=>
+    enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit)
+    ["failure"]=>
+    bool(false)
+  }
+}
+bool(true)
+bool(true)
diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c
index 3e1e587da75..5170849e328 100644
--- a/ext/uri/uri_parser_whatwg.c
+++ b/ext/uri/uri_parser_whatwg.c
@@ -1137,6 +1137,10 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2, 3, 4, 5, 6, 7, 8, 9) lxb_url_t *php_uri_parser
 				smart_str_appends(&reference, "%3F");
 			} else if (*p == '#') {
 				smart_str_appends(&reference, "%23");
+				const char *reason;
+				append_validation_error(
+					Z_ARRVAL(errors), LXB_URL_ERROR_TYPE_INVALID_URL_UNIT, p, &reason
+				);
 			} else {
 				smart_str_appendc(&reference, *p);
 			}