diff --git a/composer.json b/composer.json index 021fd4ff213..aba063686dd 100644 --- a/composer.json +++ b/composer.json @@ -44,6 +44,8 @@ "enshrined/svg-sanitize": "~0.16.0", "guzzlehttp/guzzle": "^7.2.0", "illuminate/collections": "^9.1.0", + "league/uri": "^7.4", + "league/uri-components": "^7.4", "mikehaertl/php-shellcommand": "^1.6.3", "moneyphp/money": "^4.0", "monolog/monolog": "^3.0", diff --git a/composer.lock b/composer.lock index 82a6e469ab6..12ddd75d50b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "698cc80afd3bb889d645ac8c8b1a0481", + "content-hash": "f58bf62c1f29f54ddf8df939639c9616", "packages": [ { "name": "bacon/bacon-qr-code", @@ -1591,6 +1591,262 @@ ], "time": "2023-11-17T17:00:27+00:00" }, + { + "name": "league/uri", + "version": "7.4.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "bf414ba956d902f5d98bf9385fcf63954f09dce5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/bf414ba956d902f5d98bf9385fcf63954f09dce5", + "reference": "bf414ba956d902f5d98bf9385fcf63954f09dce5", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.3", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "league/uri-components": "Needed to easily manipulate URI objects components", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.4.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2023-12-01T06:24:25+00:00" + }, + { + "name": "league/uri-components", + "version": "7.4.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-components.git", + "reference": "9b710019639c1a37692c86159f134a8a6c11de0f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/9b710019639c1a37692c86159f134a8a6c11de0f", + "reference": "9b710019639c1a37692c86159f134a8a6c11de0f", + "shasum": "" + }, + "require": { + "league/uri": "^7.3", + "php": "^8.1" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "ext-mbstring": "to use the sorting algorithm of URLSearchParams", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI components manipulation library", + "homepage": "http://uri.thephpleague.com", + "keywords": [ + "authority", + "components", + "fragment", + "host", + "middleware", + "modifier", + "path", + "port", + "query", + "rfc3986", + "scheme", + "uri", + "url", + "userinfo" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-components/tree/7.4.0" + }, + "funding": [ + { + "url": "https://github.com/nyamsprod", + "type": "github" + } + ], + "time": "2023-12-01T06:24:25+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.4.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "bd8c487ec236930f7bbc42b8d374fa882fbba0f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/bd8c487ec236930f7bbc42b8d374fa882fbba0f3", + "reference": "bd8c487ec236930f7bbc42b8d374fa882fbba0f3", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-factory": "^1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interfaces and classes for URI representation and interaction", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.4.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2023-11-24T15:40:42+00:00" + }, { "name": "mikehaertl/php-shellcommand", "version": "1.7.0", @@ -10271,5 +10527,5 @@ "platform-overrides": { "php": "8.2" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/helpers/UrlHelper.php b/src/helpers/UrlHelper.php index 28beceb3d0b..e0bbd2dd676 100644 --- a/src/helpers/UrlHelper.php +++ b/src/helpers/UrlHelper.php @@ -9,6 +9,10 @@ use Craft; use craft\errors\SiteNotFoundException; +use League\Uri\BaseUri; +use League\Uri\Components\Query; +use League\Uri\Http; +use League\Uri\Uri; use yii\base\Exception; /** @@ -27,7 +31,7 @@ class UrlHelper */ public static function isAbsoluteUrl(string $url): bool { - return (str_starts_with($url, 'http://') || str_starts_with($url, 'https://')); + return BaseUri::from($url)->isAbsolute(); } /** @@ -38,7 +42,7 @@ public static function isAbsoluteUrl(string $url): bool */ public static function isProtocolRelativeUrl(string $url): bool { - return (str_starts_with($url, '//')); + return BaseUri::from($url)->isNetworkPath(); } /** @@ -49,7 +53,7 @@ public static function isProtocolRelativeUrl(string $url): bool */ public static function isRootRelativeUrl(string $url): bool { - return (str_starts_with($url, '/') && !static::isProtocolRelativeUrl($url)); + return BaseUri::from($url)->isAbsolutePath(); } /** @@ -134,20 +138,9 @@ public static function urlWithParams(string $url, array|string $params): string */ public static function removeParam(string $url, string $param): string { - // Extract any params/fragment from the base URL - [$url, $params, $fragment] = self::_extractParams($url); - - // Remove the param - unset($params[$param]); - - // Rebuild - if (($query = static::buildQuery($params)) !== '') { - $url .= '?' . $query; - } - if ($fragment !== null) { - $url .= '#' . $fragment; - } - return $url; + return Uri::new($url)->withQuery( + Query::fromUri($url)->withoutParameters($param) + )->toString(); } /** @@ -182,16 +175,13 @@ public static function urlWithScheme(string $url, string $scheme): string return $url; } - if (static::isProtocolRelativeUrl($url)) { - return $scheme . ':' . $url; - } + $uri = Uri::new($url); if (static::isRootRelativeUrl($url)) { - // Prepend the current request’s scheme and hostname - $url = static::siteHost() . $url; + $uri = $uri->withHost(static::host()); } - return preg_replace('/^https?:/', $scheme . ':', $url); + return $uri->withScheme($scheme)->toString(); } /** @@ -216,16 +206,12 @@ public static function encodeParams(string $url): string */ public static function rootRelativeUrl(string $url): string { - $url = static::urlWithScheme($url, 'http'); - if (strlen($url) > 7 && ($slash = strpos($url, '/', 7)) !== false) { - return substr($url, $slash); - } - // Is this a host without a URI? - if (str_contains($url, '//')) { - return '/'; - } - // Must just be a URI, then - return '/' . $url; + return Uri::new($url) + ->withScheme(null) + ->withHost(null) + ->withPort(null) + ->withUserInfo(null) + ->toString(); } /**