diff --git a/RemoteCalls.php b/RemoteCalls.php index 084a673..c69c59f 100644 --- a/RemoteCalls.php +++ b/RemoteCalls.php @@ -165,7 +165,34 @@ protected function setLastCall($action) public static function getSiteUrl() { - return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . (isset($_SERVER['SCRIPT_URL']) ? $_SERVER['SCRIPT_URL'] : ''); + $scheme = ( + isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' + ? 'https' + : 'http' + ); + + $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; + $host = preg_replace('/[^A-Za-z0-9.\-:\[\]]/', '', $host); + + $path = ''; + if ( isset($_SERVER['SCRIPT_URL']) ) { + $path = $_SERVER['SCRIPT_URL']; + } elseif ( isset($_SERVER['REQUEST_URI']) ) { + $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); + } + + $path = $path ? (string)$path : ''; + $path = preg_replace('/[\x00-\x1F\x7F]/', '', $path); + $path = preg_replace('/[^A-Za-z0-9\-._~\/%]/', '', $path); + $path = preg_replace_callback('/%[0-9a-fA-F]{2}/', static function ($matches) { + return strtoupper($matches[0]); + }, $path); + $path = preg_replace('/%(?![0-9A-Fa-f]{2})/', '', $path); + if ( $path !== '' && $path[0] !== '/' ) { + $path = '/' . $path; + } + + return $scheme . '://' . $host . $path; } public static function buildParameters($rc_action, $plugin_name, $api_key, $additional_params) @@ -183,7 +210,6 @@ public static function buildParameters($rc_action, $plugin_name, $api_key, $addi /** * Performs remote call to the current website * - * @param string $host * @param string $rc_action * @param string $plugin_name * @param string $api_key diff --git a/tests/RemoteCalls/RemoteCallsGetSiteUrlTest.php b/tests/RemoteCalls/RemoteCallsGetSiteUrlTest.php new file mode 100644 index 0000000..07f3a3f --- /dev/null +++ b/tests/RemoteCalls/RemoteCallsGetSiteUrlTest.php @@ -0,0 +1,69 @@ +server_backup = $_SERVER; + } + + public function tearDown(): void + { + $_SERVER = $this->server_backup; + } + + public function testGetSiteUrlSanitizesScriptUrl() + { + $_SERVER['HTTPS'] = 'on'; + $_SERVER['HTTP_HOST'] = 'example.com'; + $_SERVER['SCRIPT_URL'] = '/'; + + $result = RemoteCalls::getSiteUrl(); + + self::assertSame('https://example.com/imgsrcxonerroralert1', $result); + self::assertStringNotContainsString('<', $result); + self::assertStringNotContainsString('>', $result); + self::assertStringNotContainsString('"', $result); + self::assertStringNotContainsString("'", $result); + } + + public function testGetSiteUrlFallsBackToRequestUri() + { + unset($_SERVER['SCRIPT_URL']); + unset($_SERVER['HTTPS']); + $_SERVER['HTTP_HOST'] = 'example.com'; + $_SERVER['REQUEST_URI'] = '/path/to/page?x='; + + $result = RemoteCalls::getSiteUrl(); + + self::assertSame('http://example.com/path/to/page', $result); + } + + public function testGetSiteUrlPreservesEncodedPathFromScriptUrl() + { + $_SERVER['HTTP_HOST'] = 'example.com'; + $_SERVER['SCRIPT_URL'] = '/a%20b/c%2fd'; + + $result = RemoteCalls::getSiteUrl(); + + self::assertSame('http://example.com/a%20b/c%2Fd', $result); + } + + public function testGetSiteUrlRemovesInvalidPercentFromRequestUri() + { + unset($_SERVER['SCRIPT_URL']); + $_SERVER['HTTP_HOST'] = 'example.com'; + $_SERVER['REQUEST_URI'] = '/a%2gb%zz'; + + $result = RemoteCalls::getSiteUrl(); + + self::assertSame('http://example.com/a2gbzz', $result); + } +}