Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/3rdparty.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'guzzlehttp/psr7/src/Uri.php')
-rw-r--r--guzzlehttp/psr7/src/Uri.php302
1 files changed, 116 insertions, 186 deletions
diff --git a/guzzlehttp/psr7/src/Uri.php b/guzzlehttp/psr7/src/Uri.php
index 0f9f020d..09e878d3 100644
--- a/guzzlehttp/psr7/src/Uri.php
+++ b/guzzlehttp/psr7/src/Uri.php
@@ -1,7 +1,10 @@
<?php
+declare(strict_types=1);
+
namespace GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\Exception\MalformedUriException;
use Psr\Http\Message\UriInterface;
/**
@@ -11,7 +14,7 @@ use Psr\Http\Message\UriInterface;
* @author Tobias Schultze
* @author Matthew Weier O'Phinney
*/
-class Uri implements UriInterface
+class Uri implements UriInterface, \JsonSerializable
{
/**
* Absolute http and https URIs require a host per RFC 7230 Section 2.7
@@ -19,9 +22,9 @@ class Uri implements UriInterface
* we apply this default host when no host is given yet to form a
* valid URI.
*/
- const HTTP_DEFAULT_HOST = 'localhost';
+ private const HTTP_DEFAULT_HOST = 'localhost';
- private static $defaultPorts = [
+ private const DEFAULT_PORTS = [
'http' => 80,
'https' => 443,
'ftp' => 21,
@@ -35,9 +38,20 @@ class Uri implements UriInterface
'ldap' => 389,
];
- private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
- private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
- private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
+ /**
+ * Unreserved characters for use in a regex.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-2.3
+ */
+ private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~';
+
+ /**
+ * Sub-delims for use in a regex.
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-2.2
+ */
+ private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';
+ private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26'];
/** @var string Uri scheme. */
private $scheme = '';
@@ -60,21 +74,19 @@ class Uri implements UriInterface
/** @var string Uri fragment. */
private $fragment = '';
- /**
- * @param string $uri URI to parse
- */
- public function __construct($uri = '')
+ /** @var string|null String representation */
+ private $composedComponents;
+
+ public function __construct(string $uri = '')
{
- // weak type check to also accept null until we can add scalar type hints
- if ($uri != '') {
+ if ($uri !== '') {
$parts = self::parse($uri);
if ($parts === false) {
- throw new \InvalidArgumentException("Unable to parse URI: $uri");
+ throw new MalformedUriException("Unable to parse URI: $uri");
}
$this->applyParts($parts);
}
}
-
/**
* UTF-8 aware \parse_url() replacement.
*
@@ -88,19 +100,19 @@ class Uri implements UriInterface
* @see https://www.php.net/manual/en/function.parse-url.php#114817
* @see https://curl.haxx.se/libcurl/c/CURLOPT_URL.html#ENCODING
*
- * @param string $url
- *
* @return array|false
*/
- private static function parse($url)
+ private static function parse(string $url)
{
// If IPv6
$prefix = '';
if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) {
+ /** @var array{0:string, 1:string, 2:string} $matches */
$prefix = $matches[1];
$url = $matches[2];
}
+ /** @var string */
$encodedUrl = preg_replace_callback(
'%[^:/@?&=#]+%usD',
static function ($matches) {
@@ -118,15 +130,19 @@ class Uri implements UriInterface
return array_map('urldecode', $result);
}
- public function __toString()
+ public function __toString(): string
{
- return self::composeComponents(
- $this->scheme,
- $this->getAuthority(),
- $this->path,
- $this->query,
- $this->fragment
- );
+ if ($this->composedComponents === null) {
+ $this->composedComponents = self::composeComponents(
+ $this->scheme,
+ $this->getAuthority(),
+ $this->path,
+ $this->query,
+ $this->fragment
+ );
+ }
+
+ return $this->composedComponents;
}
/**
@@ -145,17 +161,9 @@ class Uri implements UriInterface
* `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
* that format).
*
- * @param string $scheme
- * @param string $authority
- * @param string $path
- * @param string $query
- * @param string $fragment
- *
- * @return string
- *
* @link https://tools.ietf.org/html/rfc3986#section-5.3
*/
- public static function composeComponents($scheme, $authority, $path, $query, $fragment)
+ public static function composeComponents(?string $scheme, ?string $authority, string $path, ?string $query, ?string $fragment): string
{
$uri = '';
@@ -164,10 +172,14 @@ class Uri implements UriInterface
$uri .= $scheme . ':';
}
- if ($authority != ''|| $scheme === 'file') {
+ if ($authority != '' || $scheme === 'file') {
$uri .= '//' . $authority;
}
+ if ($authority != '' && $path != '' && $path[0] != '/') {
+ $path = '/' . $path;
+ }
+
$uri .= $path;
if ($query != '') {
@@ -186,15 +198,11 @@ class Uri implements UriInterface
*
* `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used
* independently of the implementation.
- *
- * @param UriInterface $uri
- *
- * @return bool
*/
- public static function isDefaultPort(UriInterface $uri)
+ public static function isDefaultPort(UriInterface $uri): bool
{
return $uri->getPort() === null
- || (isset(self::$defaultPorts[$uri->getScheme()]) && $uri->getPort() === self::$defaultPorts[$uri->getScheme()]);
+ || (isset(self::DEFAULT_PORTS[$uri->getScheme()]) && $uri->getPort() === self::DEFAULT_PORTS[$uri->getScheme()]);
}
/**
@@ -207,16 +215,12 @@ class Uri implements UriInterface
* - absolute-path references, e.g. '/path'
* - relative-path references, e.g. 'subpath'
*
- * @param UriInterface $uri
- *
- * @return bool
- *
* @see Uri::isNetworkPathReference
* @see Uri::isAbsolutePathReference
* @see Uri::isRelativePathReference
* @link https://tools.ietf.org/html/rfc3986#section-4
*/
- public static function isAbsolute(UriInterface $uri)
+ public static function isAbsolute(UriInterface $uri): bool
{
return $uri->getScheme() !== '';
}
@@ -226,13 +230,9 @@ class Uri implements UriInterface
*
* A relative reference that begins with two slash characters is termed an network-path reference.
*
- * @param UriInterface $uri
- *
- * @return bool
- *
* @link https://tools.ietf.org/html/rfc3986#section-4.2
*/
- public static function isNetworkPathReference(UriInterface $uri)
+ public static function isNetworkPathReference(UriInterface $uri): bool
{
return $uri->getScheme() === '' && $uri->getAuthority() !== '';
}
@@ -242,13 +242,9 @@ class Uri implements UriInterface
*
* A relative reference that begins with a single slash character is termed an absolute-path reference.
*
- * @param UriInterface $uri
- *
- * @return bool
- *
* @link https://tools.ietf.org/html/rfc3986#section-4.2
*/
- public static function isAbsolutePathReference(UriInterface $uri)
+ public static function isAbsolutePathReference(UriInterface $uri): bool
{
return $uri->getScheme() === ''
&& $uri->getAuthority() === ''
@@ -261,13 +257,9 @@ class Uri implements UriInterface
*
* A relative reference that does not begin with a slash character is termed a relative-path reference.
*
- * @param UriInterface $uri
- *
- * @return bool
- *
* @link https://tools.ietf.org/html/rfc3986#section-4.2
*/
- public static function isRelativePathReference(UriInterface $uri)
+ public static function isRelativePathReference(UriInterface $uri): bool
{
return $uri->getScheme() === ''
&& $uri->getAuthority() === ''
@@ -284,11 +276,9 @@ class Uri implements UriInterface
* @param UriInterface $uri The URI to check
* @param UriInterface|null $base An optional base URI to compare against
*
- * @return bool
- *
* @link https://tools.ietf.org/html/rfc3986#section-4.4
*/
- public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null)
+ public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool
{
if ($base !== null) {
$uri = UriResolver::resolve($base, $uri);
@@ -303,41 +293,6 @@ class Uri implements UriInterface
}
/**
- * Removes dot segments from a path and returns the new path.
- *
- * @param string $path
- *
- * @return string
- *
- * @deprecated since version 1.4. Use UriResolver::removeDotSegments instead.
- * @see UriResolver::removeDotSegments
- */
- public static function removeDotSegments($path)
- {
- return UriResolver::removeDotSegments($path);
- }
-
- /**
- * Converts the relative URI into a new URI that is resolved against the base URI.
- *
- * @param UriInterface $base Base URI
- * @param string|UriInterface $rel Relative URI
- *
- * @return UriInterface
- *
- * @deprecated since version 1.4. Use UriResolver::resolve instead.
- * @see UriResolver::resolve
- */
- public static function resolve(UriInterface $base, $rel)
- {
- if (!($rel instanceof UriInterface)) {
- $rel = new self($rel);
- }
-
- return UriResolver::resolve($base, $rel);
- }
-
- /**
* Creates a new URI with a specific query string value removed.
*
* Any existing query string values that exactly match the provided key are
@@ -345,10 +300,8 @@ class Uri implements UriInterface
*
* @param UriInterface $uri URI to use as a base.
* @param string $key Query string key to remove.
- *
- * @return UriInterface
*/
- public static function withoutQueryValue(UriInterface $uri, $key)
+ public static function withoutQueryValue(UriInterface $uri, string $key): UriInterface
{
$result = self::getFilteredQueryString($uri, [$key]);
@@ -367,10 +320,8 @@ class Uri implements UriInterface
* @param UriInterface $uri URI to use as a base.
* @param string $key Key to set.
* @param string|null $value Value to set
- *
- * @return UriInterface
*/
- public static function withQueryValue(UriInterface $uri, $key, $value)
+ public static function withQueryValue(UriInterface $uri, string $key, ?string $value): UriInterface
{
$result = self::getFilteredQueryString($uri, [$key]);
@@ -384,17 +335,15 @@ class Uri implements UriInterface
*
* It has the same behavior as withQueryValue() but for an associative array of key => value.
*
- * @param UriInterface $uri URI to use as a base.
- * @param array $keyValueArray Associative array of key and values
- *
- * @return UriInterface
+ * @param UriInterface $uri URI to use as a base.
+ * @param array<string, string|null> $keyValueArray Associative array of key and values
*/
- public static function withQueryValues(UriInterface $uri, array $keyValueArray)
+ public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface
{
$result = self::getFilteredQueryString($uri, array_keys($keyValueArray));
foreach ($keyValueArray as $key => $value) {
- $result[] = self::generateQueryString($key, $value);
+ $result[] = self::generateQueryString((string) $key, $value !== null ? (string) $value : null);
}
return $uri->withQuery(implode('&', $result));
@@ -403,15 +352,11 @@ class Uri implements UriInterface
/**
* Creates a URI from a hash of `parse_url` components.
*
- * @param array $parts
- *
- * @return UriInterface
- *
* @link http://php.net/manual/en/function.parse-url.php
*
- * @throws \InvalidArgumentException If the components do not form a valid URI.
+ * @throws MalformedUriException If the components do not form a valid URI.
*/
- public static function fromParts(array $parts)
+ public static function fromParts(array $parts): UriInterface
{
$uri = new self();
$uri->applyParts($parts);
@@ -420,12 +365,12 @@ class Uri implements UriInterface
return $uri;
}
- public function getScheme()
+ public function getScheme(): string
{
return $this->scheme;
}
- public function getAuthority()
+ public function getAuthority(): string
{
$authority = $this->host;
if ($this->userInfo !== '') {
@@ -439,37 +384,37 @@ class Uri implements UriInterface
return $authority;
}
- public function getUserInfo()
+ public function getUserInfo(): string
{
return $this->userInfo;
}
- public function getHost()
+ public function getHost(): string
{
return $this->host;
}
- public function getPort()
+ public function getPort(): ?int
{
return $this->port;
}
- public function getPath()
+ public function getPath(): string
{
return $this->path;
}
- public function getQuery()
+ public function getQuery(): string
{
return $this->query;
}
- public function getFragment()
+ public function getFragment(): string
{
return $this->fragment;
}
- public function withScheme($scheme)
+ public function withScheme($scheme): UriInterface
{
$scheme = $this->filterScheme($scheme);
@@ -479,13 +424,14 @@ class Uri implements UriInterface
$new = clone $this;
$new->scheme = $scheme;
+ $new->composedComponents = null;
$new->removeDefaultPort();
$new->validateState();
return $new;
}
- public function withUserInfo($user, $password = null)
+ public function withUserInfo($user, $password = null): UriInterface
{
$info = $this->filterUserInfoComponent($user);
if ($password !== null) {
@@ -498,12 +444,13 @@ class Uri implements UriInterface
$new = clone $this;
$new->userInfo = $info;
+ $new->composedComponents = null;
$new->validateState();
return $new;
}
- public function withHost($host)
+ public function withHost($host): UriInterface
{
$host = $this->filterHost($host);
@@ -513,12 +460,13 @@ class Uri implements UriInterface
$new = clone $this;
$new->host = $host;
+ $new->composedComponents = null;
$new->validateState();
return $new;
}
- public function withPort($port)
+ public function withPort($port): UriInterface
{
$port = $this->filterPort($port);
@@ -528,13 +476,14 @@ class Uri implements UriInterface
$new = clone $this;
$new->port = $port;
+ $new->composedComponents = null;
$new->removeDefaultPort();
$new->validateState();
return $new;
}
- public function withPath($path)
+ public function withPath($path): UriInterface
{
$path = $this->filterPath($path);
@@ -544,12 +493,13 @@ class Uri implements UriInterface
$new = clone $this;
$new->path = $path;
+ $new->composedComponents = null;
$new->validateState();
return $new;
}
- public function withQuery($query)
+ public function withQuery($query): UriInterface
{
$query = $this->filterQueryAndFragment($query);
@@ -559,11 +509,12 @@ class Uri implements UriInterface
$new = clone $this;
$new->query = $query;
+ $new->composedComponents = null;
return $new;
}
- public function withFragment($fragment)
+ public function withFragment($fragment): UriInterface
{
$fragment = $this->filterQueryAndFragment($fragment);
@@ -573,16 +524,22 @@ class Uri implements UriInterface
$new = clone $this;
$new->fragment = $fragment;
+ $new->composedComponents = null;
return $new;
}
+ public function jsonSerialize(): string
+ {
+ return $this->__toString();
+ }
+
/**
* Apply parse_url parts to a URI.
*
* @param array $parts Array of parse_url parts to apply.
*/
- private function applyParts(array $parts)
+ private function applyParts(array $parts): void
{
$this->scheme = isset($parts['scheme'])
? $this->filterScheme($parts['scheme'])
@@ -613,13 +570,11 @@ class Uri implements UriInterface
}
/**
- * @param string $scheme
- *
- * @return string
+ * @param mixed $scheme
*
* @throws \InvalidArgumentException If the scheme is invalid.
*/
- private function filterScheme($scheme)
+ private function filterScheme($scheme): string
{
if (!is_string($scheme)) {
throw new \InvalidArgumentException('Scheme must be a string');
@@ -629,33 +584,29 @@ class Uri implements UriInterface
}
/**
- * @param string $component
- *
- * @return string
+ * @param mixed $component
*
* @throws \InvalidArgumentException If the user info is invalid.
*/
- private function filterUserInfoComponent($component)
+ private function filterUserInfoComponent($component): string
{
if (!is_string($component)) {
throw new \InvalidArgumentException('User info must be a string');
}
return preg_replace_callback(
- '/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/',
+ '/(?:[^%' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . ']+|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$component
);
}
/**
- * @param string $host
- *
- * @return string
+ * @param mixed $host
*
* @throws \InvalidArgumentException If the host is invalid.
*/
- private function filterHost($host)
+ private function filterHost($host): string
{
if (!is_string($host)) {
throw new \InvalidArgumentException('Host must be a string');
@@ -665,13 +616,11 @@ class Uri implements UriInterface
}
/**
- * @param int|null $port
- *
- * @return int|null
+ * @param mixed $port
*
* @throws \InvalidArgumentException If the port is invalid.
*/
- private function filterPort($port)
+ private function filterPort($port): ?int
{
if ($port === null) {
return null;
@@ -688,12 +637,11 @@ class Uri implements UriInterface
}
/**
- * @param UriInterface $uri
- * @param array $keys
+ * @param string[] $keys
*
- * @return array
+ * @return string[]
*/
- private static function getFilteredQueryString(UriInterface $uri, array $keys)
+ private static function getFilteredQueryString(UriInterface $uri, array $keys): array
{
$current = $uri->getQuery();
@@ -708,27 +656,21 @@ class Uri implements UriInterface
});
}
- /**
- * @param string $key
- * @param string|null $value
- *
- * @return string
- */
- private static function generateQueryString($key, $value)
+ private static function generateQueryString(string $key, ?string $value): string
{
// Query string separators ("=", "&") within the key or value need to be encoded
// (while preventing double-encoding) before setting the query string. All other
// chars that need percent-encoding will be encoded by withQuery().
- $queryString = strtr($key, self::$replaceQuery);
+ $queryString = strtr($key, self::QUERY_SEPARATORS_REPLACEMENT);
if ($value !== null) {
- $queryString .= '=' . strtr($value, self::$replaceQuery);
+ $queryString .= '=' . strtr($value, self::QUERY_SEPARATORS_REPLACEMENT);
}
return $queryString;
}
- private function removeDefaultPort()
+ private function removeDefaultPort(): void
{
if ($this->port !== null && self::isDefaultPort($this)) {
$this->port = null;
@@ -738,20 +680,18 @@ class Uri implements UriInterface
/**
* Filters the path of a URI
*
- * @param string $path
- *
- * @return string
+ * @param mixed $path
*
* @throws \InvalidArgumentException If the path is invalid.
*/
- private function filterPath($path)
+ private function filterPath($path): string
{
if (!is_string($path)) {
throw new \InvalidArgumentException('Path must be a string');
}
return preg_replace_callback(
- '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
+ '/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$path
);
@@ -760,31 +700,29 @@ class Uri implements UriInterface
/**
* Filters the query string or fragment of a URI.
*
- * @param string $str
- *
- * @return string
+ * @param mixed $str
*
* @throws \InvalidArgumentException If the query or fragment is invalid.
*/
- private function filterQueryAndFragment($str)
+ private function filterQueryAndFragment($str): string
{
if (!is_string($str)) {
throw new \InvalidArgumentException('Query and fragment must be a string');
}
return preg_replace_callback(
- '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
+ '/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$str
);
}
- private function rawurlencodeMatchZero(array $match)
+ private function rawurlencodeMatchZero(array $match): string
{
return rawurlencode($match[0]);
}
- private function validateState()
+ private function validateState(): void
{
if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
$this->host = self::HTTP_DEFAULT_HOST;
@@ -792,19 +730,11 @@ class Uri implements UriInterface
if ($this->getAuthority() === '') {
if (0 === strpos($this->path, '//')) {
- throw new \InvalidArgumentException('The path of a URI without an authority must not start with two slashes "//"');
+ throw new MalformedUriException('The path of a URI without an authority must not start with two slashes "//"');
}
if ($this->scheme === '' && false !== strpos(explode('/', $this->path, 2)[0], ':')) {
- throw new \InvalidArgumentException('A relative URI must not have a path beginning with a segment containing a colon');
+ throw new MalformedUriException('A relative URI must not have a path beginning with a segment containing a colon');
}
- } elseif (isset($this->path[0]) && $this->path[0] !== '/') {
- @trigger_error(
- 'The path of a URI with an authority must start with a slash "/" or be empty. Automagically fixing the URI ' .
- 'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.',
- E_USER_DEPRECATED
- );
- $this->path = '/' . $this->path;
- //throw new \InvalidArgumentException('The path of a URI with an authority must start with a slash "/" or be empty');
}
}
}