composer update

This commit is contained in:
Oliver Davies 2019-01-24 08:00:03 +00:00
parent f6abc3dce2
commit 71dfaca858
1753 changed files with 45274 additions and 14619 deletions

9
vendor/guzzlehttp/psr7/.editorconfig vendored Normal file
View file

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

View file

@ -1,32 +1,82 @@
# CHANGELOG
# Change Log
## 1.4.2 - 2017-03-20
* Reverted BC break to `Uri::resolve` and `Uri::removeDotSegments` by removing
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.5.2] - 2018-12-04
### Fixed
- Check body size when getting the message summary
## [1.5.1] - 2018-12-04
### Fixed
- Get the summary of a body only if it is readable
## [1.5.0] - 2018-12-03
### Added
- Response first-line to response string exception (fixes #145)
- A test for #129 behavior
- `get_message_body_summary` function in order to get the message summary
- `3gp` and `mkv` mime types
### Changed
- Clarify exception message when stream is detached
### Deprecated
- Deprecated parsing folded header lines as per RFC 7230
### Fixed
- Fix `AppendStream::detach` to not close streams
- `InflateStream` preserves `isSeekable` attribute of the underlying stream
- `ServerRequest::getUriFromGlobals` to support URLs in query parameters
Several other fixes and improvements.
## [1.4.2] - 2017-03-20
### Fixed
- Reverted BC break to `Uri::resolve` and `Uri::removeDotSegments` by removing
calls to `trigger_error` when deprecated methods are invoked.
## 1.4.1 - 2017-02-27
* Reverted BC break by reintroducing behavior to automagically fix a URI with a
## [1.4.1] - 2017-02-27
### Added
- Rriggering of silenced deprecation warnings.
### Fixed
- Reverted BC break by reintroducing behavior to automagically fix a URI with a
relative path and an authority by adding a leading slash to the path. It's only
deprecated now.
* Added triggering of silenced deprecation warnings.
## 1.4.0 - 2017-02-21
* Fix `Stream::read` when length parameter <= 0.
* `copy_to_stream` reads bytes in chunks instead of `maxLen` into memory.
* Fix `ServerRequest::getUriFromGlobals` when `Host` header contains port.
* Ensure `ServerRequest::getUriFromGlobals` returns a URI in absolute form.
* Allow `parse_response` to parse a response without delimiting space and reason.
* Ensure each URI modification results in a valid URI according to PSR-7 discussions.
Invalid modifications will throw an exception instead of returning a wrong URI or
doing some magic.
- `(new Uri)->withPath('foo')->withHost('example.com')` will throw an exception
because the path of a URI with an authority must start with a slash "/" or be empty
- `(new Uri())->withScheme('http')` will return `'http://localhost'`
* Fix compatibility of URIs with `file` scheme and empty host.
* Added common URI utility methods based on RFC 3986 (see documentation in the readme):
## [1.4.0] - 2017-02-21
### Added
- Added common URI utility methods based on RFC 3986 (see documentation in the readme):
- `Uri::isDefaultPort`
- `Uri::isAbsolute`
- `Uri::isNetworkPathReference`
@ -37,69 +87,117 @@
- `UriNormalizer::normalize`
- `UriNormalizer::isEquivalent`
- `UriResolver::relativize`
* Deprecated `Uri::resolve` in favor of `UriResolver::resolve`
* Deprecated `Uri::removeDotSegments` in favor of `UriResolver::removeDotSegments`
## 1.3.1 - 2016-06-25
### Changed
* Fix `Uri::__toString` for network path references, e.g. `//example.org`.
* Fix missing lowercase normalization for host.
* Fix handling of URI components in case they are `'0'` in a lot of places,
- Ensure `ServerRequest::getUriFromGlobals` returns a URI in absolute form.
- Allow `parse_response` to parse a response without delimiting space and reason.
- Ensure each URI modification results in a valid URI according to PSR-7 discussions.
Invalid modifications will throw an exception instead of returning a wrong URI or
doing some magic.
- `(new Uri)->withPath('foo')->withHost('example.com')` will throw an exception
because the path of a URI with an authority must start with a slash "/" or be empty
- `(new Uri())->withScheme('http')` will return `'http://localhost'`
### Deprecated
- `Uri::resolve` in favor of `UriResolver::resolve`
- `Uri::removeDotSegments` in favor of `UriResolver::removeDotSegments`
### Fixed
- `Stream::read` when length parameter <= 0.
- `copy_to_stream` reads bytes in chunks instead of `maxLen` into memory.
- `ServerRequest::getUriFromGlobals` when `Host` header contains port.
- Compatibility of URIs with `file` scheme and empty host.
## [1.3.1] - 2016-06-25
### Fixed
- `Uri::__toString` for network path references, e.g. `//example.org`.
- Missing lowercase normalization for host.
- Handling of URI components in case they are `'0'` in a lot of places,
e.g. as a user info password.
* Fix `Uri::withAddedHeader` to correctly merge headers with different case.
* Fix trimming of header values in `Uri::withAddedHeader`. Header values may
- `Uri::withAddedHeader` to correctly merge headers with different case.
- Trimming of header values in `Uri::withAddedHeader`. Header values may
be surrounded by whitespace which should be ignored according to RFC 7230
Section 3.2.4. This does not apply to header names.
* Fix `Uri::withAddedHeader` with an array of header values.
* Fix `Uri::resolve` when base path has no slash and handling of fragment.
* Fix handling of encoding in `Uri::with(out)QueryValue` so one can pass the
- `Uri::withAddedHeader` with an array of header values.
- `Uri::resolve` when base path has no slash and handling of fragment.
- Handling of encoding in `Uri::with(out)QueryValue` so one can pass the
key/value both in encoded as well as decoded form to those methods. This is
consistent with withPath, withQuery etc.
* Fix `ServerRequest::withoutAttribute` when attribute value is null.
- `ServerRequest::withoutAttribute` when attribute value is null.
## 1.3.0 - 2016-04-13
* Added remaining interfaces needed for full PSR7 compatibility
## [1.3.0] - 2016-04-13
### Added
- Remaining interfaces needed for full PSR7 compatibility
(ServerRequestInterface, UploadedFileInterface, etc.).
* Added support for stream_for from scalars.
* Can now extend Uri.
* Fixed a bug in validating request methods by making it more permissive.
- Support for stream_for from scalars.
## 1.2.3 - 2016-02-18
### Changed
* Fixed support in `GuzzleHttp\Psr7\CachingStream` for seeking forward on remote
- Can now extend Uri.
### Fixed
- A bug in validating request methods by making it more permissive.
## [1.2.3] - 2016-02-18
### Fixed
- Support in `GuzzleHttp\Psr7\CachingStream` for seeking forward on remote
streams, which can sometimes return fewer bytes than requested with `fread`.
* Fixed handling of gzipped responses with FNAME headers.
- Handling of gzipped responses with FNAME headers.
## 1.2.2 - 2016-01-22
* Added support for URIs without any authority.
* Added support for HTTP 451 'Unavailable For Legal Reasons.'
* Added support for using '0' as a filename.
* Added support for including non-standard ports in Host headers.
## [1.2.2] - 2016-01-22
## 1.2.1 - 2015-11-02
### Added
* Now supporting negative offsets when seeking to SEEK_END.
- Support for URIs without any authority.
- Support for HTTP 451 'Unavailable For Legal Reasons.'
- Support for using '0' as a filename.
- Support for including non-standard ports in Host headers.
## 1.2.0 - 2015-08-15
* Body as `"0"` is now properly added to a response.
* Now allowing forward seeking in CachingStream.
* Now properly parsing HTTP requests that contain proxy targets in
## [1.2.1] - 2015-11-02
### Changes
- Now supporting negative offsets when seeking to SEEK_END.
## [1.2.0] - 2015-08-15
### Changed
- Body as `"0"` is now properly added to a response.
- Now allowing forward seeking in CachingStream.
- Now properly parsing HTTP requests that contain proxy targets in
`parse_request`.
* functions.php is now conditionally required.
* user-info is no longer dropped when resolving URIs.
- functions.php is now conditionally required.
- user-info is no longer dropped when resolving URIs.
## 1.1.0 - 2015-06-24
* URIs can now be relative.
* `multipart/form-data` headers are now overridden case-insensitively.
* URI paths no longer encode the following characters because they are allowed
## [1.1.0] - 2015-06-24
### Changed
- URIs can now be relative.
- `multipart/form-data` headers are now overridden case-insensitively.
- URI paths no longer encode the following characters because they are allowed
in URIs: "(", ")", "*", "!", "'"
* A port is no longer added to a URI when the scheme is missing and no port is
- A port is no longer added to a URI when the scheme is missing and no port is
present.
## 1.0.0 - 2015-05-19
Initial release.
@ -108,3 +206,20 @@ Currently unsupported:
- `Psr\Http\Message\ServerRequestInterface`
- `Psr\Http\Message\UploadedFileInterface`
[Unreleased]: https://github.com/guzzle/psr7/compare/1.5.2...HEAD
[1.5.2]: https://github.com/guzzle/psr7/compare/1.5.1...1.5.2
[1.5.1]: https://github.com/guzzle/psr7/compare/1.5.0...1.5.1
[1.5.0]: https://github.com/guzzle/psr7/compare/1.4.2...1.5.0
[1.4.2]: https://github.com/guzzle/psr7/compare/1.4.1...1.4.2
[1.4.1]: https://github.com/guzzle/psr7/compare/1.4.0...1.4.1
[1.4.0]: https://github.com/guzzle/psr7/compare/1.3.1...1.4.0
[1.3.1]: https://github.com/guzzle/psr7/compare/1.3.0...1.3.1
[1.3.0]: https://github.com/guzzle/psr7/compare/1.2.3...1.3.0
[1.2.3]: https://github.com/guzzle/psr7/compare/1.2.2...1.2.3
[1.2.2]: https://github.com/guzzle/psr7/compare/1.2.1...1.2.2
[1.2.1]: https://github.com/guzzle/psr7/compare/1.2.0...1.2.1
[1.2.0]: https://github.com/guzzle/psr7/compare/1.1.0...1.2.0
[1.1.0]: https://github.com/guzzle/psr7/compare/1.0.0...1.1.0

View file

@ -372,7 +372,7 @@ This method accepts the following `$resource` types:
$stream = GuzzleHttp\Psr7\stream_for('foo');
$stream = GuzzleHttp\Psr7\stream_for(fopen('/path/to/file', 'r'));
$generator function ($bytes) {
$generator = function ($bytes) {
for ($i = 0; $i < $bytes; $i++) {
yield ' ';
}
@ -606,6 +606,12 @@ Creates a new URI with a specific query string value. Any existing query string
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".
### `GuzzleHttp\Psr7\Uri::withQueryValues`
`public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface`
Creates a new URI with multiple query string values. It has the same behavior as `withQueryValue()` but for an
associative array of key => value.
### `GuzzleHttp\Psr7\Uri::withoutQueryValue`

View file

@ -2,7 +2,7 @@
"name": "guzzlehttp/psr7",
"type": "library",
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": ["request", "response", "message", "stream", "http", "uri", "url"],
"keywords": ["request", "response", "message", "stream", "http", "uri", "url", "psr-7"],
"license": "MIT",
"authors": [
{
@ -17,10 +17,11 @@
],
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
"psr/http-message": "~1.0",
"ralouphie/getallheaders": "^2.0.5"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
},
"provide": {
"psr/http-message-implementation": "1.0"
@ -31,9 +32,14 @@
},
"files": ["src/functions_include.php"]
},
"autoload-dev": {
"psr-4": {
"GuzzleHttp\\Tests\\Psr7\\": "tests/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
"dev-master": "1.5-dev"
}
}
}

View file

@ -16,7 +16,6 @@ class AppendStream implements StreamInterface
private $seekable = true;
private $current = 0;
private $pos = 0;
private $detached = false;
/**
* @param StreamInterface[] $streams Streams to decorate. Each stream must
@ -73,6 +72,7 @@ class AppendStream implements StreamInterface
public function close()
{
$this->pos = $this->current = 0;
$this->seekable = true;
foreach ($this->streams as $stream) {
$stream->close();
@ -82,14 +82,22 @@ class AppendStream implements StreamInterface
}
/**
* Detaches each attached stream
* Detaches each attached stream.
*
* Returns null as it's not clear which underlying stream resource to return.
*
* {@inheritdoc}
*/
public function detach()
{
$this->close();
$this->detached = true;
$this->pos = $this->current = 0;
$this->seekable = true;
foreach ($this->streams as $stream) {
$stream->detach();
}
$this->streams = [];
}
public function tell()

View file

@ -52,6 +52,15 @@ class FnStream implements StreamInterface
}
}
/**
* An unserialize would allow the __destruct to run when the unserialized value goes out of scope.
* @throws \LogicException
*/
public function __wakeup()
{
throw new \LogicException('FnStream should never be unserialized');
}
/**
* Adds custom functionality to an underlying stream by intercepting
* specific method calls.

View file

@ -27,7 +27,7 @@ class InflateStream implements StreamInterface
$stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength);
$resource = StreamWrapper::getResource($stream);
stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
$this->stream = new Stream($resource);
$this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));
}
/**

View file

@ -45,7 +45,7 @@ class Request implements RequestInterface
$this->setHeaders($headers);
$this->protocol = $version;
if (!$this->hasHeader('Host')) {
if (!isset($this->headerNames['host'])) {
$this->updateHostFromUri();
}
@ -110,7 +110,7 @@ class Request implements RequestInterface
$new = clone $this;
$new->uri = $uri;
if (!$preserveHost) {
if (!$preserveHost || !isset($this->headerNames['host'])) {
$new->updateHostFromUri();
}

View file

@ -93,6 +93,10 @@ class Response implements ResponseInterface
$version = '1.1',
$reason = null
) {
if (filter_var($status, FILTER_VALIDATE_INT) === false) {
throw new \InvalidArgumentException('Status code must be an integer value.');
}
$this->statusCode = (int) $status;
if ($body !== '' && $body !== null) {

18
vendor/guzzlehttp/psr7/src/Rfc7230.php vendored Normal file
View file

@ -0,0 +1,18 @@
<?php
namespace GuzzleHttp\Psr7;
final class Rfc7230
{
/**
* Header related regular expressions (copied from amphp/http package)
* (Note: once we require PHP 7.x we could just depend on the upstream package)
*
* Note: header delimiter (\r\n) is modified to \r?\n to accept line feed only delimiters for BC reasons.
*
* @link https://github.com/amphp/http/blob/v1.0.1/src/Rfc7230.php#L12-L15
* @license https://github.com/amphp/http/blob/v1.0.1/LICENSE
*/
const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m";
const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
}

