Commit de3436c76e4 for php.net

commit de3436c76e460ca44829cc8234926280d96ceae6
Author: Jordi Kroon <jkroon@onyourmarks.agency>
Date:   Mon Aug 31 19:16:00 2026 +0200

    ext/standard: Fix 1-char relative Location redirects after GH-23467

    8196275133e changed the relative-Location check from location_len > 1 to
    > 0, so a single-character Location began resolving against the request
    path instead of the host root as before.

    Closes GH-23521

diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
index 9bd12ba527c..891c1b23955 100644
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -1060,7 +1060,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
 			{
 				char *loc_path = NULL;
 				if (*header_info.location != '/') {
-					if (header_info.location_len > 0 && resource->path) {
+					if (header_info.location_len > 1 && resource->path) {
 						char *s = strrchr(ZSTR_VAL(resource->path), '/');
 						if (!s) {
 							s = ZSTR_VAL(resource->path);
diff --git a/ext/standard/tests/http/http_single_char_location_redirect.phpt b/ext/standard/tests/http/http_single_char_location_redirect.phpt
new file mode 100644
index 00000000000..66af7a43253
--- /dev/null
+++ b/ext/standard/tests/http/http_single_char_location_redirect.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Single-char relative Location header keeps resolving against the host root (pre-GH-23467 behavior)
+--DESCRIPTION--
+Not RFC 3986 compliant ("x" against "/a/b" gives "/a/x"), but matches
+PHP's long-standing behavior of resolving against the host root. See GH-23521.
+--FILE--
+<?php
+$serverCode = <<<'CODE'
+$server = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr);
+phpt_notify_server_start($server);
+
+for ($n = 0; $n < 2; $n++) {
+    $conn = stream_socket_accept($server, 10);
+    if (!$conn) {
+        break;
+    }
+    $req = fgets($conn);
+    while (trim(fgets($conn)) !== '') {}
+    $uri = explode(' ', $req)[1];
+    if ($n < 1) {
+        fwrite($conn, "HTTP/1.1 302 Found\r\nLocation: x\r\nContent-Length: 0\r\n\r\n");
+    } else {
+        $body = "uri=$uri";
+        fwrite($conn, "HTTP/1.1 200 OK\r\nContent-Length: " . strlen($body) . "\r\n\r\n$body");
+    }
+    fclose($conn);
+}
+CODE;
+
+$clientCode = <<<'CODE'
+$ctx = stream_context_create(['http' => ['follow_location' => 1]]);
+echo @file_get_contents("http://{{ ADDR }}/a/b", false, $ctx), "\n";
+CODE;
+
+include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+?>
+--EXPECT--
+uri=/x