diff --git a/system/HTTP/SiteURIFactory.php b/system/HTTP/SiteURIFactory.php index c87898c0470e..e920ba1634b3 100644 --- a/system/HTTP/SiteURIFactory.php +++ b/system/HTTP/SiteURIFactory.php @@ -111,8 +111,40 @@ public function detectRoutePath(string $protocol = ''): string */ private function parseRequestURI(): string { + $appConfig = $this->appConfig; + $baseUrl = $appConfig->baseURL; + $indexPage = $appConfig->indexPage; + $baseUri = false; + $parsedUrl = parse_url($baseUrl); + + if (isset($parsedUrl['path'])) { // The path could be empty if the url is just a domain + $baseUri = $parsedUrl['path']; + } + if ($baseUri) { + $baseUriArray = explode('/', $baseUri); + $baseUriArray = array_filter($baseUriArray); // We remove the empty strings from the array + $baseUri = implode('/', $baseUriArray); // We join the array back into a string with slashes + if ($baseUri !== '') { + $baseUri = '/' . $baseUri; // We add a slash at the beginning of the base Uri as implode will not do that + } else { + $baseUri = false; + } + } + + $serverRequestUri = $this->superglobals->server('REQUEST_URI'); // We get the request URI from the server superglobals + + if (null !== $serverRequestUri) { + if ($baseUri && str_starts_with($serverRequestUri, $baseUri)) { + $serverRequestUri = substr($serverRequestUri, strlen($baseUri)); + } // We remove the base Uri from the request URI if it exists, baseUri is the path to the subdirectory + if ($indexPage !== false && str_starts_with($serverRequestUri, '/' . $indexPage)) { + $serverRequestUri = substr($serverRequestUri, strlen('/' . $indexPage)); + } // We remove the index page from the request URI if it exists + $serverRequestUri = '/' . ltrim($serverRequestUri, '/'); // makes sure that the uri starts with a slash + } + if ( - $this->superglobals->server('REQUEST_URI') === null + $serverRequestUri === null || $this->superglobals->server('SCRIPT_NAME') === null ) { return ''; @@ -122,7 +154,7 @@ private function parseRequestURI(): string // string contains a colon followed by a number. So we attach a dummy // host since REQUEST_URI does not include the host. This allows us to // parse out the query string and path. - $parts = parse_url('http://dummy' . $this->superglobals->server('REQUEST_URI')); + $parts = parse_url('http://dummy' . $serverRequestUri); $query = $parts['query'] ?? ''; $path = $parts['path'] ?? ''; diff --git a/tests/system/HTTP/SiteURIFactoryTest.php b/tests/system/HTTP/SiteURIFactoryTest.php index b26fde04b245..737e2d8ddeb1 100644 --- a/tests/system/HTTP/SiteURIFactoryTest.php +++ b/tests/system/HTTP/SiteURIFactoryTest.php @@ -171,4 +171,53 @@ public static function provideCreateFromStringWithoutIndexPage(): iterable ], ]; } + + #[DataProvider('provideCreateFromStringWithIndexPageSubDirCombinations')] + public function testCreateFromStringWithIndexPageSubDirCombinations( + string $subDir, + string $indexPage, + ): void { + $standardUrl = 'http://localhost:8080'; + $standardScriptName = '/public/index.php'; + + $route = 'controller/method'; + $appConfig = new App(); + $appConfig->baseURL = $standardUrl . $subDir; + $appConfig->indexPage = $indexPage; + + $_SERVER['PATH_INFO'] = '/' . $route; + $_SERVER['REQUEST_URI'] = $subDir . '/' . $indexPage . $_SERVER['PATH_INFO']; + $_SERVER['SCRIPT_NAME'] = $subDir . $standardScriptName; + $_SERVER['HTTP_HOST'] = $standardUrl; + + $factory = $this->createSiteURIFactory($appConfig); + $detectedRoutePath = $factory->detectRoutePath(); + $this->assertSame($route, $detectedRoutePath); + } + + public static function provideCreateFromStringWithIndexPageSubDirCombinations(): iterable + { + return [ + 'no subdir and no index' => [ + '', + '', + ], + 'no subdir and index' => [ + '', + 'index.php', + ], + 'subdir and no index' => [ + '/subdir', + '', + ], + 'subdir and index' => [ + '/subdir', + 'index.php', + ], + 'subdir 2 levels deep string and index' => [ + '/subdir/subsubdir', + 'index.php', + ], + ]; + } }