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);
+ }
+}