Chris@0: # PSR-7 Message Implementation Chris@0: Chris@0: This repository contains a full [PSR-7](http://www.php-fig.org/psr/psr-7/) Chris@0: message implementation, several stream decorators, and some helpful Chris@0: functionality like query string parsing. Chris@0: Chris@0: Chris@0: [![Build Status](https://travis-ci.org/guzzle/psr7.svg?branch=master)](https://travis-ci.org/guzzle/psr7) Chris@0: Chris@0: Chris@0: # Stream implementation Chris@0: Chris@0: This package comes with a number of stream implementations and stream Chris@0: decorators. Chris@0: Chris@0: Chris@0: ## AppendStream Chris@0: Chris@0: `GuzzleHttp\Psr7\AppendStream` Chris@0: Chris@0: Reads from multiple streams, one after the other. Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: $a = Psr7\stream_for('abc, '); Chris@0: $b = Psr7\stream_for('123.'); Chris@0: $composed = new Psr7\AppendStream([$a, $b]); Chris@0: Chris@0: $composed->addStream(Psr7\stream_for(' Above all listen to me')); Chris@0: Chris@0: echo $composed; // abc, 123. Above all listen to me. Chris@0: ``` Chris@0: Chris@0: Chris@0: ## BufferStream Chris@0: Chris@0: `GuzzleHttp\Psr7\BufferStream` Chris@0: Chris@0: Provides a buffer stream that can be written to fill a buffer, and read Chris@0: from to remove bytes from the buffer. Chris@0: Chris@0: This stream returns a "hwm" metadata value that tells upstream consumers Chris@0: what the configured high water mark of the stream is, or the maximum Chris@0: preferred size of the buffer. Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: // When more than 1024 bytes are in the buffer, it will begin returning Chris@0: // false to writes. This is an indication that writers should slow down. Chris@0: $buffer = new Psr7\BufferStream(1024); Chris@0: ``` Chris@0: Chris@0: Chris@0: ## CachingStream Chris@0: Chris@0: The CachingStream is used to allow seeking over previously read bytes on Chris@0: non-seekable streams. This can be useful when transferring a non-seekable Chris@0: entity body fails due to needing to rewind the stream (for example, resulting Chris@0: from a redirect). Data that is read from the remote stream will be buffered in Chris@0: a PHP temp stream so that previously read bytes are cached first in memory, Chris@0: then on disk. Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: $original = Psr7\stream_for(fopen('http://www.google.com', 'r')); Chris@0: $stream = new Psr7\CachingStream($original); Chris@0: Chris@0: $stream->read(1024); Chris@0: echo $stream->tell(); Chris@0: // 1024 Chris@0: Chris@0: $stream->seek(0); Chris@0: echo $stream->tell(); Chris@0: // 0 Chris@0: ``` Chris@0: Chris@0: Chris@0: ## DroppingStream Chris@0: Chris@0: `GuzzleHttp\Psr7\DroppingStream` Chris@0: Chris@0: Stream decorator that begins dropping data once the size of the underlying Chris@0: stream becomes too full. Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: // Create an empty stream Chris@0: $stream = Psr7\stream_for(); Chris@0: Chris@0: // Start dropping data when the stream has more than 10 bytes Chris@0: $dropping = new Psr7\DroppingStream($stream, 10); Chris@0: Chris@0: $dropping->write('01234567890123456789'); Chris@0: echo $stream; // 0123456789 Chris@0: ``` Chris@0: Chris@0: Chris@0: ## FnStream Chris@0: Chris@0: `GuzzleHttp\Psr7\FnStream` Chris@0: Chris@0: Compose stream implementations based on a hash of functions. Chris@0: Chris@0: Allows for easy testing and extension of a provided stream without needing Chris@0: to create a concrete class for a simple extension point. Chris@0: Chris@0: ```php Chris@0: Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: $stream = Psr7\stream_for('hi'); Chris@0: $fnStream = Psr7\FnStream::decorate($stream, [ Chris@0: 'rewind' => function () use ($stream) { Chris@0: echo 'About to rewind - '; Chris@0: $stream->rewind(); Chris@0: echo 'rewound!'; Chris@0: } Chris@0: ]); Chris@0: Chris@0: $fnStream->rewind(); Chris@0: // Outputs: About to rewind - rewound! Chris@0: ``` Chris@0: Chris@0: Chris@0: ## InflateStream Chris@0: Chris@0: `GuzzleHttp\Psr7\InflateStream` Chris@0: Chris@0: Uses PHP's zlib.inflate filter to inflate deflate or gzipped content. Chris@0: Chris@0: This stream decorator skips the first 10 bytes of the given stream to remove Chris@0: the gzip header, converts the provided stream to a PHP stream resource, Chris@0: then appends the zlib.inflate filter. The stream is then converted back Chris@0: to a Guzzle stream resource to be used as a Guzzle stream. Chris@0: Chris@0: Chris@0: ## LazyOpenStream Chris@0: Chris@0: `GuzzleHttp\Psr7\LazyOpenStream` Chris@0: Chris@0: Lazily reads or writes to a file that is opened only after an IO operation Chris@0: take place on the stream. Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: $stream = new Psr7\LazyOpenStream('/path/to/file', 'r'); Chris@0: // The file has not yet been opened... Chris@0: Chris@0: echo $stream->read(10); Chris@0: // The file is opened and read from only when needed. Chris@0: ``` Chris@0: Chris@0: Chris@0: ## LimitStream Chris@0: Chris@0: `GuzzleHttp\Psr7\LimitStream` Chris@0: Chris@0: LimitStream can be used to read a subset or slice of an existing stream object. Chris@0: This can be useful for breaking a large file into smaller pieces to be sent in Chris@0: chunks (e.g. Amazon S3's multipart upload API). Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: $original = Psr7\stream_for(fopen('/tmp/test.txt', 'r+')); Chris@0: echo $original->getSize(); Chris@0: // >>> 1048576 Chris@0: Chris@0: // Limit the size of the body to 1024 bytes and start reading from byte 2048 Chris@0: $stream = new Psr7\LimitStream($original, 1024, 2048); Chris@0: echo $stream->getSize(); Chris@0: // >>> 1024 Chris@0: echo $stream->tell(); Chris@0: // >>> 0 Chris@0: ``` Chris@0: Chris@0: Chris@0: ## MultipartStream Chris@0: Chris@0: `GuzzleHttp\Psr7\MultipartStream` Chris@0: Chris@0: Stream that when read returns bytes for a streaming multipart or Chris@0: multipart/form-data stream. Chris@0: Chris@0: Chris@0: ## NoSeekStream Chris@0: Chris@0: `GuzzleHttp\Psr7\NoSeekStream` Chris@0: Chris@0: NoSeekStream wraps a stream and does not allow seeking. Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: $original = Psr7\stream_for('foo'); Chris@0: $noSeek = new Psr7\NoSeekStream($original); Chris@0: Chris@0: echo $noSeek->read(3); Chris@0: // foo Chris@0: var_export($noSeek->isSeekable()); Chris@0: // false Chris@0: $noSeek->seek(0); Chris@0: var_export($noSeek->read(3)); Chris@0: // NULL Chris@0: ``` Chris@0: Chris@0: Chris@0: ## PumpStream Chris@0: Chris@0: `GuzzleHttp\Psr7\PumpStream` Chris@0: Chris@0: Provides a read only stream that pumps data from a PHP callable. Chris@0: Chris@0: When invoking the provided callable, the PumpStream will pass the amount of Chris@0: data requested to read to the callable. The callable can choose to ignore Chris@0: this value and return fewer or more bytes than requested. Any extra data Chris@0: returned by the provided callable is buffered internally until drained using Chris@0: the read() function of the PumpStream. The provided callable MUST return Chris@0: false when there is no more data to read. Chris@0: Chris@0: Chris@0: ## Implementing stream decorators Chris@0: Chris@0: Creating a stream decorator is very easy thanks to the Chris@0: `GuzzleHttp\Psr7\StreamDecoratorTrait`. This trait provides methods that Chris@0: implement `Psr\Http\Message\StreamInterface` by proxying to an underlying Chris@0: stream. Just `use` the `StreamDecoratorTrait` and implement your custom Chris@0: methods. Chris@0: Chris@0: For example, let's say we wanted to call a specific function each time the last Chris@0: byte is read from a stream. This could be implemented by overriding the Chris@0: `read()` method. Chris@0: Chris@0: ```php Chris@0: use Psr\Http\Message\StreamInterface; Chris@0: use GuzzleHttp\Psr7\StreamDecoratorTrait; Chris@0: Chris@0: class EofCallbackStream implements StreamInterface Chris@0: { Chris@0: use StreamDecoratorTrait; Chris@0: Chris@0: private $callback; Chris@0: Chris@0: public function __construct(StreamInterface $stream, callable $cb) Chris@0: { Chris@0: $this->stream = $stream; Chris@0: $this->callback = $cb; Chris@0: } Chris@0: Chris@0: public function read($length) Chris@0: { Chris@0: $result = $this->stream->read($length); Chris@0: Chris@0: // Invoke the callback when EOF is hit. Chris@0: if ($this->eof()) { Chris@0: call_user_func($this->callback); Chris@0: } Chris@0: Chris@0: return $result; Chris@0: } Chris@0: } Chris@0: ``` Chris@0: Chris@0: This decorator could be added to any existing stream and used like so: Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7; Chris@0: Chris@0: $original = Psr7\stream_for('foo'); Chris@0: Chris@0: $eofStream = new EofCallbackStream($original, function () { Chris@0: echo 'EOF!'; Chris@0: }); Chris@0: Chris@0: $eofStream->read(2); Chris@0: $eofStream->read(1); Chris@0: // echoes "EOF!" Chris@0: $eofStream->seek(0); Chris@0: $eofStream->read(3); Chris@0: // echoes "EOF!" Chris@0: ``` Chris@0: Chris@0: Chris@0: ## PHP StreamWrapper Chris@0: Chris@0: You can use the `GuzzleHttp\Psr7\StreamWrapper` class if you need to use a Chris@0: PSR-7 stream as a PHP stream resource. Chris@0: Chris@0: Use the `GuzzleHttp\Psr7\StreamWrapper::getResource()` method to create a PHP Chris@0: stream from a PSR-7 stream. Chris@0: Chris@0: ```php Chris@0: use GuzzleHttp\Psr7\StreamWrapper; Chris@0: Chris@0: $stream = GuzzleHttp\Psr7\stream_for('hello!'); Chris@0: $resource = StreamWrapper::getResource($stream); Chris@0: echo fread($resource, 6); // outputs hello! Chris@0: ``` Chris@0: Chris@0: Chris@0: # Function API Chris@0: Chris@0: There are various functions available under the `GuzzleHttp\Psr7` namespace. Chris@0: Chris@0: Chris@0: ## `function str` Chris@0: Chris@0: `function str(MessageInterface $message)` Chris@0: Chris@0: Returns the string representation of an HTTP message. Chris@0: Chris@0: ```php Chris@0: $request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com'); Chris@0: echo GuzzleHttp\Psr7\str($request); Chris@0: ``` Chris@0: Chris@0: Chris@0: ## `function uri_for` Chris@0: Chris@0: `function uri_for($uri)` Chris@0: Chris@0: This function accepts a string or `Psr\Http\Message\UriInterface` and returns a Chris@0: UriInterface for the given value. If the value is already a `UriInterface`, it Chris@0: is returned as-is. Chris@0: Chris@0: ```php Chris@0: $uri = GuzzleHttp\Psr7\uri_for('http://example.com'); Chris@0: assert($uri === GuzzleHttp\Psr7\uri_for($uri)); Chris@0: ``` Chris@0: Chris@0: Chris@0: ## `function stream_for` Chris@0: Chris@0: `function stream_for($resource = '', array $options = [])` Chris@0: Chris@0: Create a new stream based on the input type. Chris@0: Chris@0: Options is an associative array that can contain the following keys: Chris@0: Chris@0: * - metadata: Array of custom metadata. Chris@0: * - size: Size of the stream. Chris@0: Chris@0: This method accepts the following `$resource` types: Chris@0: Chris@0: - `Psr\Http\Message\StreamInterface`: Returns the value as-is. Chris@0: - `string`: Creates a stream object that uses the given string as the contents. Chris@0: - `resource`: Creates a stream object that wraps the given PHP stream resource. Chris@0: - `Iterator`: If the provided value implements `Iterator`, then a read-only Chris@0: stream object will be created that wraps the given iterable. Each time the Chris@0: stream is read from, data from the iterator will fill a buffer and will be Chris@0: continuously called until the buffer is equal to the requested read size. Chris@0: Subsequent read calls will first read from the buffer and then call `next` Chris@0: on the underlying iterator until it is exhausted. Chris@0: - `object` with `__toString()`: If the object has the `__toString()` method, Chris@0: the object will be cast to a string and then a stream will be returned that Chris@0: uses the string value. Chris@0: - `NULL`: When `null` is passed, an empty stream object is returned. Chris@0: - `callable` When a callable is passed, a read-only stream object will be Chris@0: created that invokes the given callable. The callable is invoked with the Chris@0: number of suggested bytes to read. The callable can return any number of Chris@0: bytes, but MUST return `false` when there is no more data to return. The Chris@0: stream object that wraps the callable will invoke the callable until the Chris@0: number of requested bytes are available. Any additional bytes will be Chris@0: buffered and used in subsequent reads. Chris@0: Chris@0: ```php Chris@0: $stream = GuzzleHttp\Psr7\stream_for('foo'); Chris@0: $stream = GuzzleHttp\Psr7\stream_for(fopen('/path/to/file', 'r')); Chris@0: Chris@17: $generator = function ($bytes) { Chris@0: for ($i = 0; $i < $bytes; $i++) { Chris@0: yield ' '; Chris@0: } Chris@0: } Chris@0: Chris@0: $stream = GuzzleHttp\Psr7\stream_for($generator(100)); Chris@0: ``` Chris@0: Chris@0: Chris@0: ## `function parse_header` Chris@0: Chris@0: `function parse_header($header)` Chris@0: Chris@0: Parse an array of header values containing ";" separated data into an array of Chris@0: associative arrays representing the header key value pair data of the header. Chris@0: When a parameter does not contain a value, but just contains a key, this Chris@0: function will inject a key with a '' string value. Chris@0: Chris@0: Chris@0: ## `function normalize_header` Chris@0: Chris@0: `function normalize_header($header)` Chris@0: Chris@0: Converts an array of header values that may contain comma separated headers Chris@0: into an array of headers with no comma separated values. Chris@0: Chris@0: Chris@0: ## `function modify_request` Chris@0: Chris@0: `function modify_request(RequestInterface $request, array $changes)` Chris@0: Chris@0: Clone and modify a request with the given changes. This method is useful for Chris@0: reducing the number of clones needed to mutate a message. Chris@0: Chris@0: The changes can be one of: Chris@0: Chris@0: - method: (string) Changes the HTTP method. Chris@0: - set_headers: (array) Sets the given headers. Chris@0: - remove_headers: (array) Remove the given headers. Chris@0: - body: (mixed) Sets the given body. Chris@0: - uri: (UriInterface) Set the URI. Chris@0: - query: (string) Set the query string value of the URI. Chris@0: - version: (string) Set the protocol version. Chris@0: Chris@0: Chris@0: ## `function rewind_body` Chris@0: Chris@0: `function rewind_body(MessageInterface $message)` Chris@0: Chris@0: Attempts to rewind a message body and throws an exception on failure. The body Chris@0: of the message will only be rewound if a call to `tell()` returns a value other Chris@0: than `0`. Chris@0: Chris@0: Chris@0: ## `function try_fopen` Chris@0: Chris@0: `function try_fopen($filename, $mode)` Chris@0: Chris@0: Safely opens a PHP stream resource using a filename. Chris@0: Chris@0: When fopen fails, PHP normally raises a warning. This function adds an error Chris@0: handler that checks for errors and throws an exception instead. Chris@0: Chris@0: Chris@0: ## `function copy_to_string` Chris@0: Chris@0: `function copy_to_string(StreamInterface $stream, $maxLen = -1)` Chris@0: Chris@0: Copy the contents of a stream into a string until the given number of bytes Chris@0: have been read. Chris@0: Chris@0: Chris@0: ## `function copy_to_stream` Chris@0: Chris@0: `function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)` Chris@0: Chris@0: Copy the contents of a stream into another stream until the given number of Chris@0: bytes have been read. Chris@0: Chris@0: Chris@0: ## `function hash` Chris@0: Chris@0: `function hash(StreamInterface $stream, $algo, $rawOutput = false)` Chris@0: Chris@0: Calculate a hash of a Stream. This method reads the entire stream to calculate Chris@0: a rolling hash (based on PHP's hash_init functions). Chris@0: Chris@0: Chris@0: ## `function readline` Chris@0: Chris@0: `function readline(StreamInterface $stream, $maxLength = null)` Chris@0: Chris@0: Read a line from the stream up to the maximum allowed buffer length. Chris@0: Chris@0: Chris@0: ## `function parse_request` Chris@0: Chris@0: `function parse_request($message)` Chris@0: Chris@0: Parses a request message string into a request object. Chris@0: Chris@0: Chris@0: ## `function parse_response` Chris@0: Chris@0: `function parse_response($message)` Chris@0: Chris@0: Parses a response message string into a response object. Chris@0: Chris@0: Chris@0: ## `function parse_query` Chris@0: Chris@0: `function parse_query($str, $urlEncoding = true)` Chris@0: Chris@0: Parse a query string into an associative array. Chris@0: Chris@0: If multiple values are found for the same key, the value of that key value pair Chris@0: will become an array. This function does not parse nested PHP style arrays into Chris@0: an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed into Chris@0: `['foo[a]' => '1', 'foo[b]' => '2']`). Chris@0: Chris@0: Chris@0: ## `function build_query` Chris@0: Chris@0: `function build_query(array $params, $encoding = PHP_QUERY_RFC3986)` Chris@0: Chris@0: Build a query string from an array of key value pairs. Chris@0: Chris@0: This function can use the return value of parse_query() to build a query string. Chris@0: This function does not modify the provided keys when an array is encountered Chris@0: (like http_build_query would). Chris@0: Chris@0: Chris@0: ## `function mimetype_from_filename` Chris@0: Chris@0: `function mimetype_from_filename($filename)` Chris@0: Chris@0: Determines the mimetype of a file by looking at its extension. Chris@0: Chris@0: Chris@0: ## `function mimetype_from_extension` Chris@0: Chris@0: `function mimetype_from_extension($extension)` Chris@0: Chris@0: Maps a file extensions to a mimetype. Chris@0: Chris@0: Chris@0: # Additional URI Methods Chris@0: Chris@0: Aside from the standard `Psr\Http\Message\UriInterface` implementation in form of the `GuzzleHttp\Psr7\Uri` class, Chris@0: this library also provides additional functionality when working with URIs as static methods. Chris@0: Chris@0: ## URI Types Chris@0: Chris@0: An instance of `Psr\Http\Message\UriInterface` can either be an absolute URI or a relative reference. Chris@0: An absolute URI has a scheme. A relative reference is used to express a URI relative to another URI, Chris@0: the base URI. Relative references can be divided into several forms according to Chris@0: [RFC 3986 Section 4.2](https://tools.ietf.org/html/rfc3986#section-4.2): Chris@0: Chris@0: - network-path references, e.g. `//example.com/path` Chris@0: - absolute-path references, e.g. `/path` Chris@0: - relative-path references, e.g. `subpath` Chris@0: Chris@0: The following methods can be used to identify the type of the URI. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::isAbsolute` Chris@0: Chris@0: `public static function isAbsolute(UriInterface $uri): bool` Chris@0: Chris@0: Whether the URI is absolute, i.e. it has a scheme. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::isNetworkPathReference` Chris@0: Chris@0: `public static function isNetworkPathReference(UriInterface $uri): bool` Chris@0: Chris@0: Whether the URI is a network-path reference. A relative reference that begins with two slash characters is Chris@0: termed an network-path reference. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::isAbsolutePathReference` Chris@0: Chris@0: `public static function isAbsolutePathReference(UriInterface $uri): bool` Chris@0: Chris@0: Whether the URI is a absolute-path reference. A relative reference that begins with a single slash character is Chris@0: termed an absolute-path reference. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::isRelativePathReference` Chris@0: Chris@0: `public static function isRelativePathReference(UriInterface $uri): bool` Chris@0: Chris@0: Whether the URI is a relative-path reference. A relative reference that does not begin with a slash character is Chris@0: termed a relative-path reference. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::isSameDocumentReference` Chris@0: Chris@0: `public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool` Chris@0: Chris@0: Whether the URI is a same-document reference. A same-document reference refers to a URI that is, aside from its Chris@0: fragment component, identical to the base URI. When no base URI is given, only an empty URI reference Chris@0: (apart from its fragment) is considered a same-document reference. Chris@0: Chris@0: ## URI Components Chris@0: Chris@0: Additional methods to work with URI components. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::isDefaultPort` Chris@0: Chris@0: `public static function isDefaultPort(UriInterface $uri): bool` Chris@0: Chris@0: Whether the URI has the default port of the current scheme. `Psr\Http\Message\UriInterface::getPort` may return null Chris@0: or the standard port. This method can be used independently of the implementation. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::composeComponents` Chris@0: Chris@0: `public static function composeComponents($scheme, $authority, $path, $query, $fragment): string` Chris@0: Chris@0: Composes a URI reference string from its various components according to Chris@0: [RFC 3986 Section 5.3](https://tools.ietf.org/html/rfc3986#section-5.3). Usually this method does not need to be called Chris@0: manually but instead is used indirectly via `Psr\Http\Message\UriInterface::__toString`. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::fromParts` Chris@0: Chris@0: `public static function fromParts(array $parts): UriInterface` Chris@0: Chris@0: Creates a URI from a hash of [`parse_url`](http://php.net/manual/en/function.parse-url.php) components. Chris@0: Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::withQueryValue` Chris@0: Chris@0: `public static function withQueryValue(UriInterface $uri, $key, $value): UriInterface` Chris@0: Chris@0: Creates a new URI with a specific query string value. Any existing query string values that exactly match the Chris@0: provided key are removed and replaced with the given key value pair. A value of null will set the query string Chris@0: key without a value, e.g. "key" instead of "key=value". Chris@0: Chris@17: ### `GuzzleHttp\Psr7\Uri::withQueryValues` Chris@17: Chris@17: `public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface` Chris@17: Chris@17: Creates a new URI with multiple query string values. It has the same behavior as `withQueryValue()` but for an Chris@17: associative array of key => value. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\Uri::withoutQueryValue` Chris@0: Chris@0: `public static function withoutQueryValue(UriInterface $uri, $key): UriInterface` Chris@0: Chris@0: Creates a new URI with a specific query string value removed. Any existing query string values that exactly match the Chris@0: provided key are removed. Chris@0: Chris@0: ## Reference Resolution Chris@0: Chris@0: `GuzzleHttp\Psr7\UriResolver` provides methods to resolve a URI reference in the context of a base URI according Chris@0: to [RFC 3986 Section 5](https://tools.ietf.org/html/rfc3986#section-5). This is for example also what web browsers Chris@0: do when resolving a link in a website based on the current request URI. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\UriResolver::resolve` Chris@0: Chris@0: `public static function resolve(UriInterface $base, UriInterface $rel): UriInterface` Chris@0: Chris@0: Converts the relative URI into a new URI that is resolved against the base URI. Chris@0: Chris@0: ### `GuzzleHttp\Psr7\UriResolver::removeDotSegments` Chris@0: Chris@0: `public static function removeDotSegments(string $path): string` Chris@0: Chris@0: Removes dot segments from a path and returns the new path according to Chris@0: [RFC 3986 Section 5.2.4](https://tools.ietf.org/html/rfc3986#section-5.2.4). Chris@0: Chris@0: ### `GuzzleHttp\Psr7\UriResolver::relativize` Chris@0: Chris@0: `public static function relativize(UriInterface $base, UriInterface $target): UriInterface` Chris@0: Chris@0: Returns the target URI as a relative reference from the base URI. This method is the counterpart to resolve(): Chris@0: Chris@0: ```php Chris@0: (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target)) Chris@0: ``` Chris@0: Chris@0: One use-case is to use the current request URI as base URI and then generate relative links in your documents Chris@0: to reduce the document size or offer self-contained downloadable document archives. Chris@0: Chris@0: ```php Chris@0: $base = new Uri('http://example.com/a/b/'); Chris@0: echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'. Chris@0: echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'. Chris@0: echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'. Chris@0: echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'. Chris@0: ``` Chris@0: Chris@0: ## Normalization and Comparison Chris@0: Chris@0: `GuzzleHttp\Psr7\UriNormalizer` provides methods to normalize and compare URIs according to Chris@0: [RFC 3986 Section 6](https://tools.ietf.org/html/rfc3986#section-6). Chris@0: Chris@0: ### `GuzzleHttp\Psr7\UriNormalizer::normalize` Chris@0: Chris@0: `public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS): UriInterface` Chris@0: Chris@0: Returns a normalized URI. The scheme and host component are already normalized to lowercase per PSR-7 UriInterface. Chris@0: This methods adds additional normalizations that can be configured with the `$flags` parameter which is a bitmask Chris@0: of normalizations to apply. The following normalizations are available: Chris@0: Chris@0: - `UriNormalizer::PRESERVING_NORMALIZATIONS` Chris@0: Chris@0: Default normalizations which only include the ones that preserve semantics. Chris@0: Chris@0: - `UriNormalizer::CAPITALIZE_PERCENT_ENCODING` Chris@0: Chris@0: All letters within a percent-encoding triplet (e.g., "%3A") are case-insensitive, and should be capitalized. Chris@0: Chris@0: Example: `http://example.org/a%c2%b1b` → `http://example.org/a%C2%B1b` Chris@0: Chris@0: - `UriNormalizer::DECODE_UNRESERVED_CHARACTERS` Chris@0: Chris@0: Decodes percent-encoded octets of unreserved characters. For consistency, percent-encoded octets in the ranges of Chris@0: ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should Chris@0: not be created by URI producers and, when found in a URI, should be decoded to their corresponding unreserved Chris@0: characters by URI normalizers. Chris@0: Chris@0: Example: `http://example.org/%7Eusern%61me/` → `http://example.org/~username/` Chris@0: Chris@0: - `UriNormalizer::CONVERT_EMPTY_PATH` Chris@0: Chris@0: Converts the empty path to "/" for http and https URIs. Chris@0: Chris@0: Example: `http://example.org` → `http://example.org/` Chris@0: Chris@0: - `UriNormalizer::REMOVE_DEFAULT_HOST` Chris@0: Chris@0: Removes the default host of the given URI scheme from the URI. Only the "file" scheme defines the default host Chris@0: "localhost". All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile` are equivalent according to Chris@0: RFC 3986. Chris@0: Chris@0: Example: `file://localhost/myfile` → `file:///myfile` Chris@0: Chris@0: - `UriNormalizer::REMOVE_DEFAULT_PORT` Chris@0: Chris@0: Removes the default port of the given URI scheme from the URI. Chris@0: Chris@0: Example: `http://example.org:80/` → `http://example.org/` Chris@0: Chris@0: - `UriNormalizer::REMOVE_DOT_SEGMENTS` Chris@0: Chris@0: Removes unnecessary dot-segments. Dot-segments in relative-path references are not removed as it would Chris@0: change the semantics of the URI reference. Chris@0: Chris@0: Example: `http://example.org/../a/b/../c/./d.html` → `http://example.org/a/c/d.html` Chris@0: Chris@0: - `UriNormalizer::REMOVE_DUPLICATE_SLASHES` Chris@0: Chris@0: Paths which include two or more adjacent slashes are converted to one. Webservers usually ignore duplicate slashes Chris@0: and treat those URIs equivalent. But in theory those URIs do not need to be equivalent. So this normalization Chris@0: may change the semantics. Encoded slashes (%2F) are not removed. Chris@0: Chris@0: Example: `http://example.org//foo///bar.html` → `http://example.org/foo/bar.html` Chris@0: Chris@0: - `UriNormalizer::SORT_QUERY_PARAMETERS` Chris@0: Chris@0: Sort query parameters with their values in alphabetical order. However, the order of parameters in a URI may be Chris@0: significant (this is not defined by the standard). So this normalization is not safe and may change the semantics Chris@0: of the URI. Chris@0: Chris@0: Example: `?lang=en&article=fred` → `?article=fred&lang=en` Chris@0: Chris@0: ### `GuzzleHttp\Psr7\UriNormalizer::isEquivalent` Chris@0: Chris@0: `public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS): bool` Chris@0: Chris@0: Whether two URIs can be considered equivalent. Both URIs are normalized automatically before comparison with the given Chris@0: `$normalizations` bitmask. The method also accepts relative URI references and returns true when they are equivalent. Chris@0: This of course assumes they will be resolved against the same base URI. If this is not the case, determination of Chris@0: equivalence or difference of relative references does not mean anything.