class Uri in Auth0 Single Sign On 8.2
PSR-7 URI implementation.
@author Michael Dowling @author Tobias Schultze @author Matthew Weier O'Phinney
Hierarchy
- class \GuzzleHttp\Psr7\Uri implements UriInterface
Expanded class hierarchy of Uri
File
- vendor/
guzzlehttp/ psr7/ src/ Uri.php, line 13
Namespace
GuzzleHttp\Psr7View source
class Uri implements UriInterface {
/**
* Absolute http and https URIs require a host per RFC 7230 Section 2.7
* but in generic URIs the host can be empty. So for http(s) URIs
* we apply this default host when no host is given yet to form a
* valid URI.
*/
const HTTP_DEFAULT_HOST = 'localhost';
private static $defaultPorts = [
'http' => 80,
'https' => 443,
'ftp' => 21,
'gopher' => 70,
'nntp' => 119,
'news' => 119,
'telnet' => 23,
'tn3270' => 23,
'imap' => 143,
'pop' => 110,
'ldap' => 389,
];
private static $charUnreserved = 'a-zA-Z0-9_\\-\\.~';
private static $charSubDelims = '!\\$&\'\\(\\)\\*\\+,;=';
private static $replaceQuery = [
'=' => '%3D',
'&' => '%26',
];
/** @var string Uri scheme. */
private $scheme = '';
/** @var string Uri user info. */
private $userInfo = '';
/** @var string Uri host. */
private $host = '';
/** @var int|null Uri port. */
private $port;
/** @var string Uri path. */
private $path = '';
/** @var string Uri query string. */
private $query = '';
/** @var string Uri fragment. */
private $fragment = '';
/**
* @param string $uri URI to parse
*/
public function __construct($uri = '') {
// weak type check to also accept null until we can add scalar type hints
if ($uri != '') {
$parts = parse_url($uri);
if ($parts === false) {
throw new \InvalidArgumentException("Unable to parse URI: {$uri}");
}
$this
->applyParts($parts);
}
}
public function __toString() {
return self::composeComponents($this->scheme, $this
->getAuthority(), $this->path, $this->query, $this->fragment);
}
/**
* Composes a URI reference string from its various components.
*
* Usually this method does not need to be called manually but instead is used indirectly via
* `Psr\Http\Message\UriInterface::__toString`.
*
* PSR-7 UriInterface treats an empty component the same as a missing component as
* getQuery(), getFragment() etc. always return a string. This explains the slight
* difference to RFC 3986 Section 5.3.
*
* Another adjustment is that the authority separator is added even when the authority is missing/empty
* for the "file" scheme. This is because PHP stream functions like `file_get_contents` only work with
* `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But
* `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) {
$uri = '';
// weak type checks to also accept null until we can add scalar type hints
if ($scheme != '') {
$uri .= $scheme . ':';
}
if ($authority != '' || $scheme === 'file') {
$uri .= '//' . $authority;
}
$uri .= $path;
if ($query != '') {
$uri .= '?' . $query;
}
if ($fragment != '') {
$uri .= '#' . $fragment;
}
return $uri;
}
/**
* Whether the URI has the default port of the current scheme.
*
* `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) {
return $uri
->getPort() === null || isset(self::$defaultPorts[$uri
->getScheme()]) && $uri
->getPort() === self::$defaultPorts[$uri
->getScheme()];
}
/**
* Whether the URI is absolute, i.e. it has a scheme.
*
* An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true
* if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative
* to another URI, the base URI. Relative references can be divided into several forms:
* - network-path references, e.g. '//example.com/path'
* - 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) {
return $uri
->getScheme() !== '';
}
/**
* Whether the URI is a network-path reference.
*
* 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) {
return $uri
->getScheme() === '' && $uri
->getAuthority() !== '';
}
/**
* Whether the URI is a absolute-path reference.
*
* 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) {
return $uri
->getScheme() === '' && $uri
->getAuthority() === '' && isset($uri
->getPath()[0]) && $uri
->getPath()[0] === '/';
}
/**
* Whether the URI is a relative-path reference.
*
* 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) {
return $uri
->getScheme() === '' && $uri
->getAuthority() === '' && (!isset($uri
->getPath()[0]) || $uri
->getPath()[0] !== '/');
}
/**
* Whether the URI is a same-document reference.
*
* A same-document reference refers to a URI that is, aside from its fragment
* component, identical to the base URI. When no base URI is given, only an empty
* URI reference (apart from its fragment) is considered a same-document reference.
*
* @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) {
if ($base !== null) {
$uri = UriResolver::resolve($base, $uri);
return $uri
->getScheme() === $base
->getScheme() && $uri
->getAuthority() === $base
->getAuthority() && $uri
->getPath() === $base
->getPath() && $uri
->getQuery() === $base
->getQuery();
}
return $uri
->getScheme() === '' && $uri
->getAuthority() === '' && $uri
->getPath() === '' && $uri
->getQuery() === '';
}
/**
* 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
* removed.
*
* @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) {
$result = self::getFilteredQueryString($uri, [
$key,
]);
return $uri
->withQuery(implode('&', $result));
}
/**
* Creates a new URI with a specific query string value.
*
* Any existing query string values that exactly match the provided key are
* removed and replaced with the given key value pair.
*
* A value of null will set the query string key without a value, e.g. "key"
* instead of "key=value".
*
* @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) {
$result = self::getFilteredQueryString($uri, [
$key,
]);
$result[] = self::generateQueryString($key, $value);
return $uri
->withQuery(implode('&', $result));
}
/**
* Creates a new URI with multiple specific query string values.
*
* 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
*/
public static function withQueryValues(UriInterface $uri, array $keyValueArray) {
$result = self::getFilteredQueryString($uri, array_keys($keyValueArray));
foreach ($keyValueArray as $key => $value) {
$result[] = self::generateQueryString($key, $value);
}
return $uri
->withQuery(implode('&', $result));
}
/**
* 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.
*/
public static function fromParts(array $parts) {
$uri = new self();
$uri
->applyParts($parts);
$uri
->validateState();
return $uri;
}
public function getScheme() {
return $this->scheme;
}
public function getAuthority() {
$authority = $this->host;
if ($this->userInfo !== '') {
$authority = $this->userInfo . '@' . $authority;
}
if ($this->port !== null) {
$authority .= ':' . $this->port;
}
return $authority;
}
public function getUserInfo() {
return $this->userInfo;
}
public function getHost() {
return $this->host;
}
public function getPort() {
return $this->port;
}
public function getPath() {
return $this->path;
}
public function getQuery() {
return $this->query;
}
public function getFragment() {
return $this->fragment;
}
public function withScheme($scheme) {
$scheme = $this
->filterScheme($scheme);
if ($this->scheme === $scheme) {
return $this;
}
$new = clone $this;
$new->scheme = $scheme;
$new
->removeDefaultPort();
$new
->validateState();
return $new;
}
public function withUserInfo($user, $password = null) {
$info = $this
->filterUserInfoComponent($user);
if ($password !== null) {
$info .= ':' . $this
->filterUserInfoComponent($password);
}
if ($this->userInfo === $info) {
return $this;
}
$new = clone $this;
$new->userInfo = $info;
$new
->validateState();
return $new;
}
public function withHost($host) {
$host = $this
->filterHost($host);
if ($this->host === $host) {
return $this;
}
$new = clone $this;
$new->host = $host;
$new
->validateState();
return $new;
}
public function withPort($port) {
$port = $this
->filterPort($port);
if ($this->port === $port) {
return $this;
}
$new = clone $this;
$new->port = $port;
$new
->removeDefaultPort();
$new
->validateState();
return $new;
}
public function withPath($path) {
$path = $this
->filterPath($path);
if ($this->path === $path) {
return $this;
}
$new = clone $this;
$new->path = $path;
$new
->validateState();
return $new;
}
public function withQuery($query) {
$query = $this
->filterQueryAndFragment($query);
if ($this->query === $query) {
return $this;
}
$new = clone $this;
$new->query = $query;
return $new;
}
public function withFragment($fragment) {
$fragment = $this
->filterQueryAndFragment($fragment);
if ($this->fragment === $fragment) {
return $this;
}
$new = clone $this;
$new->fragment = $fragment;
return $new;
}
/**
* Apply parse_url parts to a URI.
*
* @param array $parts Array of parse_url parts to apply.
*/
private function applyParts(array $parts) {
$this->scheme = isset($parts['scheme']) ? $this
->filterScheme($parts['scheme']) : '';
$this->userInfo = isset($parts['user']) ? $this
->filterUserInfoComponent($parts['user']) : '';
$this->host = isset($parts['host']) ? $this
->filterHost($parts['host']) : '';
$this->port = isset($parts['port']) ? $this
->filterPort($parts['port']) : null;
$this->path = isset($parts['path']) ? $this
->filterPath($parts['path']) : '';
$this->query = isset($parts['query']) ? $this
->filterQueryAndFragment($parts['query']) : '';
$this->fragment = isset($parts['fragment']) ? $this
->filterQueryAndFragment($parts['fragment']) : '';
if (isset($parts['pass'])) {
$this->userInfo .= ':' . $this
->filterUserInfoComponent($parts['pass']);
}
$this
->removeDefaultPort();
}
/**
* @param string $scheme
*
* @return string
*
* @throws \InvalidArgumentException If the scheme is invalid.
*/
private function filterScheme($scheme) {
if (!is_string($scheme)) {
throw new \InvalidArgumentException('Scheme must be a string');
}
return strtolower($scheme);
}
/**
* @param string $component
*
* @return string
*
* @throws \InvalidArgumentException If the user info is invalid.
*/
private function filterUserInfoComponent($component) {
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}))/', [
$this,
'rawurlencodeMatchZero',
], $component);
}
/**
* @param string $host
*
* @return string
*
* @throws \InvalidArgumentException If the host is invalid.
*/
private function filterHost($host) {
if (!is_string($host)) {
throw new \InvalidArgumentException('Host must be a string');
}
return strtolower($host);
}
/**
* @param int|null $port
*
* @return int|null
*
* @throws \InvalidArgumentException If the port is invalid.
*/
private function filterPort($port) {
if ($port === null) {
return null;
}
$port = (int) $port;
if (0 > $port || 0xffff < $port) {
throw new \InvalidArgumentException(sprintf('Invalid port: %d. Must be between 0 and 65535', $port));
}
return $port;
}
/**
* @param UriInterface $uri
* @param array $keys
*
* @return array
*/
private static function getFilteredQueryString(UriInterface $uri, array $keys) {
$current = $uri
->getQuery();
if ($current === '') {
return [];
}
$decodedKeys = array_map('rawurldecode', $keys);
return array_filter(explode('&', $current), function ($part) use ($decodedKeys) {
return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);
});
}
/**
* @param string $key
* @param string|null $value
*
* @return string
*/
private static function generateQueryString($key, $value) {
// 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);
if ($value !== null) {
$queryString .= '=' . strtr($value, self::$replaceQuery);
}
return $queryString;
}
private function removeDefaultPort() {
if ($this->port !== null && self::isDefaultPort($this)) {
$this->port = null;
}
}
/**
* Filters the path of a URI
*
* @param string $path
*
* @return string
*
* @throws \InvalidArgumentException If the path is invalid.
*/
private function filterPath($path) {
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}))/', [
$this,
'rawurlencodeMatchZero',
], $path);
}
/**
* Filters the query string or fragment of a URI.
*
* @param string $str
*
* @return string
*
* @throws \InvalidArgumentException If the query or fragment is invalid.
*/
private function filterQueryAndFragment($str) {
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}))/', [
$this,
'rawurlencodeMatchZero',
], $str);
}
private function rawurlencodeMatchZero(array $match) {
return rawurlencode($match[0]);
}
private function validateState() {
if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
$this->host = self::HTTP_DEFAULT_HOST;
}
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 "//"');
}
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');
}
}
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');
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
Uri:: |
private static | property | ||
Uri:: |
private static | property | ||
Uri:: |
private static | property | ||
Uri:: |
private | property | @var string Uri fragment. | |
Uri:: |
private | property | @var string Uri host. | |
Uri:: |
private | property | @var string Uri path. | |
Uri:: |
private | property | @var int|null Uri port. | |
Uri:: |
private | property | @var string Uri query string. | |
Uri:: |
private static | property | ||
Uri:: |
private | property | @var string Uri scheme. | |
Uri:: |
private | property | @var string Uri user info. | |
Uri:: |
private | function | Apply parse_url parts to a URI. | |
Uri:: |
public static | function | Composes a URI reference string from its various components. | |
Uri:: |
private | function | ||
Uri:: |
private | function | Filters the path of a URI | |
Uri:: |
private | function | ||
Uri:: |
private | function | Filters the query string or fragment of a URI. | |
Uri:: |
private | function | ||
Uri:: |
private | function | ||
Uri:: |
public static | function | Creates a URI from a hash of `parse_url` components. | |
Uri:: |
private static | function | ||
Uri:: |
public | function |
Retrieve the authority component of the URI. Overrides UriInterface:: |
|
Uri:: |
private static | function | ||
Uri:: |
public | function |
Retrieve the fragment component of the URI. Overrides UriInterface:: |
|
Uri:: |
public | function |
Retrieve the host component of the URI. Overrides UriInterface:: |
|
Uri:: |
public | function |
Retrieve the path component of the URI. Overrides UriInterface:: |
|
Uri:: |
public | function |
Retrieve the port component of the URI. Overrides UriInterface:: |
|
Uri:: |
public | function |
Retrieve the query string of the URI. Overrides UriInterface:: |
|
Uri:: |
public | function |
Retrieve the scheme component of the URI. Overrides UriInterface:: |
|
Uri:: |
public | function |
Retrieve the user information component of the URI. Overrides UriInterface:: |
|
Uri:: |
constant | Absolute http and https URIs require a host per RFC 7230 Section 2.7 but in generic URIs the host can be empty. So for http(s) URIs we apply this default host when no host is given yet to form a valid URI. | ||
Uri:: |
public static | function | Whether the URI is absolute, i.e. it has a scheme. | |
Uri:: |
public static | function | Whether the URI is a absolute-path reference. | |
Uri:: |
public static | function | Whether the URI has the default port of the current scheme. | |
Uri:: |
public static | function | Whether the URI is a network-path reference. | |
Uri:: |
public static | function | Whether the URI is a relative-path reference. | |
Uri:: |
public static | function | Whether the URI is a same-document reference. | |
Uri:: |
private | function | ||
Uri:: |
private | function | ||
Uri:: |
public static | function | Removes dot segments from a path and returns the new path. | |
Uri:: |
public static | function | Converts the relative URI into a new URI that is resolved against the base URI. | |
Uri:: |
private | function | ||
Uri:: |
public | function |
Return an instance with the specified URI fragment. Overrides UriInterface:: |
|
Uri:: |
public | function |
Return an instance with the specified host. Overrides UriInterface:: |
|
Uri:: |
public static | function | Creates a new URI with a specific query string value removed. | |
Uri:: |
public | function |
Return an instance with the specified path. Overrides UriInterface:: |
|
Uri:: |
public | function |
Return an instance with the specified port. Overrides UriInterface:: |
|
Uri:: |
public | function |
Return an instance with the specified query string. Overrides UriInterface:: |
|
Uri:: |
public static | function | Creates a new URI with a specific query string value. | |
Uri:: |
public static | function | Creates a new URI with multiple specific query string values. | |
Uri:: |
public | function |
Return an instance with the specified scheme. Overrides UriInterface:: |
|
Uri:: |
public | function |
Return an instance with the specified user information. Overrides UriInterface:: |
|
Uri:: |
public | function | ||
Uri:: |
public | function |
Return the string representation as a URI reference. Overrides UriInterface:: |