View file

@ -166,7 +166,7 @@ class ServerRequest extends Request implements ServerRequestInterface
public static function fromGlobals()
{
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
$headers = function_exists('getallheaders') ? getallheaders() : [];
$headers = getallheaders();
$uri = self::getUriFromGlobals();
$body = new LazyOpenStream('php://input', 'r+');
$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
@ -180,23 +180,41 @@ class ServerRequest extends Request implements ServerRequestInterface
->withUploadedFiles(self::normalizeFiles($_FILES));
}
private static function extractHostAndPortFromAuthority($authority)
{
$uri = 'http://'.$authority;
$parts = parse_url($uri);
if (false === $parts) {
return [null, null];
}
$host = isset($parts['host']) ? $parts['host'] : null;
$port = isset($parts['port']) ? $parts['port'] : null;
return [$host, $port];
}
/**
* Get a Uri populated with values from $_SERVER.
*
* @return UriInterface
*/
public static function getUriFromGlobals() {
public static function getUriFromGlobals()
{
$uri = new Uri('');
$uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
$hasPort = false;
if (isset($_SERVER['HTTP_HOST'])) {
$hostHeaderParts = explode(':', $_SERVER['HTTP_HOST']);
$uri = $uri->withHost($hostHeaderParts[0]);
if (isset($hostHeaderParts[1])) {
list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
if ($host !== null) {
$uri = $uri->withHost($host);
}
if ($port !== null) {
$hasPort = true;
$uri = $uri->withPort($hostHeaderParts[1]);
$uri = $uri->withPort($port);
}
} elseif (isset($_SERVER['SERVER_NAME'])) {
$uri = $uri->withHost($_SERVER['SERVER_NAME']);
@ -210,7 +228,7 @@ class ServerRequest extends Request implements ServerRequestInterface
$hasQuery = false;
if (isset($_SERVER['REQUEST_URI'])) {
$requestUriParts = explode('?', $_SERVER['REQUEST_URI']);
$requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
$uri = $uri->withPath($requestUriParts[0]);
if (isset($requestUriParts[1])) {
$hasQuery = true;

View file

@ -24,11 +24,11 @@ class Stream implements StreamInterface
'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
'x+t' => true, 'c+t' => true, 'a+' => true
'x+t' => true, 'c+t' => true, 'a+' => true, 'rb+' => true,
],
'write' => [
'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true, 'rb+' => true,
'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
]
@ -70,15 +70,6 @@ class Stream implements StreamInterface
$this->uri = $this->getMetadata('uri');
}
public function __get($name)
{
if ($name == 'stream') {
throw new \RuntimeException('The stream is detached');
}
throw new \BadMethodCallException('No value for ' . $name);
}
/**
* Closes the stream when the destructed
*/
@ -99,6 +90,10 @@ class Stream implements StreamInterface
public function getContents()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
$contents = stream_get_contents($this->stream);
if ($contents === false) {
@ -173,11 +168,19 @@ class Stream implements StreamInterface
public function eof()
{
return !$this->stream || feof($this->stream);
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
return feof($this->stream);
}
public function tell()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
$result = ftell($this->stream);
if ($result === false) {
@ -194,9 +197,13 @@ class Stream implements StreamInterface
public function seek($offset, $whence = SEEK_SET)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->seekable) {
throw new \RuntimeException('Stream is not seekable');
} elseif (fseek($this->stream, $offset, $whence) === -1) {
}
if (fseek($this->stream, $offset, $whence) === -1) {
throw new \RuntimeException('Unable to seek to stream position '
. $offset . ' with whence ' . var_export($whence, true));
}
@ -204,6 +211,9 @@ class Stream implements StreamInterface
public function read($length)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->readable) {
throw new \RuntimeException('Cannot read from non-readable stream');
}
@ -225,6 +235,9 @@ class Stream implements StreamInterface
public function write($string)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->writable) {
throw new \RuntimeException('Cannot write to a non-writable stream');
}

View file

@ -38,9 +38,21 @@ class StreamWrapper
. 'writable, or both.');
}
return fopen('guzzle://stream', $mode, null, stream_context_create([
return fopen('guzzle://stream', $mode, null, self::createStreamContext($stream));
}
/**
* Creates a stream context that can be used to open a stream as a php stream resource.
*
* @param StreamInterface $stream
*
* @return resource
*/
public static function createStreamContext(StreamInterface $stream)
{
return stream_context_create([
'guzzle' => ['stream' => $stream]
]));
]);
}
/**
@ -94,12 +106,21 @@ class StreamWrapper
return true;
}
public function stream_cast($cast_as)
{
$stream = clone($this->stream);
return $stream->detach();
}
public function stream_stat()
{
static $modeMap = [
'r' => 33060,
'rb' => 33060,
'r+' => 33206,
'w' => 33188
'w' => 33188,
'wb' => 33188
];
return [
@ -118,4 +139,23 @@ class StreamWrapper
'blocks' => 0
];
}
public function url_stat($path, $flags)
{
return [
'dev' => 0,
'ino' => 0,
'mode' => 0,
'nlink' => 0,
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => 0,
'atime' => 0,
'mtime' => 0,
'ctime' => 0,
'blksize' => 0,
'blocks' => 0
];
}
}

View file

@ -301,15 +301,7 @@ class Uri implements UriInterface
*/
public static function withoutQueryValue(UriInterface $uri, $key)
{
$current = $uri->getQuery();
if ($current === '') {
return $uri;
}
$decodedKey = rawurldecode($key);
$result = array_filter(explode('&', $current), function ($part) use ($decodedKey) {
return rawurldecode(explode('=', $part)[0]) !== $decodedKey;
});
$result = self::getFilteredQueryString($uri, [$key]);
return $uri->withQuery(implode('&', $result));
}
@ -331,26 +323,29 @@ class Uri implements UriInterface
*/
public static function withQueryValue(UriInterface $uri, $key, $value)
{
$current = $uri->getQuery();
$result = self::getFilteredQueryString($uri, [$key]);
if ($current === '') {
$result = [];
} else {
$decodedKey = rawurldecode($key);
$result = array_filter(explode('&', $current), function ($part) use ($decodedKey) {
return rawurldecode(explode('=', $part)[0]) !== $decodedKey;
});
}
$result[] = self::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().
$key = strtr($key, self::$replaceQuery);
return $uri->withQuery(implode('&', $result));
}
if ($value !== null) {
$result[] = $key . '=' . strtr($value, self::$replaceQuery);
} else {
$result[] = $key;
/**
* 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));
@ -620,6 +615,47 @@ class Uri implements UriInterface
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)) {

View file

@ -69,10 +69,10 @@ function uri_for($uri)
* - metadata: Array of custom metadata.
* - size: Size of the stream.
*
* @param resource|string|null|int|float|bool|StreamInterface|callable $resource Entity body data
* @param array $options Additional options
* @param resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource Entity body data
* @param array $options Additional options
*
* @return Stream
* @return StreamInterface
* @throws \InvalidArgumentException if the $resource arg is not valid.
*/
function stream_for($resource = '', array $options = [])
@ -238,7 +238,7 @@ function modify_request(RequestInterface $request, array $changes)
}
if ($request instanceof ServerRequestInterface) {
return new ServerRequest(
return (new ServerRequest(
isset($changes['method']) ? $changes['method'] : $request->getMethod(),
$uri,
$headers,
@ -247,7 +247,11 @@ function modify_request(RequestInterface $request, array $changes)
? $changes['version']
: $request->getProtocolVersion(),
$request->getServerParams()
);
))
->withParsedBody($request->getParsedBody())
->withQueryParams($request->getQueryParams())
->withCookieParams($request->getCookieParams())
->withUploadedFiles($request->getUploadedFiles());
}
return new Request(
@ -431,7 +435,7 @@ function hash(
* @param StreamInterface $stream Stream to read from
* @param int $maxLength Maximum buffer length
*
* @return string|bool
* @return string
*/
function readline(StreamInterface $stream, $maxLength = null)
{
@ -495,7 +499,7 @@ function parse_response($message)
// between status-code and reason-phrase is required. But browsers accept
// responses without space and reason as well.
if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
throw new \InvalidArgumentException('Invalid response string');
throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']);
}
$parts = explode(' ', $data['start-line'], 3);
@ -516,8 +520,8 @@ function parse_response($message)
* PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
* be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
*
* @param string $str Query string to parse
* @param bool|string $urlEncoding How the query string is encoded
* @param string $str Query string to parse
* @param int|bool $urlEncoding How the query string is encoded
*
* @return array
*/
@ -533,9 +537,9 @@ function parse_query($str, $urlEncoding = true)
$decoder = function ($value) {
return rawurldecode(str_replace('+', ' ', $value));
};
} elseif ($urlEncoding == PHP_QUERY_RFC3986) {
} elseif ($urlEncoding === PHP_QUERY_RFC3986) {
$decoder = 'rawurldecode';
} elseif ($urlEncoding == PHP_QUERY_RFC1738) {
} elseif ($urlEncoding === PHP_QUERY_RFC1738) {
$decoder = 'urldecode';
} else {
$decoder = function ($str) { return $str; };
@ -633,6 +637,7 @@ function mimetype_from_filename($filename)
function mimetype_from_extension($extension)
{
static $mimetypes = [
'3gp' => 'video/3gpp',
'7z' => 'application/x-7z-compressed',
'aac' => 'audio/x-aac',
'ai' => 'application/postscript',
@ -680,6 +685,7 @@ function mimetype_from_extension($extension)
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mov' => 'video/quicktime',
'mkv' => 'video/x-matroska',
'mp3' => 'audio/mpeg',
'mp4' => 'video/mp4',
'mp4a' => 'audio/mp4',
@ -758,29 +764,53 @@ function _parse_message($message)
throw new \InvalidArgumentException('Invalid message');
}
// Iterate over each line in the message, accounting for line endings
$lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
$result = ['start-line' => array_shift($lines), 'headers' => [], 'body' => ''];
array_shift($lines);
$message = ltrim($message, "\r\n");
for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
$line = $lines[$i];
// If two line breaks were encountered, then this is the end of body
if (empty($line)) {
if ($i < $totalLines - 1) {
$result['body'] = implode('', array_slice($lines, $i + 2));
}
break;
}
if (strpos($line, ':')) {
$parts = explode(':', $line, 2);
$key = trim($parts[0]);
$value = isset($parts[1]) ? trim($parts[1]) : '';
$result['headers'][$key][] = $value;
}
$messageParts = preg_split("/\r?\n\r?\n/", $message, 2);
if ($messageParts === false || count($messageParts) !== 2) {
throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
}
return $result;
list($rawHeaders, $body) = $messageParts;
$rawHeaders .= "\r\n"; // Put back the delimiter we split previously
$headerParts = preg_split("/\r?\n/", $rawHeaders, 2);
if ($headerParts === false || count($headerParts) !== 2) {
throw new \InvalidArgumentException('Invalid message: Missing status line');
}
list($startLine, $rawHeaders) = $headerParts;
if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {
// Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0
$rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
}
/** @var array[] $headerLines */
$count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);
// If these aren't the same, then one line didn't match and there's an invalid header.
if ($count !== substr_count($rawHeaders, "\n")) {
// Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4
if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
}
throw new \InvalidArgumentException('Invalid header syntax');
}
$headers = [];
foreach ($headerLines as $headerLine) {
$headers[$headerLine[1]][] = $headerLine[2];
}
return [
'start-line' => $startLine,
'headers' => $headers,
'body' => $body,
];
}
/**
@ -809,6 +839,46 @@ function _parse_request_uri($path, array $headers)
return $scheme . '://' . $host . '/' . ltrim($path, '/');
}
/**
* Get a short summary of the message body
*
* Will return `null` if the response is not printable.
*
* @param MessageInterface $message The message to get the body summary
* @param int $truncateAt The maximum allowed size of the summary
*
* @return null|string
*/
function get_message_body_summary(MessageInterface $message, $truncateAt = 120)
{
$body = $message->getBody();
if (!$body->isSeekable() || !$body->isReadable()) {
return null;
}
$size = $body->getSize();
if ($size === 0) {
return null;
}
$summary = $body->read($truncateAt);
$body->rewind();
if ($size > $truncateAt) {
$summary .= ' (truncated...)';
}
// Matches any printable character, including unicode characters:
// letters, marks, numbers, punctuation, spacing, and separators.
if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
return null;
}
return $summary;
}
/** @internal */
function _caseless_remove($keys, array $data)
{