diff --git a/CHANGELOG.md b/CHANGELOG.md index b558746..743d797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ Attention: this is a major release with breaking changes. - Event and content tracking requests now send `&ca=1` (custom action), so Matomo no longer falls back to recording them as page views if the handling plugin is disabled (#80). - The `cip` (override IP) tracking parameter is now URL-encoded like every other value (#151). - No longer calls the deprecated `curl_close()` (it was already a no-op on the supported PHP versions) (#149). +- Auto-detection of the tracked page URL now uses `REQUEST_URI` as the source instead of `PATH_INFO`. With front-controller / path-info routing (e.g. `/dir1/page` handled by `dir1/index.php`), `PATH_INFO` only holds the trailing `/page`, so the tracker previously recorded a truncated URL; it now records the full requested path. `PATH_INFO` is no longer used at all (`SCRIPT_NAME` remains the fallback when `REQUEST_URI` is unavailable) (#141). ### Added - PHPStan static analysis at max level (`phpstan.neon.dist`) and the Matomo coding standard via PHP_CodeSniffer (`phpcs.xml.dist`), both enforced for every pull request through GitHub Actions. diff --git a/MatomoTracker.php b/MatomoTracker.php index f77dcbc..591ba59 100644 --- a/MatomoTracker.php +++ b/MatomoTracker.php @@ -2621,24 +2621,26 @@ protected function getCookieMatchingName(string $name): string|false } /** - * If current URL is "http://example.org/dir1/dir2/index.php?param1=value1¶m2=value2" - * will return "/dir1/dir2/index.php" + * Returns the path portion of the URL the visitor requested (everything between the host and + * the query string). For "http://example.org/dir1/dir2/index.php?param1=value1" this returns + * "/dir1/dir2/index.php"; for a front-controller URL such as "http://example.org/dir1/page" + * (where "/page" is handled by dir1/index.php) it returns "/dir1/page". + * + * The full request path is taken from REQUEST_URI. PATH_INFO is deliberately not used: it only + * holds the trailing path-info segment (e.g. "/page"), so it would drop the directory/script + * prefix and yield a truncated URL. SCRIPT_NAME is the fallback when REQUEST_URI is unavailable. * * @ignore */ protected static function getCurrentScriptName(): string { $url = ''; - if (!empty($_SERVER['PATH_INFO'])) { - $url = self::toStringValue($_SERVER['PATH_INFO']); - } else { - if (!empty($_SERVER['REQUEST_URI'])) { - $requestUri = self::toStringValue($_SERVER['REQUEST_URI']); - if (($pos = strpos($requestUri, '?')) !== false) { - $url = substr($requestUri, 0, $pos); - } else { - $url = $requestUri; - } + if (!empty($_SERVER['REQUEST_URI'])) { + $requestUri = self::toStringValue($_SERVER['REQUEST_URI']); + if (($pos = strpos($requestUri, '?')) !== false) { + $url = substr($requestUri, 0, $pos); + } else { + $url = $requestUri; } } if (empty($url) && isset($_SERVER['SCRIPT_NAME'])) { diff --git a/tests/Unit/MatomoTrackerTest.php b/tests/Unit/MatomoTrackerTest.php index de2057a..e971e1d 100644 --- a/tests/Unit/MatomoTrackerTest.php +++ b/tests/Unit/MatomoTrackerTest.php @@ -1848,17 +1848,24 @@ public function testGetCurrentScriptName(): void unset($_SERVER['PATH_INFO'], $_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']); $this->assertSame('/', TestableMatomoTracker::callGetCurrentScriptName()); + // SCRIPT_NAME is only the fallback when REQUEST_URI is unavailable. $_SERVER['SCRIPT_NAME'] = 'script.php'; $this->assertSame('/script.php', TestableMatomoTracker::callGetCurrentScriptName()); + // REQUEST_URI is the primary source; the query string is stripped. $_SERVER['REQUEST_URI'] = '/dir/page.php?query=1'; $this->assertSame('/dir/page.php', TestableMatomoTracker::callGetCurrentScriptName()); $_SERVER['REQUEST_URI'] = '/dir/other.php'; $this->assertSame('/dir/other.php', TestableMatomoTracker::callGetCurrentScriptName()); - $_SERVER['PATH_INFO'] = '/path/info'; - $this->assertSame('/path/info', TestableMatomoTracker::callGetCurrentScriptName()); + // Front-controller / path-info routing: with a request for /dir1/page handled by + // dir1/index.php, PATH_INFO is only "/page". The full requested path must still be tracked, + // so REQUEST_URI wins and PATH_INFO is ignored (previously it truncated the URL to "/page"). + $_SERVER['REQUEST_URI'] = '/dir1/page'; + $_SERVER['PATH_INFO'] = '/page'; + $_SERVER['SCRIPT_NAME'] = '/dir1/index.php'; + $this->assertSame('/dir1/page', TestableMatomoTracker::callGetCurrentScriptName()); } public function testGetCurrentQueryStringAndUrl(): void @@ -1871,7 +1878,8 @@ public function testGetCurrentQueryStringAndUrl(): void $_SERVER['HTTPS'] = 'on'; $_SERVER['HTTP_HOST'] = 'matomo.example'; - $_SERVER['PATH_INFO'] = '/page'; + unset($_SERVER['PATH_INFO']); + $_SERVER['REQUEST_URI'] = '/page'; $this->assertSame('https://matomo.example/page?a=b&c=d', TestableMatomoTracker::callGetCurrentUrl()); }