From 05affd38a8614f968cc8ca10884645763c53d6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20S=C3=B8derlind?= Date: Mon, 2 Mar 2026 10:51:24 +0100 Subject: [PATCH] Update PHP-Scoper --- php-scoper/composer.json | 14 +- php-scoper/composer.lock | 50 +-- vendor-prefixed/autoload.php | 7 +- vendor-prefixed/composer/autoload_real.php | 8 +- vendor-prefixed/composer/autoload_static.php | 4 +- vendor-prefixed/composer/platform_check.php | 5 +- .../guzzlehttp/guzzle/CHANGELOG.md | 43 ++ .../guzzlehttp/guzzle/composer.json | 4 +- .../guzzlehttp/guzzle/package-lock.json | 6 + .../guzzle/src/Cookie/SetCookie.php | 4 + .../guzzle/src/Exception/RequestException.php | 15 +- .../guzzle/src/Handler/CurlFactory.php | 111 ++++- .../guzzle/src/Handler/CurlMultiHandler.php | 19 +- .../guzzlehttp/guzzle/src/Handler/Proxy.php | 12 +- .../guzzle/src/Handler/StreamHandler.php | 17 +- .../guzzlehttp/guzzle/src/Middleware.php | 4 +- .../guzzlehttp/guzzle/src/Pool.php | 2 +- .../guzzle/src/PrepareBodyMiddleware.php | 4 +- .../guzzlehttp/guzzle/src/Utils.php | 4 +- .../guzzlehttp/guzzle/src/functions.php | 2 +- vendor-prefixed/guzzlehttp/psr7/CHANGELOG.md | 177 +++++++- vendor-prefixed/guzzlehttp/psr7/README.md | 97 +++-- vendor-prefixed/guzzlehttp/psr7/composer.json | 39 +- .../guzzlehttp/psr7/src/AppendStream.php | 60 ++- .../guzzlehttp/psr7/src/BufferStream.php | 45 +- .../guzzlehttp/psr7/src/CachingStream.php | 36 +- .../guzzlehttp/psr7/src/DroppingStream.php | 12 +- .../src/Exception/MalformedUriException.php | 12 + .../guzzlehttp/psr7/src/FnStream.php | 99 +++-- .../guzzlehttp/psr7/src/Header.php | 101 +++-- .../guzzlehttp/psr7/src/HttpFactory.php | 76 ++++ .../guzzlehttp/psr7/src/InflateStream.php | 46 +- .../guzzlehttp/psr7/src/LazyOpenStream.php | 20 +- .../guzzlehttp/psr7/src/LimitStream.php | 32 +- .../guzzlehttp/psr7/src/Message.php | 48 +-- .../guzzlehttp/psr7/src/MessageTrait.php | 66 ++- .../guzzlehttp/psr7/src/MimeType.php | 20 +- .../guzzlehttp/psr7/src/MultipartStream.php | 59 +-- .../guzzlehttp/psr7/src/NoSeekStream.php | 11 +- .../guzzlehttp/psr7/src/PumpStream.php | 76 ++-- vendor-prefixed/guzzlehttp/psr7/src/Query.php | 39 +- .../guzzlehttp/psr7/src/Request.php | 30 +- .../guzzlehttp/psr7/src/Response.php | 36 +- .../guzzlehttp/psr7/src/Rfc7230.php | 13 +- .../guzzlehttp/psr7/src/ServerRequest.php | 96 ++--- .../guzzlehttp/psr7/src/Stream.php | 82 ++-- .../psr7/src/StreamDecoratorTrait.php | 59 +-- .../guzzlehttp/psr7/src/StreamWrapper.php | 72 +++- .../guzzlehttp/psr7/src/UploadedFile.php | 161 ++----- vendor-prefixed/guzzlehttp/psr7/src/Uri.php | 294 +++++-------- .../guzzlehttp/psr7/src/UriComparator.php | 10 +- .../guzzlehttp/psr7/src/UriNormalizer.php | 44 +- .../guzzlehttp/psr7/src/UriResolver.php | 30 +- vendor-prefixed/guzzlehttp/psr7/src/Utils.php | 119 ++++-- .../guzzlehttp/psr7/src/functions.php | 400 ------------------ .../guzzlehttp/psr7/src/functions_include.php | 8 - vendor-prefixed/psr/http-factory/README.md | 12 + .../psr/http-factory/composer.json | 38 ++ .../src/RequestFactoryInterface.php | 18 + .../src/ResponseFactoryInterface.php | 18 + .../src/ServerRequestFactoryInterface.php | 24 ++ .../src/StreamFactoryInterface.php | 43 ++ .../src/UploadedFileFactoryInterface.php | 28 ++ .../http-factory/src/UriFactoryInterface.php | 17 + .../psr/http-message/composer.json | 4 +- .../psr/http-message/src/MessageInterface.php | 23 +- .../psr/http-message/src/RequestInterface.php | 13 +- .../http-message/src/ResponseInterface.php | 7 +- .../src/ServerRequestInterface.php | 23 +- .../psr/http-message/src/StreamInterface.php | 27 +- .../src/UploadedFileInterface.php | 13 +- .../psr/http-message/src/UriInterface.php | 33 +- 72 files changed, 1716 insertions(+), 1585 deletions(-) create mode 100644 vendor-prefixed/guzzlehttp/guzzle/package-lock.json create mode 100644 vendor-prefixed/guzzlehttp/psr7/src/Exception/MalformedUriException.php create mode 100644 vendor-prefixed/guzzlehttp/psr7/src/HttpFactory.php delete mode 100644 vendor-prefixed/guzzlehttp/psr7/src/functions.php delete mode 100644 vendor-prefixed/guzzlehttp/psr7/src/functions_include.php create mode 100644 vendor-prefixed/psr/http-factory/README.md create mode 100644 vendor-prefixed/psr/http-factory/composer.json create mode 100644 vendor-prefixed/psr/http-factory/src/RequestFactoryInterface.php create mode 100644 vendor-prefixed/psr/http-factory/src/ResponseFactoryInterface.php create mode 100644 vendor-prefixed/psr/http-factory/src/ServerRequestFactoryInterface.php create mode 100644 vendor-prefixed/psr/http-factory/src/StreamFactoryInterface.php create mode 100644 vendor-prefixed/psr/http-factory/src/UploadedFileFactoryInterface.php create mode 100644 vendor-prefixed/psr/http-factory/src/UriFactoryInterface.php diff --git a/php-scoper/composer.json b/php-scoper/composer.json index e0f0083..ad8bd73 100644 --- a/php-scoper/composer.json +++ b/php-scoper/composer.json @@ -1,8 +1,8 @@ { - "minimum-stability": "dev", - "prefer-stable": true, - "require-dev": { - "humbug/php-scoper": "~0.18.0", - "pxlrbt/php-scoper-prefix-remover": "~0.2.0" - } -} + "minimum-stability": "dev", + "prefer-stable": true, + "require-dev": { + "humbug/php-scoper": "~0.18.11", + "pxlrbt/php-scoper-prefix-remover": "~0.2.0" + } +} \ No newline at end of file diff --git a/php-scoper/composer.lock b/php-scoper/composer.lock index 596e08a..906ee68 100644 --- a/php-scoper/composer.lock +++ b/php-scoper/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "662e90c0dc2767302db3d1099e2e3d38", + "content-hash": "b4d28e1e0ec1e0f36323c981e5cc7973", "packages": [], "packages-dev": [ { @@ -533,16 +533,16 @@ }, { "name": "symfony/console", - "version": "v7.4.4", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894" + "reference": "6d643a93b47398599124022eb24d97c153c12f27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/41e38717ac1dd7a46b6bda7d6a82af2d98a78894", - "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894", + "url": "https://api.github.com/repos/symfony/console/zipball/6d643a93b47398599124022eb24d97c153c12f27", + "reference": "6d643a93b47398599124022eb24d97c153c12f27", "shasum": "" }, "require": { @@ -607,7 +607,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.4" + "source": "https://github.com/symfony/console/tree/v7.4.6" }, "funding": [ { @@ -627,7 +627,7 @@ "type": "tidelift" } ], - "time": "2026-01-13T11:36:38+00:00" + "time": "2026-02-25T17:02:47+00:00" }, { "name": "symfony/deprecation-contracts", @@ -774,16 +774,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.4.0", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "d551b38811096d0be9c4691d406991b47c0c630a" + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", - "reference": "d551b38811096d0be9c4691d406991b47c0c630a", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", "shasum": "" }, "require": { @@ -820,7 +820,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.4.0" + "source": "https://github.com/symfony/filesystem/tree/v7.4.6" }, "funding": [ { @@ -840,20 +840,20 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2026-02-25T16:50:00+00:00" }, { "name": "symfony/finder", - "version": "v7.4.5", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb" + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", - "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", + "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", "shasum": "" }, "require": { @@ -888,7 +888,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.5" + "source": "https://github.com/symfony/finder/tree/v7.4.6" }, "funding": [ { @@ -908,7 +908,7 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:07:59+00:00" + "time": "2026-01-29T09:40:50+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1414,16 +1414,16 @@ }, { "name": "symfony/string", - "version": "v7.4.4", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f" + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f", - "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f", + "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", "shasum": "" }, "require": { @@ -1481,7 +1481,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.4" + "source": "https://github.com/symfony/string/tree/v7.4.6" }, "funding": [ { @@ -1501,7 +1501,7 @@ "type": "tidelift" } ], - "time": "2026-01-12T10:54:30+00:00" + "time": "2026-02-09T09:33:46+00:00" }, { "name": "thecodingmachine/safe", diff --git a/vendor-prefixed/autoload.php b/vendor-prefixed/autoload.php index 2c4237b..9ee92dc 100644 --- a/vendor-prefixed/autoload.php +++ b/vendor-prefixed/autoload.php @@ -14,12 +14,9 @@ echo $err; } } - trigger_error( - $err, - E_USER_ERROR - ); + throw new RuntimeException($err); } require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit8fc9476b6e3a7e74b08053b13b0faab5::getLoader(); +return ComposerAutoloaderInitd7ed5f1afdb08b36117782761d9508e4::getLoader(); diff --git a/vendor-prefixed/composer/autoload_real.php b/vendor-prefixed/composer/autoload_real.php index 3fbb8bb..1d11df9 100644 --- a/vendor-prefixed/composer/autoload_real.php +++ b/vendor-prefixed/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit8fc9476b6e3a7e74b08053b13b0faab5 +class ComposerAutoloaderInitd7ed5f1afdb08b36117782761d9508e4 { private static $loader; @@ -24,12 +24,12 @@ public static function getLoader() require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit8fc9476b6e3a7e74b08053b13b0faab5', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitd7ed5f1afdb08b36117782761d9508e4', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit8fc9476b6e3a7e74b08053b13b0faab5', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitd7ed5f1afdb08b36117782761d9508e4', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit8fc9476b6e3a7e74b08053b13b0faab5::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitd7ed5f1afdb08b36117782761d9508e4::getInitializer($loader)); $loader->setClassMapAuthoritative(true); $loader->register(true); diff --git a/vendor-prefixed/composer/autoload_static.php b/vendor-prefixed/composer/autoload_static.php index fe766b2..56e0a63 100644 --- a/vendor-prefixed/composer/autoload_static.php +++ b/vendor-prefixed/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit8fc9476b6e3a7e74b08053b13b0faab5 +class ComposerStaticInitd7ed5f1afdb08b36117782761d9508e4 { public static $classMap = array ( 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', @@ -13,7 +13,7 @@ class ComposerStaticInit8fc9476b6e3a7e74b08053b13b0faab5 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->classMap = ComposerStaticInit8fc9476b6e3a7e74b08053b13b0faab5::$classMap; + $loader->classMap = ComposerStaticInitd7ed5f1afdb08b36117782761d9508e4::$classMap; }, null, ClassLoader::class); } diff --git a/vendor-prefixed/composer/platform_check.php b/vendor-prefixed/composer/platform_check.php index 589e9e7..6cd6b53 100644 --- a/vendor-prefixed/composer/platform_check.php +++ b/vendor-prefixed/composer/platform_check.php @@ -19,8 +19,7 @@ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; } } - trigger_error( - 'Composer detected issues in your platform: ' . implode(' ', $issues), - E_USER_ERROR + throw new \RuntimeException( + 'Composer detected issues in your platform: ' . implode(' ', $issues) ); } diff --git a/vendor-prefixed/guzzlehttp/guzzle/CHANGELOG.md b/vendor-prefixed/guzzlehttp/guzzle/CHANGELOG.md index c1470eb..5fe721e 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/CHANGELOG.md +++ b/vendor-prefixed/guzzlehttp/guzzle/CHANGELOG.md @@ -2,6 +2,49 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version. +## 7.10.0 - 2025-08-23 + +### Added + +- Support for PHP 8.5 + +### Changed + +- Adjusted `guzzlehttp/promises` version constraint to `^2.3` +- Adjusted `guzzlehttp/psr7` version constraint to `^2.8` + + +## 7.9.3 - 2025-03-27 + +### Changed + +- Remove explicit content-length header for GET requests +- Improve compatibility with bad servers for boolean cookie values + + +## 7.9.2 - 2024-07-24 + +### Fixed + +- Adjusted handler selection to use cURL if its version is 7.21.2 or higher, rather than 7.34.0 + + +## 7.9.1 - 2024-07-19 + +### Fixed + +- Fix TLS 1.3 check for HTTP/2 requests + + +## 7.9.0 - 2024-07-18 + +### Changed + +- Improve protocol version checks to provide feedback around unsupported protocols +- Only select the cURL handler by default if 7.34.0 or higher is linked +- Improved `CurlMultiHandler` to avoid busy wait if possible +- Dropped support for EOL `guzzlehttp/psr7` v1 +- Improved URI user info redaction in errors ## 7.8.2 - 2024-07-18 diff --git a/vendor-prefixed/guzzlehttp/guzzle/composer.json b/vendor-prefixed/guzzlehttp/guzzle/composer.json index c2c980c..c62bc07 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/composer.json +++ b/vendor-prefixed/guzzlehttp/guzzle/composer.json @@ -81,8 +81,8 @@ "require": { "php": "^7.2.5 || ^8.0", "ext-json": "*", - "guzzlehttp\/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp\/psr7": "^1.9.1 || ^2.6.3", + "guzzlehttp\/promises": "^2.3", + "guzzlehttp\/psr7": "^2.8", "psr\/http-client": "^1.0", "symfony\/deprecation-contracts": "^2.2 || ^3.0" }, diff --git a/vendor-prefixed/guzzlehttp/guzzle/package-lock.json b/vendor-prefixed/guzzlehttp/guzzle/package-lock.json new file mode 100644 index 0000000..0e14dc1 --- /dev/null +++ b/vendor-prefixed/guzzlehttp/guzzle/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "guzzle", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/vendor-prefixed/guzzlehttp/guzzle/src/Cookie/SetCookie.php index 50e0cab..a0d924a 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Cookie/SetCookie.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Cookie/SetCookie.php @@ -46,6 +46,10 @@ public static function fromString(string $cookie) : self if (\is_numeric($value)) { $data[$search] = (int) $value; } + } elseif ($search === 'Secure' || $search === 'Discard' || $search === 'HttpOnly') { + if ($value) { + $data[$search] = \true; + } } else { $data[$search] = $value; } diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Exception/RequestException.php b/vendor-prefixed/guzzlehttp/guzzle/src/Exception/RequestException.php index 1d31882..80e2196 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Exception/RequestException.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Exception/RequestException.php @@ -7,7 +7,6 @@ use Dekode\GravityForms\Vendor\Psr\Http\Client\RequestExceptionInterface; use Dekode\GravityForms\Vendor\Psr\Http\Message\RequestInterface; use Dekode\GravityForms\Vendor\Psr\Http\Message\ResponseInterface; -use Dekode\GravityForms\Vendor\Psr\Http\Message\UriInterface; /** * HTTP Request exception */ @@ -66,8 +65,7 @@ public static function create(RequestInterface $request, ?ResponseInterface $res $label = 'Unsuccessful request'; $className = __CLASS__; } - $uri = $request->getUri(); - $uri = static::obfuscateUri($uri); + $uri = \Dekode\GravityForms\Vendor\GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri()); // Client Error: `GET /` resulted in a `404 Not Found` response: // ... (truncated) $message = \sprintf('%s: `%s %s` resulted in a `%s %s` response', $label, $request->getMethod(), $uri->__toString(), $response->getStatusCode(), $response->getReasonPhrase()); @@ -77,17 +75,6 @@ public static function create(RequestInterface $request, ?ResponseInterface $res } return new $className($message, $request, $response, $previous, $handlerContext); } - /** - * Obfuscates URI if there is a username and a password present - */ - private static function obfuscateUri(UriInterface $uri) : UriInterface - { - $userInfo = $uri->getUserInfo(); - if (\false !== ($pos = \strpos($userInfo, ':'))) { - return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***'); - } - return $uri; - } /** * Get the request that caused the exception */ diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Handler/CurlFactory.php b/vendor-prefixed/guzzlehttp/guzzle/src/Handler/CurlFactory.php index 6a2ec9e..5aa062c 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Handler/CurlFactory.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Handler/CurlFactory.php @@ -11,6 +11,7 @@ use Dekode\GravityForms\Vendor\GuzzleHttp\TransferStats; use Dekode\GravityForms\Vendor\GuzzleHttp\Utils; use Dekode\GravityForms\Vendor\Psr\Http\Message\RequestInterface; +use Dekode\GravityForms\Vendor\Psr\Http\Message\UriInterface; /** * Creates curl resources from a request * @@ -40,6 +41,14 @@ public function __construct(int $maxHandles) } public function create(RequestInterface $request, array $options) : EasyHandle { + $protocolVersion = $request->getProtocolVersion(); + if ('2' === $protocolVersion || '2.0' === $protocolVersion) { + if (!self::supportsHttp2()) { + throw new ConnectException('HTTP/2 is supported by the cURL handler, however libcurl is built without HTTP/2 support.', $request); + } + } elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) { + throw new ConnectException(\sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request); + } if (isset($options['curl']['body_as_string'])) { $options['_body_as_string'] = $options['curl']['body_as_string']; unset($options['curl']['body_as_string']); @@ -61,12 +70,38 @@ public function create(RequestInterface $request, array $options) : EasyHandle \curl_setopt_array($easy->handle, $conf); return $easy; } + private static function supportsHttp2() : bool + { + static $supportsHttp2 = null; + if (null === $supportsHttp2) { + $supportsHttp2 = self::supportsTls12() && \defined('CURL_VERSION_HTTP2') && \CURL_VERSION_HTTP2 & \curl_version()['features']; + } + return $supportsHttp2; + } + private static function supportsTls12() : bool + { + static $supportsTls12 = null; + if (null === $supportsTls12) { + $supportsTls12 = \CURL_SSLVERSION_TLSv1_2 & \curl_version()['features']; + } + return $supportsTls12; + } + private static function supportsTls13() : bool + { + static $supportsTls13 = null; + if (null === $supportsTls13) { + $supportsTls13 = \defined('CURL_SSLVERSION_TLSv1_3') && \CURL_SSLVERSION_TLSv1_3 & \curl_version()['features']; + } + return $supportsTls13; + } public function release(EasyHandle $easy) : void { $resource = $easy->handle; unset($easy->handle); if (\count($this->handles) >= $this->maxHandles) { - \curl_close($resource); + if (\PHP_VERSION_ID < 80000) { + \curl_close($resource); + } } else { // Remove all callback functions as they can hold onto references // and are not cleaned up by curl_reset. Using curl_setopt_array @@ -118,7 +153,7 @@ private static function finishError(callable $handler, EasyHandle $easy, CurlFac { // Get error information and release the handle to the factory. $ctx = ['errno' => $easy->errno, 'error' => \curl_error($easy->handle), 'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME)] + \curl_getinfo($easy->handle); - $ctx[self::CURL_VERSION_STR] = \curl_version()['version']; + $ctx[self::CURL_VERSION_STR] = self::getCurlVersion(); $factory->release($easy); // Retry when nothing is present or when curl failed to rewind. if (empty($easy->options['_err_message']) && (!$easy->errno || $easy->errno == 65)) { @@ -126,6 +161,14 @@ private static function finishError(callable $handler, EasyHandle $easy, CurlFac } return self::createRejection($easy, $ctx); } + private static function getCurlVersion() : string + { + static $curlVersion = null; + if (null === $curlVersion) { + $curlVersion = \curl_version()['version']; + } + return $curlVersion; + } private static function createRejection(EasyHandle $easy, array $ctx) : PromiseInterface { static $connectionErrors = [\CURLE_OPERATION_TIMEOUTED => \true, \CURLE_COULDNT_RESOLVE_HOST => \true, \CURLE_COULDNT_CONNECT => \true, \CURLE_SSL_CONNECT_ERROR => \true, \CURLE_GOT_NOTHING => \true]; @@ -137,15 +180,32 @@ private static function createRejection(EasyHandle $easy, array $ctx) : PromiseI if ($easy->onHeadersException) { return P\Create::rejectionFor(new RequestException('An error was encountered during the on_headers event', $easy->request, $easy->response, $easy->onHeadersException, $ctx)); } - $message = \sprintf('cURL error %s: %s (%s)', $ctx['errno'], $ctx['error'], 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'); - $uriString = (string) $easy->request->getUri(); - if ($uriString !== '' && \false === \strpos($ctx['error'], $uriString)) { - $message .= \sprintf(' for %s', $uriString); + $uri = $easy->request->getUri(); + $sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri); + $message = \sprintf('cURL error %s: %s (%s)', $ctx['errno'], $sanitizedError, 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'); + if ('' !== $sanitizedError) { + $redactedUriString = \Dekode\GravityForms\Vendor\GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString(); + if ($redactedUriString !== '' && \false === \strpos($sanitizedError, $redactedUriString)) { + $message .= \sprintf(' for %s', $redactedUriString); + } } // Create a connection exception if it was a specific error code. $error = isset($connectionErrors[$easy->errno]) ? new ConnectException($message, $easy->request, null, $ctx) : new RequestException($message, $easy->request, $easy->response, null, $ctx); return P\Create::rejectionFor($error); } + private static function sanitizeCurlError(string $error, UriInterface $uri) : string + { + if ('' === $error) { + return $error; + } + $baseUri = $uri->withQuery('')->withFragment(''); + $baseUriString = $baseUri->__toString(); + if ('' === $baseUriString) { + return $error; + } + $redactedUriString = \Dekode\GravityForms\Vendor\GuzzleHttp\Psr7\Utils::redactUserInfo($baseUri)->__toString(); + return \str_replace($baseUriString, $redactedUriString, $error); + } /** * @return array */ @@ -156,10 +216,10 @@ private function getDefaultConf(EasyHandle $easy) : array $conf[\CURLOPT_PROTOCOLS] = \CURLPROTO_HTTP | \CURLPROTO_HTTPS; } $version = $easy->request->getProtocolVersion(); - if ($version == 1.1) { - $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1; - } elseif ($version == 2.0) { + if ('2' === $version || '2.0' === $version) { $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0; + } elseif ('1.1' === $version) { + $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1; } else { $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0; } @@ -285,8 +345,10 @@ private function applyHandlerOptions(EasyHandle $easy, array &$conf) : void // The empty string enables all available decoders and implicitly // sets a matching 'Accept-Encoding' header. $conf[\CURLOPT_ENCODING] = ''; - // But as the user did not specify any acceptable encodings we need - // to overwrite this implicit header with an empty one. + // But as the user did not specify any encoding preference, + // let's leave it up to server by preventing curl from sending + // the header, which will be interpreted as 'Accept-Encoding: *'. + // https://www.rfc-editor.org/rfc/rfc9110#field.accept-encoding $conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:'; } } @@ -343,23 +405,30 @@ private function applyHandlerOptions(EasyHandle $easy, array &$conf) : void } } if (isset($options['crypto_method'])) { - if (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) { - if (!\defined('CURL_SSLVERSION_TLSv1_0')) { - throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.0 not supported by your version of cURL'); + $protocolVersion = $easy->request->getProtocolVersion(); + // If HTTP/2, upgrade TLS 1.0 and 1.1 to 1.2 + if ('2' === $protocolVersion || '2.0' === $protocolVersion) { + if (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method'] || \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method'] || \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) { + $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2; + } elseif (\defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) { + if (!self::supportsTls13()) { + throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL'); + } + $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3; + } else { + throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided'); } + } elseif (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) { $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0; } elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) { - if (!\defined('CURL_SSLVERSION_TLSv1_1')) { - throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.1 not supported by your version of cURL'); - } $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1; } elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) { - if (!\defined('CURL_SSLVERSION_TLSv1_2')) { + if (!self::supportsTls12()) { throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.2 not supported by your version of cURL'); } $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2; } elseif (\defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) { - if (!\defined('CURL_SSLVERSION_TLSv1_3')) { + if (!self::supportsTls13()) { throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL'); } $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3; @@ -489,7 +558,9 @@ private function createHeaderFn(EasyHandle $easy) : callable public function __destruct() { foreach ($this->handles as $id => $handle) { - \curl_close($handle); + if (\PHP_VERSION_ID < 80000) { + \curl_close($handle); + } unset($this->handles[$id]); } } diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/vendor-prefixed/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php index ae1d175..2f24fe0 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php @@ -2,6 +2,7 @@ namespace Dekode\GravityForms\Vendor\GuzzleHttp\Handler; +use Closure; use Dekode\GravityForms\Vendor\GuzzleHttp\Promise as P; use Dekode\GravityForms\Vendor\GuzzleHttp\Promise\Promise; use Dekode\GravityForms\Vendor\GuzzleHttp\Promise\PromiseInterface; @@ -129,6 +130,8 @@ public function tick() : void } } } + // Run curl_multi_exec in the queue to enable other async tasks to run + P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue'])); // Step through the task queue which may add additional requests. P\Utils::queue()->run(); if ($this->active && \curl_multi_select($this->_mh, $this->selectTimeout) === -1) { @@ -137,9 +140,21 @@ public function tick() : void \usleep(250); } while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) { + // Prevent busy looping for slow HTTP requests. + \curl_multi_select($this->_mh, $this->selectTimeout); } $this->processMessages(); } + /** + * Runs \curl_multi_exec() inside the event loop, to prevent busy looping + */ + private function tickInQueue() : void + { + if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) { + \curl_multi_select($this->_mh, 0); + P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue'])); + } + } /** * Runs until all outstanding connections have completed. */ @@ -184,7 +199,9 @@ private function cancel($id) : bool $handle = $this->handles[$id]['easy']->handle; unset($this->delays[$id], $this->handles[$id]); \curl_multi_remove_handle($this->_mh, $handle); - \curl_close($handle); + if (\PHP_VERSION_ID < 80000) { + \curl_close($handle); + } return \true; } private function processMessages() : void diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Handler/Proxy.php b/vendor-prefixed/guzzlehttp/guzzle/src/Handler/Proxy.php index b4f9efc..d427ec0 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Handler/Proxy.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Handler/Proxy.php @@ -16,10 +16,10 @@ class Proxy * Sends synchronous requests to a specific handler while sending all other * requests to another handler. * - * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for normal responses - * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $sync Handler used for synchronous responses. + * @param callable(RequestInterface, array): PromiseInterface $default Handler used for normal responses + * @param callable(RequestInterface, array): PromiseInterface $sync Handler used for synchronous responses. * - * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler. + * @return callable(RequestInterface, array): PromiseInterface Returns the composed handler. */ public static function wrapSync(callable $default, callable $sync) : callable { @@ -35,10 +35,10 @@ public static function wrapSync(callable $default, callable $sync) : callable * performance benefits of curl while still supporting true streaming * through the StreamHandler. * - * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for non-streaming responses - * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $streaming Handler used for streaming responses + * @param callable(RequestInterface, array): PromiseInterface $default Handler used for non-streaming responses + * @param callable(RequestInterface, array): PromiseInterface $streaming Handler used for streaming responses * - * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler. + * @return callable(RequestInterface, array): PromiseInterface Returns the composed handler. */ public static function wrapStreaming(callable $default, callable $streaming) : callable { diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Handler/StreamHandler.php b/vendor-prefixed/guzzlehttp/guzzle/src/Handler/StreamHandler.php index 82719dc..14e63a6 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Handler/StreamHandler.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Handler/StreamHandler.php @@ -37,13 +37,17 @@ public function __invoke(RequestInterface $request, array $options) : PromiseInt if (isset($options['delay'])) { \usleep($options['delay'] * 1000); } + $protocolVersion = $request->getProtocolVersion(); + if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) { + throw new ConnectException(\sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request); + } $startTime = isset($options['on_stats']) ? Utils::currentTime() : null; try { // Does not support the expect header. $request = $request->withoutHeader('Expect'); // Append a content-length header if body size is zero to match - // cURL's behavior. - if (0 === $request->getBody()->getSize()) { + // the behavior of `CurlHandler` + if ((0 === \strcasecmp('PUT', $request->getMethod()) || 0 === \strcasecmp('POST', $request->getMethod())) && 0 === $request->getBody()->getSize()) { $request = $request->withHeader('Content-Length', '0'); } return $this->createResponse($request, $options, $this->createStream($request, $options), $startTime); @@ -210,7 +214,7 @@ private function createStream(RequestInterface $request, array $options) } // HTTP/1.1 streams using the PHP stream wrapper require a // Connection: close header - if ($request->getProtocolVersion() == '1.1' && !$request->hasHeader('Connection')) { + if ($request->getProtocolVersion() === '1.1' && !$request->hasHeader('Connection')) { $request = $request->withHeader('Connection', 'close'); } // Ensure SSL is verified by default @@ -244,8 +248,13 @@ private function createStream(RequestInterface $request, array $options) $contextResource = $this->createResource(static function () use($context, $params) { return \stream_context_create($context, $params); }); - return $this->createResource(function () use($uri, &$http_response_header, $contextResource, $context, $options, $request) { + return $this->createResource(function () use($uri, $contextResource, $context, $options, $request) { $resource = @\fopen((string) $uri, 'r', \false, $contextResource); + // See https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_http_response_header_predefined_variable + if (\function_exists('Dekode\\GravityForms\\Vendor\\http_get_last_response_headers')) { + /** @var array|null */ + $http_response_header = \Dekode\GravityForms\Vendor\http_get_last_response_headers(); + } $this->lastHeaders = $http_response_header ?? []; if (\false === $resource) { throw new ConnectException(\sprintf('Connection refused for URI %s', $uri), $request, null, $context); diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Middleware.php b/vendor-prefixed/guzzlehttp/guzzle/src/Middleware.php index 16d35e0..f3a91a3 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Middleware.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Middleware.php @@ -155,12 +155,12 @@ public static function retry(callable $decider, ?callable $delay = null) : calla * Middleware that logs requests, responses, and errors using a message * formatter. * - * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests. - * * @param LoggerInterface $logger Logs messages. * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings. * @param string $logLevel Level at which to log requests. * + * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests. + * * @return callable Returns a function that accepts the next handler. */ public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info') : callable diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Pool.php b/vendor-prefixed/guzzlehttp/guzzle/src/Pool.php index 5189d35..ced2a68 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Pool.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Pool.php @@ -79,7 +79,7 @@ public function promise() : PromiseInterface * @param ClientInterface $client Client used to send the requests * @param array|\Iterator $requests Requests to send concurrently. * @param array $options Passes through the options available in - * {@see \GuzzleHttp\Pool::__construct} + * {@see Pool::__construct} * * @return array Returns an array containing the response or an exception * in the same order that the requests were sent. diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php b/vendor-prefixed/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php index d932f81..de39d23 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php @@ -62,8 +62,8 @@ private function addExpectHeader(RequestInterface $request, array $options, arra return; } $expect = $options['expect'] ?? null; - // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0 - if ($expect === \false || $request->getProtocolVersion() < 1.1) { + // Return if disabled or using HTTP/1.0 + if ($expect === \false || $request->getProtocolVersion() === '1.0') { return; } // The expect header is unconditionally enabled diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/Utils.php b/vendor-prefixed/guzzlehttp/guzzle/src/Utils.php index 0050bdb..8f7ff75 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/Utils.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/Utils.php @@ -71,14 +71,14 @@ public static function debugResource($value = null) * * The returned handler is not wrapped by any default middlewares. * - * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system. + * @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system. * * @throws \RuntimeException if no viable Handler is available. */ public static function chooseHandler() : callable { $handler = null; - if (\defined('CURLOPT_CUSTOMREQUEST')) { + if (\defined('CURLOPT_CUSTOMREQUEST') && \function_exists('curl_version') && \version_compare(\curl_version()['version'], '7.21.2') >= 0) { if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) { $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler()); } elseif (\function_exists('curl_exec')) { diff --git a/vendor-prefixed/guzzlehttp/guzzle/src/functions.php b/vendor-prefixed/guzzlehttp/guzzle/src/functions.php index fbd292f..294d67b 100644 --- a/vendor-prefixed/guzzlehttp/guzzle/src/functions.php +++ b/vendor-prefixed/guzzlehttp/guzzle/src/functions.php @@ -47,7 +47,7 @@ function debug_resource($value = null) * * The returned handler is not wrapped by any default middlewares. * - * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system. + * @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system. * * @throws \RuntimeException if no viable Handler is available. * diff --git a/vendor-prefixed/guzzlehttp/psr7/CHANGELOG.md b/vendor-prefixed/guzzlehttp/psr7/CHANGELOG.md index 9b2b65c..4a2a121 100644 --- a/vendor-prefixed/guzzlehttp/psr7/CHANGELOG.md +++ b/vendor-prefixed/guzzlehttp/psr7/CHANGELOG.md @@ -1,50 +1,211 @@ # Change Log - All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 2.8.0 - 2025-08-23 + +### Added + +- Allow empty lists as header values + +### Changed + +- PHP 8.5 support + +## 2.7.1 - 2025-03-27 + +### Fixed + +- Fixed uppercase IPv6 addresses in URI + +### Changed + +- Improve uploaded file error message + +## 2.7.0 - 2024-07-18 + +### Added + +- Add `Utils::redactUserInfo()` method +- Add ability to encode bools as ints in `Query::build` + +## 2.6.3 - 2024-07-18 + +### Fixed + +- Make `StreamWrapper::stream_stat()` return `false` if inner stream's size is `null` + +### Changed + +- PHP 8.4 support + +## 2.6.2 - 2023-12-03 + +### Fixed + +- Fixed another issue with the fact that PHP transforms numeric strings in array keys to ints + +### Changed + +- Updated links in docs to their canonical versions +- Replaced `call_user_func*` with native calls + +## 2.6.1 - 2023-08-27 + +### Fixed + +- Properly handle the fact that PHP transforms numeric strings in array keys to ints -## Unreleased +## 2.6.0 - 2023-08-03 -## 1.9.1 - 2023-04-17 +### Changed + +- Updated the mime type map to add some new entries, fix a couple of invalid entries, and remove an invalid entry +- Fallback to `application/octet-stream` if we are unable to guess the content type for a multipart file upload + +## 2.5.1 - 2023-08-03 ### Fixed +- Corrected mime type for `.acc` files to `audio/aac` + +### Changed + +- PHP 8.3 support + +## 2.5.0 - 2023-04-17 + +### Changed + +- Adjusted `psr/http-message` version constraint to `^1.1 || ^2.0` + +## 2.4.5 - 2023-04-17 + +### Fixed + +- Prevent possible warnings on unset variables in `ServerRequest::normalizeNestedFileSpec` +- Fixed `Message::bodySummary` when `preg_match` fails - Fixed header validation issue -## 1.9.0 - 2022-06-20 +## 2.4.4 - 2023-03-09 + +### Changed + +- Removed the need for `AllowDynamicProperties` in `LazyOpenStream` + +## 2.4.3 - 2022-10-26 + +### Changed + +- Replaced `sha1(uniqid())` by `bin2hex(random_bytes(20))` + +## 2.4.2 - 2022-10-25 + +### Fixed + +- Fixed erroneous behaviour when combining host and relative path + +## 2.4.1 - 2022-08-28 + +### Fixed + +- Rewind body before reading in `Message::bodySummary` + +## 2.4.0 - 2022-06-20 ### Added +- Added provisional PHP 8.2 support - Added `UriComparator::isCrossOrigin` method -## 1.8.5 - 2022-03-20 +## 2.3.0 - 2022-06-09 + +### Fixed + +- Added `Header::splitList` method +- Added `Utils::tryGetContents` method +- Improved `Stream::getContents` method +- Updated mimetype mappings + +## 2.2.2 - 2022-06-08 + +### Fixed + +- Fix `Message::parseRequestUri` for numeric headers +- Re-wrap exceptions thrown in `fread` into runtime exceptions +- Throw an exception when multipart options is misformatted + +## 2.2.1 - 2022-03-20 ### Fixed - Correct header value validation -## 1.8.4 - 2022-03-20 +## 2.2.0 - 2022-03-20 + +### Added + +- A more compressive list of mime types +- Add JsonSerializable to Uri +- Missing return types + +### Fixed + +- Bug MultipartStream no `uri` metadata +- Bug MultipartStream with filename for `data://` streams +- Fixed new line handling in MultipartStream +- Reduced RAM usage when copying streams +- Updated parsing in `Header::normalize()` + +## 2.1.1 - 2022-03-20 ### Fixed - Validate header values properly -## 1.8.3 - 2021-10-05 +## 2.1.0 - 2021-10-06 + +### Changed + +- Attempting to create a `Uri` object from a malformed URI will no longer throw a generic + `InvalidArgumentException`, but rather a `MalformedUriException`, which inherits from the former + for backwards compatibility. Callers relying on the exception being thrown to detect invalid + URIs should catch the new exception. ### Fixed - Return `null` in caching stream size if remote size is `null` -## 1.8.2 - 2021-04-26 +## 2.0.0 - 2021-06-30 + +Identical to the RC release. + +## 2.0.0@RC-1 - 2021-04-29 ### Fixed - Handle possibly unset `url` in `stream_get_meta_data` +## 2.0.0@beta-1 - 2021-03-21 + +### Added + +- PSR-17 factories +- Made classes final +- PHP7 type hints + +### Changed + +- When building a query string, booleans are represented as 1 and 0. + +### Removed + +- PHP < 7.2 support +- All functions in the `GuzzleHttp\Psr7` namespace + ## 1.8.1 - 2021-03-21 ### Fixed diff --git a/vendor-prefixed/guzzlehttp/psr7/README.md b/vendor-prefixed/guzzlehttp/psr7/README.md index 64776cb..24aad86 100644 --- a/vendor-prefixed/guzzlehttp/psr7/README.md +++ b/vendor-prefixed/guzzlehttp/psr7/README.md @@ -4,16 +4,30 @@ This repository contains a full [PSR-7](https://www.php-fig.org/psr/psr-7/) message implementation, several stream decorators, and some helpful functionality like query string parsing. +![CI](https://github.com/guzzle/psr7/workflows/CI/badge.svg) +![Static analysis](https://github.com/guzzle/psr7/workflows/Static%20analysis/badge.svg) -[![Build Status](https://travis-ci.org/guzzle/psr7.svg?branch=master)](https://travis-ci.org/guzzle/psr7) - -# Stream implementation +## Features This package comes with a number of stream implementations and stream decorators. +## Installation + +```shell +composer require guzzlehttp/psr7 +``` + +## Version Guidance + +| Version | Status | PHP Version | +|---------|---------------------|--------------| +| 1.x | EOL (2024-06-30) | >=5.4,<8.2 | +| 2.x | Latest | >=7.2.5,<8.6 | + + ## AppendStream `GuzzleHttp\Psr7\AppendStream` @@ -130,10 +144,9 @@ $fnStream->rewind(); `GuzzleHttp\Psr7\InflateStream` -Uses PHP's zlib.inflate filter to inflate deflate or gzipped content. +Uses PHP's zlib.inflate filter to inflate zlib (HTTP deflate, RFC1950) or gzipped (RFC1952) content. -This stream decorator skips the first 10 bytes of the given stream to remove -the gzip header, converts the provided stream to a PHP stream resource, +This stream decorator converts the provided stream to a PHP stream resource, then appends the zlib.inflate filter. The stream is then converted back to a Guzzle stream resource to be used as a Guzzle stream. @@ -246,6 +259,8 @@ class EofCallbackStream implements StreamInterface private $callback; + private $stream; + public function __construct(StreamInterface $stream, callable $cb) { $this->stream = $stream; @@ -258,7 +273,7 @@ class EofCallbackStream implements StreamInterface // Invoke the callback when EOF is hit. if ($this->eof()) { - call_user_func($this->callback); + ($this->callback)(); } return $result; @@ -381,10 +396,28 @@ of the header. When a parameter does not contain a value, but just contains a key, this function will inject a key with a '' string value. -## `GuzzleHttp\Psr7\Header::normalize` +## `GuzzleHttp\Psr7\Header::splitList` + +`public static function splitList(string|string[] $header): string[]` + +Splits a HTTP header defined to contain a comma-separated list into +each individual value: + +``` +$knownEtags = Header::splitList($request->getHeader('if-none-match')); +``` + +Example headers include `accept`, `cache-control` and `if-none-match`. + + +## `GuzzleHttp\Psr7\Header::normalize` (deprecated) `public static function normalize(string|array $header): array` +`Header::normalize()` is deprecated in favor of [`Header::splitList()`](README.md#guzzlehttppsr7headersplitlist) +which performs the same operation with a cleaned up API and improved +documentation. + Converts an array of header values that may contain comma separated headers into an array of headers with no comma separated values. @@ -403,7 +436,7 @@ will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`. ## `GuzzleHttp\Psr7\Query::build` -`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986): string` +`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string` Build a query string from an array of key value pairs. @@ -465,11 +498,18 @@ a message. ## `GuzzleHttp\Psr7\Utils::readLine` -`public static function readLine(StreamInterface $stream, int $maxLength = null): string` +`public static function readLine(StreamInterface $stream, ?int $maxLength = null): string` Read a line from the stream up to the maximum allowed buffer length. +## `GuzzleHttp\Psr7\Utils::redactUserInfo` + +`public static function redactUserInfo(UriInterface $uri): UriInterface` + +Redact the password in the user info part of a URI. + + ## `GuzzleHttp\Psr7\Utils::streamFor` `public static function streamFor(resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource = '', array $options = []): StreamInterface` @@ -528,6 +568,17 @@ When fopen fails, PHP normally raises a warning. This function adds an error handler that checks for errors and throws an exception instead. +## `GuzzleHttp\Psr7\Utils::tryGetContents` + +`public static function tryGetContents(resource $stream): string` + +Safely gets the contents of a given stream. + +When stream_get_contents fails, PHP normally raises a warning. This +function adds an error handler that checks for errors and throws an +exception instead. + + ## `GuzzleHttp\Psr7\Utils::uriFor` `public static function uriFor(string|UriInterface $uri): UriInterface` @@ -555,7 +606,7 @@ Maps a file extensions to a mimetype. ## Upgrading from Function API -The static API was first introduced in 1.7.0, in order to mitigate problems with functions conflicting between global and local copies of the package. The function API will be removed in 2.0.0. A migration table has been provided here for your convenience: +The static API was first introduced in 1.7.0, in order to mitigate problems with functions conflicting between global and local copies of the package. The function API was removed in 2.0.0. A migration table has been provided here for your convenience: | Original Function | Replacement Method | |----------------|----------------| @@ -593,7 +644,7 @@ this library also provides additional functionality when working with URIs as st An instance of `Psr\Http\Message\UriInterface` can either be an absolute URI or a relative reference. 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 according to -[RFC 3986 Section 4.2](https://tools.ietf.org/html/rfc3986#section-4.2): +[RFC 3986 Section 4.2](https://datatracker.ietf.org/doc/html/rfc3986#section-4.2): - network-path references, e.g. `//example.com/path` - absolute-path references, e.g. `/path` @@ -630,7 +681,7 @@ termed a relative-path reference. ### `GuzzleHttp\Psr7\Uri::isSameDocumentReference` -`public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool` +`public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool` 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 @@ -652,8 +703,8 @@ or the standard port. This method can be used independently of the implementatio `public static function composeComponents($scheme, $authority, $path, $query, $fragment): string` Composes a URI reference string from its various components according to -[RFC 3986 Section 5.3](https://tools.ietf.org/html/rfc3986#section-5.3). Usually this method does not need to be called -manually but instead is used indirectly via `Psr\Http\Message\UriInterface::__toString`. +[RFC 3986 Section 5.3](https://datatracker.ietf.org/doc/html/rfc3986#section-5.3). Usually this method does not need +to be called manually but instead is used indirectly via `Psr\Http\Message\UriInterface::__toString`. ### `GuzzleHttp\Psr7\Uri::fromParts` @@ -697,8 +748,8 @@ Determines if a modified URL should be considered cross-origin with respect to a ## Reference Resolution `GuzzleHttp\Psr7\UriResolver` provides methods to resolve a URI reference in the context of a base URI according -to [RFC 3986 Section 5](https://tools.ietf.org/html/rfc3986#section-5). This is for example also what web browsers -do when resolving a link in a website based on the current request URI. +to [RFC 3986 Section 5](https://datatracker.ietf.org/doc/html/rfc3986#section-5). This is for example also what web +browsers do when resolving a link in a website based on the current request URI. ### `GuzzleHttp\Psr7\UriResolver::resolve` @@ -711,7 +762,7 @@ Converts the relative URI into a new URI that is resolved against the base URI. `public static function removeDotSegments(string $path): string` Removes dot segments from a path and returns the new path according to -[RFC 3986 Section 5.2.4](https://tools.ietf.org/html/rfc3986#section-5.2.4). +[RFC 3986 Section 5.2.4](https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4). ### `GuzzleHttp\Psr7\UriResolver::relativize` @@ -737,7 +788,7 @@ echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // pr ## Normalization and Comparison `GuzzleHttp\Psr7\UriNormalizer` provides methods to normalize and compare URIs according to -[RFC 3986 Section 6](https://tools.ietf.org/html/rfc3986#section-6). +[RFC 3986 Section 6](https://datatracker.ietf.org/doc/html/rfc3986#section-6). ### `GuzzleHttp\Psr7\UriNormalizer::normalize` @@ -819,14 +870,6 @@ This of course assumes they will be resolved against the same base URI. If this equivalence or difference of relative references does not mean anything. -## Version Guidance - -| Version | Status | PHP Version | -|---------|----------------|------------------| -| 1.x | Security fixes | >=5.4,<8.1 | -| 2.x | Latest | ^7.2.5 \|\| ^8.0 | - - ## Security If you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/psr7/security/policy) for more information. diff --git a/vendor-prefixed/guzzlehttp/psr7/composer.json b/vendor-prefixed/guzzlehttp/psr7/composer.json index 0ddd3c5..79cb4d9 100644 --- a/vendor-prefixed/guzzlehttp/psr7/composer.json +++ b/vendor-prefixed/guzzlehttp/psr7/composer.json @@ -42,41 +42,52 @@ "name": "Tobias Schultze", "email": "webmaster@tubo-world.de", "homepage": "https:\/\/github.com\/Tobion" + }, + { + "name": "M\u00e1rk S\u00e1gi-Kaz\u00e1r", + "email": "mark.sagikazar@gmail.com", + "homepage": "https:\/\/sagikazarmark.hu" } ], "require": { - "php": ">=5.4.0", - "psr\/http-message": "~1.0", - "ralouphie\/getallheaders": "^2.0.5 || ^3.0.0" - }, - "require-dev": { - "phpunit\/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10", - "ext-zlib": "*" + "php": "^7.2.5 || ^8.0", + "psr\/http-factory": "^1.0", + "psr\/http-message": "^1.1 || ^2.0", + "ralouphie\/getallheaders": "^3.0" }, "provide": { + "psr\/http-factory-implementation": "1.0", "psr\/http-message-implementation": "1.0" }, + "require-dev": { + "bamarni\/composer-bin-plugin": "^1.8.2", + "http-interop\/http-factory-tests": "0.9.0", + "phpunit\/phpunit": "^8.5.44 || ^9.6.25" + }, "suggest": { "laminas\/laminas-httphandlerrunner": "Emit PSR-7 responses" }, "autoload": { "psr-4": { "Dekode\\GravityForms\\Vendor\\GuzzleHttp\\Psr7\\": "src\/" - }, - "files": [ - "src\/functions_include.php" - ] + } }, "autoload-dev": { "psr-4": { "Dekode\\GravityForms\\Vendor\\GuzzleHttp\\Tests\\Psr7\\": "tests\/" } }, + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, "config": { - "preferred-install": "dist", - "sort-packages": true, "allow-plugins": { "bamarni\/composer-bin-plugin": true - } + }, + "preferred-install": "dist", + "sort-packages": true } } \ No newline at end of file diff --git a/vendor-prefixed/guzzlehttp/psr7/src/AppendStream.php b/vendor-prefixed/guzzlehttp/psr7/src/AppendStream.php index d9f0708..e876d07 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/AppendStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/AppendStream.php @@ -1,5 +1,6 @@ addStream($stream); } } - public function __toString() + public function __toString() : string { try { $this->rewind(); return $this->getContents(); - } catch (\Exception $e) { + } catch (\Throwable $e) { + if (\PHP_VERSION_ID >= 70400) { + throw $e; + } + \trigger_error(\sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR); return ''; } } @@ -43,7 +49,7 @@ public function __toString() * * @throws \InvalidArgumentException if the stream is not readable */ - public function addStream(StreamInterface $stream) + public function addStream(StreamInterface $stream) : void { if (!$stream->isReadable()) { throw new \InvalidArgumentException('Each stream must be readable'); @@ -54,16 +60,14 @@ public function addStream(StreamInterface $stream) } $this->streams[] = $stream; } - public function getContents() + public function getContents() : string { return Utils::copyToString($this); } /** * Closes each attached stream. - * - * {@inheritdoc} */ - public function close() + public function close() : void { $this->pos = $this->current = 0; $this->seekable = \true; @@ -76,8 +80,6 @@ public function close() * Detaches each attached stream. * * Returns null as it's not clear which underlying stream resource to return. - * - * {@inheritdoc} */ public function detach() { @@ -89,7 +91,7 @@ public function detach() $this->streams = []; return null; } - public function tell() + public function tell() : int { return $this->pos; } @@ -98,10 +100,8 @@ public function tell() * * If any of the streams do not return a valid number, then the size of the * append stream cannot be determined and null is returned. - * - * {@inheritdoc} */ - public function getSize() + public function getSize() : ?int { $size = 0; foreach ($this->streams as $stream) { @@ -113,20 +113,18 @@ public function getSize() } return $size; } - public function eof() + public function eof() : bool { return !$this->streams || $this->current >= \count($this->streams) - 1 && $this->streams[$this->current]->eof(); } - public function rewind() + public function rewind() : void { $this->seek(0); } /** * Attempts to seek to the given position. Only supports SEEK_SET. - * - * {@inheritdoc} */ - public function seek($offset, $whence = \SEEK_SET) + public function seek($offset, $whence = \SEEK_SET) : void { if (!$this->seekable) { throw new \RuntimeException('This AppendStream is not seekable'); @@ -152,10 +150,8 @@ public function seek($offset, $whence = \SEEK_SET) } /** * Reads from all of the appended streams until the length is met or EOF. - * - * {@inheritdoc} */ - public function read($length) + public function read($length) : string { $buffer = ''; $total = \count($this->streams) - 1; @@ -168,11 +164,10 @@ public function read($length) if ($this->current === $total) { break; } - $this->current++; + ++$this->current; } $result = $this->streams[$this->current]->read($remaining); - // Using a loose comparison here to match on '', false, and null - if ($result == null) { + if ($result === '') { $progressToNext = \true; continue; } @@ -182,22 +177,25 @@ public function read($length) $this->pos += \strlen($buffer); return $buffer; } - public function isReadable() + public function isReadable() : bool { return \true; } - public function isWritable() + public function isWritable() : bool { return \false; } - public function isSeekable() + public function isSeekable() : bool { return $this->seekable; } - public function write($string) + public function write($string) : int { throw new \RuntimeException('Cannot write to an AppendStream'); } + /** + * @return mixed + */ public function getMetadata($key = null) { return $key ? null : []; diff --git a/vendor-prefixed/guzzlehttp/psr7/src/BufferStream.php b/vendor-prefixed/guzzlehttp/psr7/src/BufferStream.php index 51c26a1..ec92fd4 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/BufferStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/BufferStream.php @@ -1,5 +1,6 @@ hwm = $hwm; } - public function __toString() + public function __toString() : string { return $this->getContents(); } - public function getContents() + public function getContents() : string { $buffer = $this->buffer; $this->buffer = ''; return $buffer; } - public function close() + public function close() : void { $this->buffer = ''; } @@ -47,42 +48,42 @@ public function detach() $this->close(); return null; } - public function getSize() + public function getSize() : ?int { return \strlen($this->buffer); } - public function isReadable() + public function isReadable() : bool { return \true; } - public function isWritable() + public function isWritable() : bool { return \true; } - public function isSeekable() + public function isSeekable() : bool { return \false; } - public function rewind() + public function rewind() : void { $this->seek(0); } - public function seek($offset, $whence = \SEEK_SET) + public function seek($offset, $whence = \SEEK_SET) : void { throw new \RuntimeException('Cannot seek a BufferStream'); } - public function eof() + public function eof() : bool { return \strlen($this->buffer) === 0; } - public function tell() + public function tell() : int { throw new \RuntimeException('Cannot determine the position of a BufferStream'); } /** * Reads data from the buffer. */ - public function read($length) + public function read($length) : string { $currentLength = \strlen($this->buffer); if ($length >= $currentLength) { @@ -99,18 +100,20 @@ public function read($length) /** * Writes data to the buffer. */ - public function write($string) + public function write($string) : int { $this->buffer .= $string; - // TODO: What should happen here? if (\strlen($this->buffer) >= $this->hwm) { - return \false; + return 0; } return \strlen($string); } + /** + * @return mixed + */ public function getMetadata($key = null) { - if ($key == 'hwm') { + if ($key === 'hwm') { return $this->hwm; } return $key ? null : []; diff --git a/vendor-prefixed/guzzlehttp/psr7/src/CachingStream.php b/vendor-prefixed/guzzlehttp/psr7/src/CachingStream.php index 4746623..93e3fb0 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/CachingStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/CachingStream.php @@ -1,33 +1,36 @@ remoteStream = $stream; $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+')); } - public function getSize() + public function getSize() : ?int { $remoteSize = $this->remoteStream->getSize(); if (null === $remoteSize) { @@ -35,17 +38,17 @@ public function getSize() } return \max($this->stream->getSize(), $remoteSize); } - public function rewind() + public function rewind() : void { $this->seek(0); } - public function seek($offset, $whence = \SEEK_SET) + public function seek($offset, $whence = \SEEK_SET) : void { - if ($whence == \SEEK_SET) { + if ($whence === \SEEK_SET) { $byte = $offset; - } elseif ($whence == \SEEK_CUR) { + } elseif ($whence === \SEEK_CUR) { $byte = $offset + $this->tell(); - } elseif ($whence == \SEEK_END) { + } elseif ($whence === \SEEK_END) { $size = $this->remoteStream->getSize(); if ($size === null) { $size = $this->cacheEntireStream(); @@ -67,7 +70,7 @@ public function seek($offset, $whence = \SEEK_SET) $this->stream->seek($byte); } } - public function read($length) + public function read($length) : string { // Perform a regular read on any previously read data from the buffer $data = $this->stream->read($length); @@ -89,7 +92,7 @@ public function read($length) } return $data; } - public function write($string) + public function write($string) : int { // When appending to the end of the currently read stream, you'll want // to skip bytes from being read from the remote stream to emulate @@ -101,18 +104,19 @@ public function write($string) } return $this->stream->write($string); } - public function eof() + public function eof() : bool { return $this->stream->eof() && $this->remoteStream->eof(); } /** * Close both the remote stream and buffer stream */ - public function close() + public function close() : void { - $this->remoteStream->close() && $this->stream->close(); + $this->remoteStream->close(); + $this->stream->close(); } - private function cacheEntireStream() + private function cacheEntireStream() : int { $target = new FnStream(['write' => 'strlen']); Utils::copyToStream($this, $target); diff --git a/vendor-prefixed/guzzlehttp/psr7/src/DroppingStream.php b/vendor-prefixed/guzzlehttp/psr7/src/DroppingStream.php index f7953e8..9bf63e3 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/DroppingStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/DroppingStream.php @@ -1,28 +1,30 @@ stream = $stream; $this->maxLength = $maxLength; } - public function write($string) + public function write($string) : int { $diff = $this->maxLength - $this->stream->getSize(); // Begin returning 0 when the underlying stream is too large. diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Exception/MalformedUriException.php b/vendor-prefixed/guzzlehttp/psr7/src/Exception/MalformedUriException.php new file mode 100644 index 0000000..d003add --- /dev/null +++ b/vendor-prefixed/guzzlehttp/psr7/src/Exception/MalformedUriException.php @@ -0,0 +1,12 @@ + */ private $methods; - /** @var array Methods that must be implemented in the given array */ - private static $slots = ['__toString', 'close', 'detach', 'rewind', 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write', 'isReadable', 'read', 'getContents', 'getMetadata']; /** - * @param array $methods Hash of method name to a callable. + * @param array $methods Hash of method name to a callable. */ public function __construct(array $methods) { @@ -33,7 +32,7 @@ public function __construct(array $methods) * * @throws \BadMethodCallException */ - public function __get($name) + public function __get(string $name) : void { throw new \BadMethodCallException(\str_replace('_fn_', '', $name) . '() is not implemented in the FnStream'); } @@ -43,7 +42,7 @@ public function __get($name) public function __destruct() { if (isset($this->_fn_close)) { - \call_user_func($this->_fn_close); + ($this->_fn_close)(); } } /** @@ -51,7 +50,7 @@ public function __destruct() * * @throws \LogicException */ - public function __wakeup() + public function __wakeup() : void { throw new \LogicException('FnStream should never be unserialized'); } @@ -59,8 +58,8 @@ public function __wakeup() * Adds custom functionality to an underlying stream by intercepting * specific method calls. * - * @param StreamInterface $stream Stream to decorate - * @param array $methods Hash of method name to a closure + * @param StreamInterface $stream Stream to decorate + * @param array $methods Hash of method name to a closure * * @return FnStream */ @@ -68,69 +67,83 @@ public static function decorate(StreamInterface $stream, array $methods) { // If any of the required methods were not provided, then simply // proxy to the decorated stream. - foreach (\array_diff(self::$slots, \array_keys($methods)) as $diff) { - $methods[$diff] = [$stream, $diff]; + foreach (\array_diff(self::SLOTS, \array_keys($methods)) as $diff) { + /** @var callable $callable */ + $callable = [$stream, $diff]; + $methods[$diff] = $callable; } return new self($methods); } - public function __toString() - { - return \call_user_func($this->_fn___toString); + public function __toString() : string + { + try { + /** @var string */ + return ($this->_fn___toString)(); + } catch (\Throwable $e) { + if (\PHP_VERSION_ID >= 70400) { + throw $e; + } + \trigger_error(\sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR); + return ''; + } } - public function close() + public function close() : void { - return \call_user_func($this->_fn_close); + ($this->_fn_close)(); } public function detach() { - return \call_user_func($this->_fn_detach); + return ($this->_fn_detach)(); } - public function getSize() + public function getSize() : ?int { - return \call_user_func($this->_fn_getSize); + return ($this->_fn_getSize)(); } - public function tell() + public function tell() : int { - return \call_user_func($this->_fn_tell); + return ($this->_fn_tell)(); } - public function eof() + public function eof() : bool { - return \call_user_func($this->_fn_eof); + return ($this->_fn_eof)(); } - public function isSeekable() + public function isSeekable() : bool { - return \call_user_func($this->_fn_isSeekable); + return ($this->_fn_isSeekable)(); } - public function rewind() + public function rewind() : void { - \call_user_func($this->_fn_rewind); + ($this->_fn_rewind)(); } - public function seek($offset, $whence = \SEEK_SET) + public function seek($offset, $whence = \SEEK_SET) : void { - \call_user_func($this->_fn_seek, $offset, $whence); + ($this->_fn_seek)($offset, $whence); } - public function isWritable() + public function isWritable() : bool { - return \call_user_func($this->_fn_isWritable); + return ($this->_fn_isWritable)(); } - public function write($string) + public function write($string) : int { - return \call_user_func($this->_fn_write, $string); + return ($this->_fn_write)($string); } - public function isReadable() + public function isReadable() : bool { - return \call_user_func($this->_fn_isReadable); + return ($this->_fn_isReadable)(); } - public function read($length) + public function read($length) : string { - return \call_user_func($this->_fn_read, $length); + return ($this->_fn_read)($length); } - public function getContents() + public function getContents() : string { - return \call_user_func($this->_fn_getContents); + return ($this->_fn_getContents)(); } + /** + * @return mixed + */ public function getMetadata($key = null) { - return \call_user_func($this->_fn_getMetadata, $key); + return ($this->_fn_getMetadata)($key); } } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Header.php b/vendor-prefixed/guzzlehttp/psr7/src/Header.php index fe56cff..b949b54 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Header.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Header.php @@ -1,5 +1,6 @@ ]+>|[^=]+/', $kvp, $matches)) { - $m = $matches[0]; - if (isset($m[1])) { - $part[\trim($m[0], $trimmed)] = \trim($m[1], $trimmed); - } else { - $part[] = \trim($m[0], $trimmed); + foreach ((array) $header as $value) { + foreach (self::splitList($value) as $val) { + $part = []; + foreach (\preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) ?: [] as $kvp) { + if (\preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { + $m = $matches[0]; + if (isset($m[1])) { + $part[\trim($m[0], $trimmed)] = \trim($m[1], $trimmed); + } else { + $part[] = \trim($m[0], $trimmed); + } } } - } - if ($part) { - $params[] = $part; + if ($part) { + $params[] = $part; + } } } return $params; @@ -42,23 +43,73 @@ public static function parse($header) * * @param string|array $header Header to normalize. * - * @return array Returns the normalized header field values. + * @deprecated Use self::splitList() instead. */ - public static function normalize($header) + public static function normalize($header) : array { - if (!\is_array($header)) { - return \array_map('trim', \explode(',', $header)); + $result = []; + foreach ((array) $header as $value) { + foreach (self::splitList($value) as $parsed) { + $result[] = $parsed; + } + } + return $result; + } + /** + * Splits a HTTP header defined to contain a comma-separated list into + * each individual value. Empty values will be removed. + * + * Example headers include 'accept', 'cache-control' and 'if-none-match'. + * + * This method must not be used to parse headers that are not defined as + * a list, such as 'user-agent' or 'set-cookie'. + * + * @param string|string[] $values Header value as returned by MessageInterface::getHeader() + * + * @return string[] + */ + public static function splitList($values) : array + { + if (!\is_array($values)) { + $values = [$values]; } $result = []; - foreach ($header as $value) { - foreach ((array) $value as $v) { - if (\strpos($v, ',') === \false) { - $result[] = $v; + foreach ($values as $value) { + if (!\is_string($value)) { + throw new \TypeError('$header must either be a string or an array containing strings.'); + } + $v = ''; + $isQuoted = \false; + $isEscaped = \false; + for ($i = 0, $max = \strlen($value); $i < $max; ++$i) { + if ($isEscaped) { + $v .= $value[$i]; + $isEscaped = \false; continue; } - foreach (\preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) { - $result[] = \trim($vv); + if (!$isQuoted && $value[$i] === ',') { + $v = \trim($v); + if ($v !== '') { + $result[] = $v; + } + $v = ''; + continue; } + if ($isQuoted && $value[$i] === '\\') { + $isEscaped = \true; + $v .= $value[$i]; + continue; + } + if ($value[$i] === '"') { + $isQuoted = !$isQuoted; + $v .= $value[$i]; + continue; + } + $v .= $value[$i]; + } + $v = \trim($v); + if ($v !== '') { + $result[] = $v; } } return $result; diff --git a/vendor-prefixed/guzzlehttp/psr7/src/HttpFactory.php b/vendor-prefixed/guzzlehttp/psr7/src/HttpFactory.php new file mode 100644 index 0000000..0485765 --- /dev/null +++ b/vendor-prefixed/guzzlehttp/psr7/src/HttpFactory.php @@ -0,0 +1,76 @@ +getSize(); + } + return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType); + } + public function createStream(string $content = '') : StreamInterface + { + return Utils::streamFor($content); + } + public function createStreamFromFile(string $file, string $mode = 'r') : StreamInterface + { + try { + $resource = Utils::tryFopen($file, $mode); + } catch (\RuntimeException $e) { + if ('' === $mode || \false === \in_array($mode[0], ['r', 'w', 'a', 'x', 'c'], \true)) { + throw new \InvalidArgumentException(\sprintf('Invalid file opening mode "%s"', $mode), 0, $e); + } + throw $e; + } + return Utils::streamFor($resource); + } + public function createStreamFromResource($resource) : StreamInterface + { + return Utils::streamFor($resource); + } + public function createServerRequest(string $method, $uri, array $serverParams = []) : ServerRequestInterface + { + if (empty($method)) { + if (!empty($serverParams['REQUEST_METHOD'])) { + $method = $serverParams['REQUEST_METHOD']; + } else { + throw new \InvalidArgumentException('Cannot determine HTTP method'); + } + } + return new ServerRequest($method, $uri, [], null, '1.1', $serverParams); + } + public function createResponse(int $code = 200, string $reasonPhrase = '') : ResponseInterface + { + return new Response($code, [], null, '1.1', $reasonPhrase); + } + public function createRequest(string $method, $uri) : RequestInterface + { + return new Request($method, $uri); + } + public function createUri(string $uri = '') : UriInterface + { + return new Uri($uri); + } +} diff --git a/vendor-prefixed/guzzlehttp/psr7/src/InflateStream.php b/vendor-prefixed/guzzlehttp/psr7/src/InflateStream.php index 603e7a4..d9700c6 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/InflateStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/InflateStream.php @@ -1,51 +1,33 @@ read(10); - $filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header); - // Skip the header, that is 10 + length of filename + 1 (nil) bytes - $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength); $resource = StreamWrapper::getResource($stream); - \stream_filter_append($resource, 'zlib.inflate', \STREAM_FILTER_READ); + // Specify window=15+32, so zlib will use header detection to both gzip (with header) and zlib data + // See https://www.zlib.net/manual.html#Advanced definition of inflateInit2 + // "Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection" + // Default window size is 15. + \stream_filter_append($resource, 'zlib.inflate', \STREAM_FILTER_READ, ['window' => 15 + 32]); $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource)); } - /** - * @param StreamInterface $stream - * @param $header - * - * @return int - */ - private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header) - { - $filename_header_length = 0; - if (\substr(\bin2hex($header), 6, 2) === '08') { - // we have a filename, read until nil - $filename_header_length = 1; - while ($stream->read(1) !== \chr(0)) { - $filename_header_length++; - } - } - return $filename_header_length; - } } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/LazyOpenStream.php b/vendor-prefixed/guzzlehttp/psr7/src/LazyOpenStream.php index bf00dc5..9cc91d4 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/LazyOpenStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/LazyOpenStream.php @@ -1,36 +1,40 @@ filename = $filename; $this->mode = $mode; + // unsetting the property forces the first access to go through + // __get(). + unset($this->stream); } /** * Creates the underlying stream lazily when required. - * - * @return StreamInterface */ - protected function createStream() + protected function createStream() : StreamInterface { return Utils::streamFor(Utils::tryFopen($this->filename, $this->mode)); } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/LimitStream.php b/vendor-prefixed/guzzlehttp/psr7/src/LimitStream.php index d18f2d8..31fa1b7 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/LimitStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/LimitStream.php @@ -1,20 +1,21 @@ stream = $stream; $this->setLimit($limit); $this->setOffset($offset); } - public function eof() + public function eof() : bool { // Always return true if the underlying stream is EOF if ($this->stream->eof()) { return \true; } // No limit and the underlying stream is not at EOF - if ($this->limit == -1) { + if ($this->limit === -1) { return \false; } return $this->stream->tell() >= $this->offset + $this->limit; } /** * Returns the size of the limited subset of data - * {@inheritdoc} */ - public function getSize() + public function getSize() : ?int { if (null === ($length = $this->stream->getSize())) { return null; - } elseif ($this->limit == -1) { + } elseif ($this->limit === -1) { return $length - $this->offset; } else { return \min($this->limit, $length - $this->offset); @@ -56,9 +56,8 @@ public function getSize() } /** * Allow for a bounded seek on the read limited stream - * {@inheritdoc} */ - public function seek($offset, $whence = \SEEK_SET) + public function seek($offset, $whence = \SEEK_SET) : void { if ($whence !== \SEEK_SET || $offset < 0) { throw new \RuntimeException(\sprintf('Cannot seek to offset %s with whence %s', $offset, $whence)); @@ -73,9 +72,8 @@ public function seek($offset, $whence = \SEEK_SET) } /** * Give a relative tell() - * {@inheritdoc} */ - public function tell() + public function tell() : int { return $this->stream->tell() - $this->offset; } @@ -86,7 +84,7 @@ public function tell() * * @throws \RuntimeException if the stream cannot be seeked. */ - public function setOffset($offset) + public function setOffset(int $offset) : void { $current = $this->stream->tell(); if ($current !== $offset) { @@ -108,13 +106,13 @@ public function setOffset($offset) * @param int $limit Number of bytes to allow to be read from the stream. * Use -1 for no limit. */ - public function setLimit($limit) + public function setLimit(int $limit) : void { $this->limit = $limit; } - public function read($length) + public function read($length) : string { - if ($this->limit == -1) { + if ($this->limit === -1) { return $this->stream->read($length); } // Check if the current position is less than the total allowed diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Message.php b/vendor-prefixed/guzzlehttp/psr7/src/Message.php index 5481b45..31164f8 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Message.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Message.php @@ -1,5 +1,6 @@ getMethod() . ' ' . $message->getRequestTarget()) . ' HTTP/' . $message->getProtocolVersion(); @@ -27,7 +26,7 @@ public static function toString(MessageInterface $message) throw new \InvalidArgumentException('Unknown message type'); } foreach ($message->getHeaders() as $name => $values) { - if (\strtolower($name) === 'set-cookie') { + if (\is_string($name) && \strtolower($name) === 'set-cookie') { foreach ($values as $value) { $msg .= "\r\n{$name}: " . $value; } @@ -44,10 +43,8 @@ public static function toString(MessageInterface $message) * * @param MessageInterface $message The message to get the body summary * @param int $truncateAt The maximum allowed size of the summary - * - * @return string|null */ - public static function bodySummary(MessageInterface $message, $truncateAt = 120) + public static function bodySummary(MessageInterface $message, int $truncateAt = 120) : ?string { $body = $message->getBody(); if (!$body->isSeekable() || !$body->isReadable()) { @@ -57,6 +54,7 @@ public static function bodySummary(MessageInterface $message, $truncateAt = 120) if ($size === 0) { return null; } + $body->rewind(); $summary = $body->read($truncateAt); $body->rewind(); if ($size > $truncateAt) { @@ -64,7 +62,7 @@ public static function bodySummary(MessageInterface $message, $truncateAt = 120) } // 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]/u', $summary)) { + if (\preg_match('/[^\\pL\\pM\\pN\\pP\\pS\\pZ\\n\\r\\t]/u', $summary) !== 0) { return null; } return $summary; @@ -79,7 +77,7 @@ public static function bodySummary(MessageInterface $message, $truncateAt = 120) * * @throws \RuntimeException */ - public static function rewindBody(MessageInterface $message) + public static function rewindBody(MessageInterface $message) : void { $body = $message->getBody(); if ($body->tell()) { @@ -94,10 +92,8 @@ public static function rewindBody(MessageInterface $message) * array values, and a "body" key containing the body of the message. * * @param string $message HTTP request or response to parse. - * - * @return array */ - public static function parseMessage($message) + public static function parseMessage(string $message) : array { if (!$message) { throw new \InvalidArgumentException('Invalid message'); @@ -107,14 +103,14 @@ public static function parseMessage($message) if ($messageParts === \false || \count($messageParts) !== 2) { throw new \InvalidArgumentException('Invalid message: Missing header delimiter'); } - list($rawHeaders, $body) = $messageParts; + [$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; + [$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); @@ -123,7 +119,7 @@ public static function parseMessage($message) $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 + // Folding is deprecated, see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4 if (\preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) { throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding'); } @@ -140,12 +136,12 @@ public static function parseMessage($message) * * @param string $path Path from the start-line * @param array $headers Array of headers (each value an array). - * - * @return string */ - public static function parseRequestUri($path, array $headers) + public static function parseRequestUri(string $path, array $headers) : string { $hostKey = \array_filter(\array_keys($headers), function ($k) { + // Numeric array keys are converted to int by PHP. + $k = (string) $k; return \strtolower($k) === 'host'; }); // If no host is found, then a full URI cannot be constructed. @@ -160,10 +156,8 @@ public static function parseRequestUri($path, array $headers) * Parses a request message string into a request object. * * @param string $message Request message string. - * - * @return Request */ - public static function parseRequest($message) + public static function parseRequest(string $message) : RequestInterface { $data = self::parseMessage($message); $matches = []; @@ -179,19 +173,17 @@ public static function parseRequest($message) * Parses a response message string into a response object. * * @param string $message Response message string. - * - * @return Response */ - public static function parseResponse($message) + public static function parseResponse(string $message) : ResponseInterface { $data = self::parseMessage($message); - // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space - // between status-code and reason-phrase is required. But browsers accept - // responses without space and reason as well. + // According to https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2 + // the space 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: ' . $data['start-line']); } $parts = \explode(' ', $data['start-line'], 3); - return new Response((int) $parts[1], $data['headers'], $data['body'], \explode('/', $parts[0])[1], isset($parts[2]) ? $parts[2] : null); + return new Response((int) $parts[1], $data['headers'], $data['body'], \explode('/', $parts[0])[1], $parts[2] ?? null); } } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/MessageTrait.php b/vendor-prefixed/guzzlehttp/psr7/src/MessageTrait.php index 3c1310b..c2aaa7c 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/MessageTrait.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/MessageTrait.php @@ -1,26 +1,28 @@ array of values */ + /** @var string[][] Map of all registered headers, as original name => array of values */ private $headers = []; - /** @var array Map of lowercase header name => original name at registration */ + /** @var string[] Map of lowercase header name => original name at registration */ private $headerNames = []; /** @var string */ private $protocol = '1.1'; /** @var StreamInterface|null */ private $stream; - public function getProtocolVersion() + public function getProtocolVersion() : string { return $this->protocol; } - public function withProtocolVersion($version) + public function withProtocolVersion($version) : MessageInterface { if ($this->protocol === $version) { return $this; @@ -29,15 +31,15 @@ public function withProtocolVersion($version) $new->protocol = $version; return $new; } - public function getHeaders() + public function getHeaders() : array { return $this->headers; } - public function hasHeader($header) + public function hasHeader($header) : bool { return isset($this->headerNames[\strtolower($header)]); } - public function getHeader($header) + public function getHeader($header) : array { $header = \strtolower($header); if (!isset($this->headerNames[$header])) { @@ -46,11 +48,11 @@ public function getHeader($header) $header = $this->headerNames[$header]; return $this->headers[$header]; } - public function getHeaderLine($header) + public function getHeaderLine($header) : string { return \implode(', ', $this->getHeader($header)); } - public function withHeader($header, $value) + public function withHeader($header, $value) : MessageInterface { $this->assertHeader($header); $value = $this->normalizeHeaderValue($value); @@ -63,7 +65,7 @@ public function withHeader($header, $value) $new->headers[$header] = $value; return $new; } - public function withAddedHeader($header, $value) + public function withAddedHeader($header, $value) : MessageInterface { $this->assertHeader($header); $value = $this->normalizeHeaderValue($value); @@ -78,7 +80,7 @@ public function withAddedHeader($header, $value) } return $new; } - public function withoutHeader($header) + public function withoutHeader($header) : MessageInterface { $normalized = \strtolower($header); if (!isset($this->headerNames[$normalized])) { @@ -89,14 +91,14 @@ public function withoutHeader($header) unset($new->headers[$header], $new->headerNames[$normalized]); return $new; } - public function getBody() + public function getBody() : StreamInterface { if (!$this->stream) { $this->stream = Utils::streamFor(''); } return $this->stream; } - public function withBody(StreamInterface $body) + public function withBody(StreamInterface $body) : MessageInterface { if ($body === $this->stream) { return $this; @@ -105,15 +107,15 @@ public function withBody(StreamInterface $body) $new->stream = $body; return $new; } - private function setHeaders(array $headers) + /** + * @param (string|string[])[] $headers + */ + private function setHeaders(array $headers) : void { $this->headerNames = $this->headers = []; foreach ($headers as $header => $value) { - if (\is_int($header)) { - // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec - // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass. - $header = (string) $header; - } + // Numeric array keys are converted to int by PHP. + $header = (string) $header; $this->assertHeader($header); $value = $this->normalizeHeaderValue($value); $normalized = \strtolower($header); @@ -131,14 +133,11 @@ private function setHeaders(array $headers) * * @return string[] */ - private function normalizeHeaderValue($value) + private function normalizeHeaderValue($value) : array { if (!\is_array($value)) { return $this->trimAndValidateHeaderValues([$value]); } - if (\count($value) === 0) { - throw new \InvalidArgumentException('Header value can not be an empty array.'); - } return $this->trimAndValidateHeaderValues($value); } /** @@ -153,9 +152,9 @@ private function normalizeHeaderValue($value) * * @return string[] Trimmed header values * - * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 + * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4 */ - private function trimAndValidateHeaderValues(array $values) + private function trimAndValidateHeaderValues(array $values) : array { return \array_map(function ($value) { if (!\is_scalar($value) && null !== $value) { @@ -167,30 +166,21 @@ private function trimAndValidateHeaderValues(array $values) }, \array_values($values)); } /** - * @see https://tools.ietf.org/html/rfc7230#section-3.2 + * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 * * @param mixed $header - * - * @return void */ - private function assertHeader($header) + private function assertHeader($header) : void { if (!\is_string($header)) { throw new \InvalidArgumentException(\sprintf('Header name must be a string but %s provided.', \is_object($header) ? \get_class($header) : \gettype($header))); } - if ($header === '') { - throw new \InvalidArgumentException('Header name can not be empty.'); - } if (!\preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) { throw new \InvalidArgumentException(\sprintf('"%s" is not valid header name.', $header)); } } /** - * @param string $value - * - * @return void - * - * @see https://tools.ietf.org/html/rfc7230#section-3.2 + * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 * * field-value = *( field-content / obs-fold ) * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] @@ -199,7 +189,7 @@ private function assertHeader($header) * obs-text = %x80-FF * obs-fold = CRLF 1*( SP / HTAB ) */ - private function assertValue($value) + private function assertValue(string $value) : void { // The regular expression intentionally does not support the obs-fold production, because as // per RFC 7230#3.2.4: diff --git a/vendor-prefixed/guzzlehttp/psr7/src/MimeType.php b/vendor-prefixed/guzzlehttp/psr7/src/MimeType.php index fb13985..f68d93d 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/MimeType.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/MimeType.php @@ -1,33 +1,27 @@ 'application/vnd.1000minds.decision-model+xml', '3dml' => 'text/vnd.in3d.3dml', '3ds' => 'image/x-3ds', '3g2' => 'video/3gpp2', '3gp' => 'video/3gp', '3gpp' => 'video/3gpp', '3mf' => 'model/3mf', '7z' => 'application/x-7z-compressed', '7zip' => 'application/x-7z-compressed', '123' => 'application/vnd.lotus-1-2-3', 'aab' => 'application/x-authorware-bin', 'aac' => 'audio/aac', 'aam' => 'application/x-authorware-map', 'aas' => 'application/x-authorware-seg', 'abw' => 'application/x-abiword', 'ac' => 'application/vnd.nokia.n-gage.ac+xml', 'ac3' => 'audio/ac3', 'acc' => 'application/vnd.americandynamics.acc', 'ace' => 'application/x-ace-compressed', 'acu' => 'application/vnd.acucobol', 'acutc' => 'application/vnd.acucorp', 'adp' => 'audio/adpcm', 'adts' => 'audio/aac', 'aep' => 'application/vnd.audiograph', 'afm' => 'application/x-font-type1', 'afp' => 'application/vnd.ibm.modcap', 'age' => 'application/vnd.age', 'ahead' => 'application/vnd.ahead.space', 'ai' => 'application/pdf', 'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'air' => 'application/vnd.adobe.air-application-installer-package+zip', 'ait' => 'application/vnd.dvb.ait', 'ami' => 'application/vnd.amiga.ami', 'aml' => 'application/automationml-aml+xml', 'amlx' => 'application/automationml-amlx+zip', 'amr' => 'audio/amr', 'apk' => 'application/vnd.android.package-archive', 'apng' => 'image/apng', 'appcache' => 'text/cache-manifest', 'appinstaller' => 'application/appinstaller', 'application' => 'application/x-ms-application', 'appx' => 'application/appx', 'appxbundle' => 'application/appxbundle', 'apr' => 'application/vnd.lotus-approach', 'arc' => 'application/x-freearc', 'arj' => 'application/x-arj', 'asc' => 'application/pgp-signature', 'asf' => 'video/x-ms-asf', 'asm' => 'text/x-asm', 'aso' => 'application/vnd.accpac.simply.aso', 'asx' => 'video/x-ms-asf', 'atc' => 'application/vnd.acucorp', 'atom' => 'application/atom+xml', 'atomcat' => 'application/atomcat+xml', 'atomdeleted' => 'application/atomdeleted+xml', 'atomsvc' => 'application/atomsvc+xml', 'atx' => 'application/vnd.antix.game-component', 'au' => 'audio/x-au', 'avci' => 'image/avci', 'avcs' => 'image/avcs', 'avi' => 'video/x-msvideo', 'avif' => 'image/avif', 'aw' => 'application/applixware', 'azf' => 'application/vnd.airzip.filesecure.azf', 'azs' => 'application/vnd.airzip.filesecure.azs', 'azv' => 'image/vnd.airzip.accelerator.azv', 'azw' => 'application/vnd.amazon.ebook', 'b16' => 'image/vnd.pco.b16', 'bat' => 'application/x-msdownload', 'bcpio' => 'application/x-bcpio', 'bdf' => 'application/x-font-bdf', 'bdm' => 'application/vnd.syncml.dm+wbxml', 'bdoc' => 'application/x-bdoc', 'bed' => 'application/vnd.realvnc.bed', 'bh2' => 'application/vnd.fujitsu.oasysprs', 'bin' => 'application/octet-stream', 'blb' => 'application/x-blorb', 'blorb' => 'application/x-blorb', 'bmi' => 'application/vnd.bmi', 'bmml' => 'application/vnd.balsamiq.bmml+xml', 'bmp' => 'image/bmp', 'book' => 'application/vnd.framemaker', 'box' => 'application/vnd.previewsystems.box', 'boz' => 'application/x-bzip2', 'bpk' => 'application/octet-stream', 'bpmn' => 'application/octet-stream', 'bsp' => 'model/vnd.valve.source.compiled-map', 'btf' => 'image/prs.btif', 'btif' => 'image/prs.btif', 'buffer' => 'application/octet-stream', 'bz' => 'application/x-bzip', 'bz2' => 'application/x-bzip2', 'c' => 'text/x-c', 'c4d' => 'application/vnd.clonk.c4group', 'c4f' => 'application/vnd.clonk.c4group', 'c4g' => 'application/vnd.clonk.c4group', 'c4p' => 'application/vnd.clonk.c4group', 'c4u' => 'application/vnd.clonk.c4group', 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', 'cab' => 'application/vnd.ms-cab-compressed', 'caf' => 'audio/x-caf', 'cap' => 'application/vnd.tcpdump.pcap', 'car' => 'application/vnd.curl.car', 'cat' => 'application/vnd.ms-pki.seccat', 'cb7' => 'application/x-cbr', 'cba' => 'application/x-cbr', 'cbr' => 'application/x-cbr', 'cbt' => 'application/x-cbr', 'cbz' => 'application/x-cbr', 'cc' => 'text/x-c', 'cco' => 'application/x-cocoa', 'cct' => 'application/x-director', 'ccxml' => 'application/ccxml+xml', 'cdbcmsg' => 'application/vnd.contact.cmsg', 'cdf' => 'application/x-netcdf', 'cdfx' => 'application/cdfx+xml', 'cdkey' => 'application/vnd.mediastation.cdkey', 'cdmia' => 'application/cdmi-capability', 'cdmic' => 'application/cdmi-container', 'cdmid' => 'application/cdmi-domain', 'cdmio' => 'application/cdmi-object', 'cdmiq' => 'application/cdmi-queue', 'cdr' => 'application/cdr', 'cdx' => 'chemical/x-cdx', 'cdxml' => 'application/vnd.chemdraw+xml', 'cdy' => 'application/vnd.cinderella', 'cer' => 'application/pkix-cert', 'cfs' => 'application/x-cfs-compressed', 'cgm' => 'image/cgm', 'chat' => 'application/x-chat', 'chm' => 'application/vnd.ms-htmlhelp', 'chrt' => 'application/vnd.kde.kchart', 'cif' => 'chemical/x-cif', 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', 'cil' => 'application/vnd.ms-artgalry', 'cjs' => 'application/node', 'cla' => 'application/vnd.claymore', 'class' => 'application/octet-stream', 'cld' => 'model/vnd.cld', 'clkk' => 'application/vnd.crick.clicker.keyboard', 'clkp' => 'application/vnd.crick.clicker.palette', 'clkt' => 'application/vnd.crick.clicker.template', 'clkw' => 'application/vnd.crick.clicker.wordbank', 'clkx' => 'application/vnd.crick.clicker', 'clp' => 'application/x-msclip', 'cmc' => 'application/vnd.cosmocaller', 'cmdf' => 'chemical/x-cmdf', 'cml' => 'chemical/x-cml', 'cmp' => 'application/vnd.yellowriver-custom-menu', 'cmx' => 'image/x-cmx', 'cod' => 'application/vnd.rim.cod', 'coffee' => 'text/coffeescript', 'com' => 'application/x-msdownload', 'conf' => 'text/plain', 'cpio' => 'application/x-cpio', 'cpl' => 'application/cpl+xml', 'cpp' => 'text/x-c', 'cpt' => 'application/mac-compactpro', 'crd' => 'application/x-mscardfile', 'crl' => 'application/pkix-crl', 'crt' => 'application/x-x509-ca-cert', 'crx' => 'application/x-chrome-extension', 'cryptonote' => 'application/vnd.rig.cryptonote', 'csh' => 'application/x-csh', 'csl' => 'application/vnd.citationstyles.style+xml', 'csml' => 'chemical/x-csml', 'csp' => 'application/vnd.commonspace', 'csr' => 'application/octet-stream', 'css' => 'text/css', 'cst' => 'application/x-director', 'csv' => 'text/csv', 'cu' => 'application/cu-seeme', 'curl' => 'text/vnd.curl', 'cwl' => 'application/cwl', 'cww' => 'application/prs.cww', 'cxt' => 'application/x-director', 'cxx' => 'text/x-c', 'dae' => 'model/vnd.collada+xml', 'daf' => 'application/vnd.mobius.daf', 'dart' => 'application/vnd.dart', 'dataless' => 'application/vnd.fdsn.seed', 'davmount' => 'application/davmount+xml', 'dbf' => 'application/vnd.dbf', 'dbk' => 'application/docbook+xml', 'dcr' => 'application/x-director', 'dcurl' => 'text/vnd.curl.dcurl', 'dd2' => 'application/vnd.oma.dd2+xml', 'ddd' => 'application/vnd.fujixerox.ddd', 'ddf' => 'application/vnd.syncml.dmddf+xml', 'dds' => 'image/vnd.ms-dds', 'deb' => 'application/x-debian-package', 'def' => 'text/plain', 'deploy' => 'application/octet-stream', 'der' => 'application/x-x509-ca-cert', 'dfac' => 'application/vnd.dreamfactory', 'dgc' => 'application/x-dgc-compressed', 'dib' => 'image/bmp', 'dic' => 'text/x-c', 'dir' => 'application/x-director', 'dis' => 'application/vnd.mobius.dis', 'disposition-notification' => 'message/disposition-notification', 'dist' => 'application/octet-stream', 'distz' => 'application/octet-stream', 'djv' => 'image/vnd.djvu', 'djvu' => 'image/vnd.djvu', 'dll' => 'application/octet-stream', 'dmg' => 'application/x-apple-diskimage', 'dmn' => 'application/octet-stream', 'dmp' => 'application/vnd.tcpdump.pcap', 'dms' => 'application/octet-stream', 'dna' => 'application/vnd.dna', 'doc' => 'application/msword', 'docm' => 'application/vnd.ms-word.template.macroEnabled.12', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'dot' => 'application/msword', 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12', 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'dp' => 'application/vnd.osgi.dp', 'dpg' => 'application/vnd.dpgraph', 'dpx' => 'image/dpx', 'dra' => 'audio/vnd.dra', 'drle' => 'image/dicom-rle', 'dsc' => 'text/prs.lines.tag', 'dssc' => 'application/dssc+der', 'dtb' => 'application/x-dtbook+xml', 'dtd' => 'application/xml-dtd', 'dts' => 'audio/vnd.dts', 'dtshd' => 'audio/vnd.dts.hd', 'dump' => 'application/octet-stream', 'dvb' => 'video/vnd.dvb.file', 'dvi' => 'application/x-dvi', 'dwd' => 'application/atsc-dwd+xml', 'dwf' => 'model/vnd.dwf', 'dwg' => 'image/vnd.dwg', 'dxf' => 'image/vnd.dxf', 'dxp' => 'application/vnd.spotfire.dxp', 'dxr' => 'application/x-director', 'ear' => 'application/java-archive', 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', 'ecma' => 'application/ecmascript', 'edm' => 'application/vnd.novadigm.edm', 'edx' => 'application/vnd.novadigm.edx', 'efif' => 'application/vnd.picsel', 'ei6' => 'application/vnd.pg.osasli', 'elc' => 'application/octet-stream', 'emf' => 'image/emf', 'eml' => 'message/rfc822', 'emma' => 'application/emma+xml', 'emotionml' => 'application/emotionml+xml', 'emz' => 'application/x-msmetafile', 'eol' => 'audio/vnd.digital-winds', 'eot' => 'application/vnd.ms-fontobject', 'eps' => 'application/postscript', 'epub' => 'application/epub+zip', 'es3' => 'application/vnd.eszigno3+xml', 'esa' => 'application/vnd.osgi.subsystem', 'esf' => 'application/vnd.epson.esf', 'et3' => 'application/vnd.eszigno3+xml', 'etx' => 'text/x-setext', 'eva' => 'application/x-eva', 'evy' => 'application/x-envoy', 'exe' => 'application/octet-stream', 'exi' => 'application/exi', 'exp' => 'application/express', 'exr' => 'image/aces', 'ext' => 'application/vnd.novadigm.ext', 'ez' => 'application/andrew-inset', 'ez2' => 'application/vnd.ezpix-album', 'ez3' => 'application/vnd.ezpix-package', 'f' => 'text/x-fortran', 'f4v' => 'video/mp4', 'f77' => 'text/x-fortran', 'f90' => 'text/x-fortran', 'fbs' => 'image/vnd.fastbidsheet', 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', 'fcs' => 'application/vnd.isac.fcs', 'fdf' => 'application/vnd.fdf', 'fdt' => 'application/fdt+xml', 'fe_launch' => 'application/vnd.denovo.fcselayout-link', 'fg5' => 'application/vnd.fujitsu.oasysgp', 'fgd' => 'application/x-director', 'fh' => 'image/x-freehand', 'fh4' => 'image/x-freehand', 'fh5' => 'image/x-freehand', 'fh7' => 'image/x-freehand', 'fhc' => 'image/x-freehand', 'fig' => 'application/x-xfig', 'fits' => 'image/fits', 'flac' => 'audio/x-flac', 'fli' => 'video/x-fli', 'flo' => 'application/vnd.micrografx.flo', 'flv' => 'video/x-flv', 'flw' => 'application/vnd.kde.kivio', 'flx' => 'text/vnd.fmi.flexstor', 'fly' => 'text/vnd.fly', 'fm' => 'application/vnd.framemaker', 'fnc' => 'application/vnd.frogans.fnc', 'fo' => 'application/vnd.software602.filler.form+xml', 'for' => 'text/x-fortran', 'fpx' => 'image/vnd.fpx', 'frame' => 'application/vnd.framemaker', 'fsc' => 'application/vnd.fsc.weblaunch', 'fst' => 'image/vnd.fst', 'ftc' => 'application/vnd.fluxtime.clip', 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', 'fvt' => 'video/vnd.fvt', 'fxp' => 'application/vnd.adobe.fxp', 'fxpl' => 'application/vnd.adobe.fxp', 'fzs' => 'application/vnd.fuzzysheet', 'g2w' => 'application/vnd.geoplan', 'g3' => 'image/g3fax', 'g3w' => 'application/vnd.geospace', 'gac' => 'application/vnd.groove-account', 'gam' => 'application/x-tads', 'gbr' => 'application/rpki-ghostbusters', 'gca' => 'application/x-gca-compressed', 'gdl' => 'model/vnd.gdl', 'gdoc' => 'application/vnd.google-apps.document', 'ged' => 'text/vnd.familysearch.gedcom', 'geo' => 'application/vnd.dynageo', 'geojson' => 'application/geo+json', 'gex' => 'application/vnd.geometry-explorer', 'ggb' => 'application/vnd.geogebra.file', 'ggt' => 'application/vnd.geogebra.tool', 'ghf' => 'application/vnd.groove-help', 'gif' => 'image/gif', 'gim' => 'application/vnd.groove-identity-message', 'glb' => 'model/gltf-binary', 'gltf' => 'model/gltf+json', 'gml' => 'application/gml+xml', 'gmx' => 'application/vnd.gmx', 'gnumeric' => 'application/x-gnumeric', 'gpg' => 'application/gpg-keys', 'gph' => 'application/vnd.flographit', 'gpx' => 'application/gpx+xml', 'gqf' => 'application/vnd.grafeq', 'gqs' => 'application/vnd.grafeq', 'gram' => 'application/srgs', 'gramps' => 'application/x-gramps-xml', 'gre' => 'application/vnd.geometry-explorer', 'grv' => 'application/vnd.groove-injector', 'grxml' => 'application/srgs+xml', 'gsf' => 'application/x-font-ghostscript', 'gsheet' => 'application/vnd.google-apps.spreadsheet', 'gslides' => 'application/vnd.google-apps.presentation', 'gtar' => 'application/x-gtar', 'gtm' => 'application/vnd.groove-tool-message', 'gtw' => 'model/vnd.gtw', 'gv' => 'text/vnd.graphviz', 'gxf' => 'application/gxf', 'gxt' => 'application/vnd.geonext', 'gz' => 'application/gzip', 'gzip' => 'application/gzip', 'h' => 'text/x-c', 'h261' => 'video/h261', 'h263' => 'video/h263', 'h264' => 'video/h264', 'hal' => 'application/vnd.hal+xml', 'hbci' => 'application/vnd.hbci', 'hbs' => 'text/x-handlebars-template', 'hdd' => 'application/x-virtualbox-hdd', 'hdf' => 'application/x-hdf', 'heic' => 'image/heic', 'heics' => 'image/heic-sequence', 'heif' => 'image/heif', 'heifs' => 'image/heif-sequence', 'hej2' => 'image/hej2k', 'held' => 'application/atsc-held+xml', 'hh' => 'text/x-c', 'hjson' => 'application/hjson', 'hlp' => 'application/winhlp', 'hpgl' => 'application/vnd.hp-hpgl', 'hpid' => 'application/vnd.hp-hpid', 'hps' => 'application/vnd.hp-hps', 'hqx' => 'application/mac-binhex40', 'hsj2' => 'image/hsj2', 'htc' => 'text/x-component', 'htke' => 'application/vnd.kenameaapp', 'htm' => 'text/html', 'html' => 'text/html', 'hvd' => 'application/vnd.yamaha.hv-dic', 'hvp' => 'application/vnd.yamaha.hv-voice', 'hvs' => 'application/vnd.yamaha.hv-script', 'i2g' => 'application/vnd.intergeo', 'icc' => 'application/vnd.iccprofile', 'ice' => 'x-conference/x-cooltalk', 'icm' => 'application/vnd.iccprofile', 'ico' => 'image/x-icon', 'ics' => 'text/calendar', 'ief' => 'image/ief', 'ifb' => 'text/calendar', 'ifm' => 'application/vnd.shana.informed.formdata', 'iges' => 'model/iges', 'igl' => 'application/vnd.igloader', 'igm' => 'application/vnd.insors.igm', 'igs' => 'model/iges', 'igx' => 'application/vnd.micrografx.igx', 'iif' => 'application/vnd.shana.informed.interchange', 'img' => 'application/octet-stream', 'imp' => 'application/vnd.accpac.simply.imp', 'ims' => 'application/vnd.ms-ims', 'in' => 'text/plain', 'ini' => 'text/plain', 'ink' => 'application/inkml+xml', 'inkml' => 'application/inkml+xml', 'install' => 'application/x-install-instructions', 'iota' => 'application/vnd.astraea-software.iota', 'ipfix' => 'application/ipfix', 'ipk' => 'application/vnd.shana.informed.package', 'irm' => 'application/vnd.ibm.rights-management', 'irp' => 'application/vnd.irepository.package+xml', 'iso' => 'application/x-iso9660-image', 'itp' => 'application/vnd.shana.informed.formtemplate', 'its' => 'application/its+xml', 'ivp' => 'application/vnd.immervision-ivp', 'ivu' => 'application/vnd.immervision-ivu', 'jad' => 'text/vnd.sun.j2me.app-descriptor', 'jade' => 'text/jade', 'jam' => 'application/vnd.jam', 'jar' => 'application/java-archive', 'jardiff' => 'application/x-java-archive-diff', 'java' => 'text/x-java-source', 'jhc' => 'image/jphc', 'jisp' => 'application/vnd.jisp', 'jls' => 'image/jls', 'jlt' => 'application/vnd.hp-jlyt', 'jng' => 'image/x-jng', 'jnlp' => 'application/x-java-jnlp-file', 'joda' => 'application/vnd.joost.joda-archive', 'jp2' => 'image/jp2', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpf' => 'image/jpx', 'jpg' => 'image/jpeg', 'jpg2' => 'image/jp2', 'jpgm' => 'video/jpm', 'jpgv' => 'video/jpeg', 'jph' => 'image/jph', 'jpm' => 'video/jpm', 'jpx' => 'image/jpx', 'js' => 'application/javascript', 'json' => 'application/json', 'json5' => 'application/json5', 'jsonld' => 'application/ld+json', 'jsonml' => 'application/jsonml+json', 'jsx' => 'text/jsx', 'jt' => 'model/jt', 'jxr' => 'image/jxr', 'jxra' => 'image/jxra', 'jxrs' => 'image/jxrs', 'jxs' => 'image/jxs', 'jxsc' => 'image/jxsc', 'jxsi' => 'image/jxsi', 'jxss' => 'image/jxss', 'kar' => 'audio/midi', 'karbon' => 'application/vnd.kde.karbon', 'kdb' => 'application/octet-stream', 'kdbx' => 'application/x-keepass2', 'key' => 'application/x-iwork-keynote-sffkey', 'kfo' => 'application/vnd.kde.kformula', 'kia' => 'application/vnd.kidspiration', 'kml' => 'application/vnd.google-earth.kml+xml', 'kmz' => 'application/vnd.google-earth.kmz', 'kne' => 'application/vnd.kinar', 'knp' => 'application/vnd.kinar', 'kon' => 'application/vnd.kde.kontour', 'kpr' => 'application/vnd.kde.kpresenter', 'kpt' => 'application/vnd.kde.kpresenter', 'kpxx' => 'application/vnd.ds-keypoint', 'ksp' => 'application/vnd.kde.kspread', 'ktr' => 'application/vnd.kahootz', 'ktx' => 'image/ktx', 'ktx2' => 'image/ktx2', 'ktz' => 'application/vnd.kahootz', 'kwd' => 'application/vnd.kde.kword', 'kwt' => 'application/vnd.kde.kword', 'lasxml' => 'application/vnd.las.las+xml', 'latex' => 'application/x-latex', 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', 'les' => 'application/vnd.hhe.lesson-player', 'less' => 'text/less', 'lgr' => 'application/lgr+xml', 'lha' => 'application/octet-stream', 'link66' => 'application/vnd.route66.link66+xml', 'list' => 'text/plain', 'list3820' => 'application/vnd.ibm.modcap', 'listafp' => 'application/vnd.ibm.modcap', 'litcoffee' => 'text/coffeescript', 'lnk' => 'application/x-ms-shortcut', 'log' => 'text/plain', 'lostxml' => 'application/lost+xml', 'lrf' => 'application/octet-stream', 'lrm' => 'application/vnd.ms-lrm', 'ltf' => 'application/vnd.frogans.ltf', 'lua' => 'text/x-lua', 'luac' => 'application/x-lua-bytecode', 'lvp' => 'audio/vnd.lucent.voice', 'lwp' => 'application/vnd.lotus-wordpro', 'lzh' => 'application/octet-stream', 'm1v' => 'video/mpeg', 'm2a' => 'audio/mpeg', 'm2v' => 'video/mpeg', 'm3a' => 'audio/mpeg', 'm3u' => 'text/plain', 'm3u8' => 'application/vnd.apple.mpegurl', 'm4a' => 'audio/x-m4a', 'm4p' => 'application/mp4', 'm4s' => 'video/iso.segment', 'm4u' => 'application/vnd.mpegurl', 'm4v' => 'video/x-m4v', 'm13' => 'application/x-msmediaview', 'm14' => 'application/x-msmediaview', 'm21' => 'application/mp21', 'ma' => 'application/mathematica', 'mads' => 'application/mads+xml', 'maei' => 'application/mmt-aei+xml', 'mag' => 'application/vnd.ecowin.chart', 'maker' => 'application/vnd.framemaker', 'man' => 'text/troff', 'manifest' => 'text/cache-manifest', 'map' => 'application/json', 'mar' => 'application/octet-stream', 'markdown' => 'text/markdown', 'mathml' => 'application/mathml+xml', 'mb' => 'application/mathematica', 'mbk' => 'application/vnd.mobius.mbk', 'mbox' => 'application/mbox', 'mc1' => 'application/vnd.medcalcdata', 'mcd' => 'application/vnd.mcd', 'mcurl' => 'text/vnd.curl.mcurl', 'md' => 'text/markdown', 'mdb' => 'application/x-msaccess', 'mdi' => 'image/vnd.ms-modi', 'mdx' => 'text/mdx', 'me' => 'text/troff', 'mesh' => 'model/mesh', 'meta4' => 'application/metalink4+xml', 'metalink' => 'application/metalink+xml', 'mets' => 'application/mets+xml', 'mfm' => 'application/vnd.mfmp', 'mft' => 'application/rpki-manifest', 'mgp' => 'application/vnd.osgeo.mapguide.package', 'mgz' => 'application/vnd.proteus.magazine', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'mie' => 'application/x-mie', 'mif' => 'application/vnd.mif', 'mime' => 'message/rfc822', 'mj2' => 'video/mj2', 'mjp2' => 'video/mj2', 'mjs' => 'text/javascript', 'mk3d' => 'video/x-matroska', 'mka' => 'audio/x-matroska', 'mkd' => 'text/x-markdown', 'mks' => 'video/x-matroska', 'mkv' => 'video/x-matroska', 'mlp' => 'application/vnd.dolby.mlp', 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', 'mmf' => 'application/vnd.smaf', 'mml' => 'text/mathml', 'mmr' => 'image/vnd.fujixerox.edmics-mmr', 'mng' => 'video/x-mng', 'mny' => 'application/x-msmoney', 'mobi' => 'application/x-mobipocket-ebook', 'mods' => 'application/mods+xml', 'mov' => 'video/quicktime', 'movie' => 'video/x-sgi-movie', 'mp2' => 'audio/mpeg', 'mp2a' => 'audio/mpeg', 'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4', 'mp4a' => 'audio/mp4', 'mp4s' => 'application/mp4', 'mp4v' => 'video/mp4', 'mp21' => 'application/mp21', 'mpc' => 'application/vnd.mophun.certificate', 'mpd' => 'application/dash+xml', 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', 'mpf' => 'application/media-policy-dataset+xml', 'mpg' => 'video/mpeg', 'mpg4' => 'video/mp4', 'mpga' => 'audio/mpeg', 'mpkg' => 'application/vnd.apple.installer+xml', 'mpm' => 'application/vnd.blueice.multipass', 'mpn' => 'application/vnd.mophun.application', 'mpp' => 'application/vnd.ms-project', 'mpt' => 'application/vnd.ms-project', 'mpy' => 'application/vnd.ibm.minipay', 'mqy' => 'application/vnd.mobius.mqy', 'mrc' => 'application/marc', 'mrcx' => 'application/marcxml+xml', 'ms' => 'text/troff', 'mscml' => 'application/mediaservercontrol+xml', 'mseed' => 'application/vnd.fdsn.mseed', 'mseq' => 'application/vnd.mseq', 'msf' => 'application/vnd.epson.msf', 'msg' => 'application/vnd.ms-outlook', 'msh' => 'model/mesh', 'msi' => 'application/x-msdownload', 'msix' => 'application/msix', 'msixbundle' => 'application/msixbundle', 'msl' => 'application/vnd.mobius.msl', 'msm' => 'application/octet-stream', 'msp' => 'application/octet-stream', 'msty' => 'application/vnd.muvee.style', 'mtl' => 'model/mtl', 'mts' => 'model/vnd.mts', 'mus' => 'application/vnd.musician', 'musd' => 'application/mmt-usd+xml', 'musicxml' => 'application/vnd.recordare.musicxml+xml', 'mvb' => 'application/x-msmediaview', 'mvt' => 'application/vnd.mapbox-vector-tile', 'mwf' => 'application/vnd.mfer', 'mxf' => 'application/mxf', 'mxl' => 'application/vnd.recordare.musicxml', 'mxmf' => 'audio/mobile-xmf', 'mxml' => 'application/xv+xml', 'mxs' => 'application/vnd.triscape.mxs', 'mxu' => 'video/vnd.mpegurl', 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', 'n3' => 'text/n3', 'nb' => 'application/mathematica', 'nbp' => 'application/vnd.wolfram.player', 'nc' => 'application/x-netcdf', 'ncx' => 'application/x-dtbncx+xml', 'nfo' => 'text/x-nfo', 'ngdat' => 'application/vnd.nokia.n-gage.data', 'nitf' => 'application/vnd.nitf', 'nlu' => 'application/vnd.neurolanguage.nlu', 'nml' => 'application/vnd.enliven', 'nnd' => 'application/vnd.noblenet-directory', 'nns' => 'application/vnd.noblenet-sealer', 'nnw' => 'application/vnd.noblenet-web', 'npx' => 'image/vnd.net-fpx', 'nq' => 'application/n-quads', 'nsc' => 'application/x-conference', 'nsf' => 'application/vnd.lotus-notes', 'nt' => 'application/n-triples', 'ntf' => 'application/vnd.nitf', 'numbers' => 'application/x-iwork-numbers-sffnumbers', 'nzb' => 'application/x-nzb', 'oa2' => 'application/vnd.fujitsu.oasys2', 'oa3' => 'application/vnd.fujitsu.oasys3', 'oas' => 'application/vnd.fujitsu.oasys', 'obd' => 'application/x-msbinder', 'obgx' => 'application/vnd.openblox.game+xml', 'obj' => 'model/obj', 'oda' => 'application/oda', 'odb' => 'application/vnd.oasis.opendocument.database', 'odc' => 'application/vnd.oasis.opendocument.chart', 'odf' => 'application/vnd.oasis.opendocument.formula', 'odft' => 'application/vnd.oasis.opendocument.formula-template', 'odg' => 'application/vnd.oasis.opendocument.graphics', 'odi' => 'application/vnd.oasis.opendocument.image', 'odm' => 'application/vnd.oasis.opendocument.text-master', 'odp' => 'application/vnd.oasis.opendocument.presentation', 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 'odt' => 'application/vnd.oasis.opendocument.text', 'oga' => 'audio/ogg', 'ogex' => 'model/vnd.opengex', 'ogg' => 'audio/ogg', 'ogv' => 'video/ogg', 'ogx' => 'application/ogg', 'omdoc' => 'application/omdoc+xml', 'onepkg' => 'application/onenote', 'onetmp' => 'application/onenote', 'onetoc' => 'application/onenote', 'onetoc2' => 'application/onenote', 'opf' => 'application/oebps-package+xml', 'opml' => 'text/x-opml', 'oprc' => 'application/vnd.palm', 'opus' => 'audio/ogg', 'org' => 'text/x-org', 'osf' => 'application/vnd.yamaha.openscoreformat', 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', 'osm' => 'application/vnd.openstreetmap.data+xml', 'otc' => 'application/vnd.oasis.opendocument.chart-template', 'otf' => 'font/otf', 'otg' => 'application/vnd.oasis.opendocument.graphics-template', 'oth' => 'application/vnd.oasis.opendocument.text-web', 'oti' => 'application/vnd.oasis.opendocument.image-template', 'otp' => 'application/vnd.oasis.opendocument.presentation-template', 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', 'ott' => 'application/vnd.oasis.opendocument.text-template', 'ova' => 'application/x-virtualbox-ova', 'ovf' => 'application/x-virtualbox-ovf', 'owl' => 'application/rdf+xml', 'oxps' => 'application/oxps', 'oxt' => 'application/vnd.openofficeorg.extension', 'p' => 'text/x-pascal', 'p7a' => 'application/x-pkcs7-signature', 'p7b' => 'application/x-pkcs7-certificates', 'p7c' => 'application/pkcs7-mime', 'p7m' => 'application/pkcs7-mime', 'p7r' => 'application/x-pkcs7-certreqresp', 'p7s' => 'application/pkcs7-signature', 'p8' => 'application/pkcs8', 'p10' => 'application/x-pkcs10', 'p12' => 'application/x-pkcs12', 'pac' => 'application/x-ns-proxy-autoconfig', 'pages' => 'application/x-iwork-pages-sffpages', 'pas' => 'text/x-pascal', 'paw' => 'application/vnd.pawaafile', 'pbd' => 'application/vnd.powerbuilder6', 'pbm' => 'image/x-portable-bitmap', 'pcap' => 'application/vnd.tcpdump.pcap', 'pcf' => 'application/x-font-pcf', 'pcl' => 'application/vnd.hp-pcl', 'pclxl' => 'application/vnd.hp-pclxl', 'pct' => 'image/x-pict', 'pcurl' => 'application/vnd.curl.pcurl', 'pcx' => 'image/x-pcx', 'pdb' => 'application/x-pilot', 'pde' => 'text/x-processing', 'pdf' => 'application/pdf', 'pem' => 'application/x-x509-user-cert', 'pfa' => 'application/x-font-type1', 'pfb' => 'application/x-font-type1', 'pfm' => 'application/x-font-type1', 'pfr' => 'application/font-tdpfr', 'pfx' => 'application/x-pkcs12', 'pgm' => 'image/x-portable-graymap', 'pgn' => 'application/x-chess-pgn', 'pgp' => 'application/pgp', 'phar' => 'application/octet-stream', 'php' => 'application/x-httpd-php', 'php3' => 'application/x-httpd-php', 'php4' => 'application/x-httpd-php', 'phps' => 'application/x-httpd-php-source', 'phtml' => 'application/x-httpd-php', 'pic' => 'image/x-pict', 'pkg' => 'application/octet-stream', 'pki' => 'application/pkixcmp', 'pkipath' => 'application/pkix-pkipath', 'pkpass' => 'application/vnd.apple.pkpass', 'pl' => 'application/x-perl', 'plb' => 'application/vnd.3gpp.pic-bw-large', 'plc' => 'application/vnd.mobius.plc', 'plf' => 'application/vnd.pocketlearn', 'pls' => 'application/pls+xml', 'pm' => 'application/x-perl', 'pml' => 'application/vnd.ctc-posml', 'png' => 'image/png', 'pnm' => 'image/x-portable-anymap', 'portpkg' => 'application/vnd.macports.portpkg', 'pot' => 'application/vnd.ms-powerpoint', 'potm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', 'ppa' => 'application/vnd.ms-powerpoint', 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', 'ppd' => 'application/vnd.cups-ppd', 'ppm' => 'image/x-portable-pixmap', 'pps' => 'application/vnd.ms-powerpoint', 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', 'ppt' => 'application/powerpoint', 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pqa' => 'application/vnd.palm', 'prc' => 'model/prc', 'pre' => 'application/vnd.lotus-freelance', 'prf' => 'application/pics-rules', 'provx' => 'application/provenance+xml', 'ps' => 'application/postscript', 'psb' => 'application/vnd.3gpp.pic-bw-small', 'psd' => 'application/x-photoshop', 'psf' => 'application/x-font-linux-psf', 'pskcxml' => 'application/pskc+xml', 'pti' => 'image/prs.pti', 'ptid' => 'application/vnd.pvi.ptid1', 'pub' => 'application/x-mspublisher', 'pvb' => 'application/vnd.3gpp.pic-bw-var', 'pwn' => 'application/vnd.3m.post-it-notes', 'pya' => 'audio/vnd.ms-playready.media.pya', 'pyo' => 'model/vnd.pytha.pyox', 'pyox' => 'model/vnd.pytha.pyox', 'pyv' => 'video/vnd.ms-playready.media.pyv', 'qam' => 'application/vnd.epson.quickanime', 'qbo' => 'application/vnd.intu.qbo', 'qfx' => 'application/vnd.intu.qfx', 'qps' => 'application/vnd.publishare-delta-tree', 'qt' => 'video/quicktime', 'qwd' => 'application/vnd.quark.quarkxpress', 'qwt' => 'application/vnd.quark.quarkxpress', 'qxb' => 'application/vnd.quark.quarkxpress', 'qxd' => 'application/vnd.quark.quarkxpress', 'qxl' => 'application/vnd.quark.quarkxpress', 'qxt' => 'application/vnd.quark.quarkxpress', 'ra' => 'audio/x-realaudio', 'ram' => 'audio/x-pn-realaudio', 'raml' => 'application/raml+yaml', 'rapd' => 'application/route-apd+xml', 'rar' => 'application/x-rar', 'ras' => 'image/x-cmu-raster', 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', 'rdf' => 'application/rdf+xml', 'rdz' => 'application/vnd.data-vision.rdz', 'relo' => 'application/p2p-overlay+xml', 'rep' => 'application/vnd.businessobjects', 'res' => 'application/x-dtbresource+xml', 'rgb' => 'image/x-rgb', 'rif' => 'application/reginfo+xml', 'rip' => 'audio/vnd.rip', 'ris' => 'application/x-research-info-systems', 'rl' => 'application/resource-lists+xml', 'rlc' => 'image/vnd.fujixerox.edmics-rlc', 'rld' => 'application/resource-lists-diff+xml', 'rm' => 'audio/x-pn-realaudio', 'rmi' => 'audio/midi', 'rmp' => 'audio/x-pn-realaudio-plugin', 'rms' => 'application/vnd.jcp.javame.midlet-rms', 'rmvb' => 'application/vnd.rn-realmedia-vbr', 'rnc' => 'application/relax-ng-compact-syntax', 'rng' => 'application/xml', 'roa' => 'application/rpki-roa', 'roff' => 'text/troff', 'rp9' => 'application/vnd.cloanto.rp9', 'rpm' => 'audio/x-pn-realaudio-plugin', 'rpss' => 'application/vnd.nokia.radio-presets', 'rpst' => 'application/vnd.nokia.radio-preset', 'rq' => 'application/sparql-query', 'rs' => 'application/rls-services+xml', 'rsa' => 'application/x-pkcs7', 'rsat' => 'application/atsc-rsat+xml', 'rsd' => 'application/rsd+xml', 'rsheet' => 'application/urc-ressheet+xml', 'rss' => 'application/rss+xml', 'rtf' => 'text/rtf', 'rtx' => 'text/richtext', 'run' => 'application/x-makeself', 'rusd' => 'application/route-usd+xml', 'rv' => 'video/vnd.rn-realvideo', 's' => 'text/x-asm', 's3m' => 'audio/s3m', 'saf' => 'application/vnd.yamaha.smaf-audio', 'sass' => 'text/x-sass', 'sbml' => 'application/sbml+xml', 'sc' => 'application/vnd.ibm.secure-container', 'scd' => 'application/x-msschedule', 'scm' => 'application/vnd.lotus-screencam', 'scq' => 'application/scvp-cv-request', 'scs' => 'application/scvp-cv-response', 'scss' => 'text/x-scss', 'scurl' => 'text/vnd.curl.scurl', 'sda' => 'application/vnd.stardivision.draw', 'sdc' => 'application/vnd.stardivision.calc', 'sdd' => 'application/vnd.stardivision.impress', 'sdkd' => 'application/vnd.solent.sdkm+xml', 'sdkm' => 'application/vnd.solent.sdkm+xml', 'sdp' => 'application/sdp', 'sdw' => 'application/vnd.stardivision.writer', 'sea' => 'application/octet-stream', 'see' => 'application/vnd.seemail', 'seed' => 'application/vnd.fdsn.seed', 'sema' => 'application/vnd.sema', 'semd' => 'application/vnd.semd', 'semf' => 'application/vnd.semf', 'senmlx' => 'application/senml+xml', 'sensmlx' => 'application/sensml+xml', 'ser' => 'application/java-serialized-object', 'setpay' => 'application/set-payment-initiation', 'setreg' => 'application/set-registration-initiation', 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', 'sfs' => 'application/vnd.spotfire.sfs', 'sfv' => 'text/x-sfv', 'sgi' => 'image/sgi', 'sgl' => 'application/vnd.stardivision.writer-global', 'sgm' => 'text/sgml', 'sgml' => 'text/sgml', 'sh' => 'application/x-sh', 'shar' => 'application/x-shar', 'shex' => 'text/shex', 'shf' => 'application/shf+xml', 'shtml' => 'text/html', 'sid' => 'image/x-mrsid-image', 'sieve' => 'application/sieve', 'sig' => 'application/pgp-signature', 'sil' => 'audio/silk', 'silo' => 'model/mesh', 'sis' => 'application/vnd.symbian.install', 'sisx' => 'application/vnd.symbian.install', 'sit' => 'application/x-stuffit', 'sitx' => 'application/x-stuffitx', 'siv' => 'application/sieve', 'skd' => 'application/vnd.koan', 'skm' => 'application/vnd.koan', 'skp' => 'application/vnd.koan', 'skt' => 'application/vnd.koan', 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', 'slim' => 'text/slim', 'slm' => 'text/slim', 'sls' => 'application/route-s-tsid+xml', 'slt' => 'application/vnd.epson.salt', 'sm' => 'application/vnd.stepmania.stepchart', 'smf' => 'application/vnd.stardivision.math', 'smi' => 'application/smil', 'smil' => 'application/smil', 'smv' => 'video/x-smv', 'smzip' => 'application/vnd.stepmania.package', 'snd' => 'audio/basic', 'snf' => 'application/x-font-snf', 'so' => 'application/octet-stream', 'spc' => 'application/x-pkcs7-certificates', 'spdx' => 'text/spdx', 'spf' => 'application/vnd.yamaha.smaf-phrase', 'spl' => 'application/x-futuresplash', 'spot' => 'text/vnd.in3d.spot', 'spp' => 'application/scvp-vp-response', 'spq' => 'application/scvp-vp-request', 'spx' => 'audio/ogg', 'sql' => 'application/x-sql', 'src' => 'application/x-wais-source', 'srt' => 'application/x-subrip', 'sru' => 'application/sru+xml', 'srx' => 'application/sparql-results+xml', 'ssdl' => 'application/ssdl+xml', 'sse' => 'application/vnd.kodak-descriptor', 'ssf' => 'application/vnd.epson.ssf', 'ssml' => 'application/ssml+xml', 'sst' => 'application/octet-stream', 'st' => 'application/vnd.sailingtracker.track', 'stc' => 'application/vnd.sun.xml.calc.template', 'std' => 'application/vnd.sun.xml.draw.template', 'step' => 'application/STEP', 'stf' => 'application/vnd.wt.stf', 'sti' => 'application/vnd.sun.xml.impress.template', 'stk' => 'application/hyperstudio', 'stl' => 'model/stl', 'stp' => 'application/STEP', 'stpx' => 'model/step+xml', 'stpxz' => 'model/step-xml+zip', 'stpz' => 'model/step+zip', 'str' => 'application/vnd.pg.format', 'stw' => 'application/vnd.sun.xml.writer.template', 'styl' => 'text/stylus', 'stylus' => 'text/stylus', 'sub' => 'text/vnd.dvb.subtitle', 'sus' => 'application/vnd.sus-calendar', 'susp' => 'application/vnd.sus-calendar', 'sv4cpio' => 'application/x-sv4cpio', 'sv4crc' => 'application/x-sv4crc', 'svc' => 'application/vnd.dvb.service', 'svd' => 'application/vnd.svd', 'svg' => 'image/svg+xml', 'svgz' => 'image/svg+xml', 'swa' => 'application/x-director', 'swf' => 'application/x-shockwave-flash', 'swi' => 'application/vnd.aristanetworks.swi', 'swidtag' => 'application/swid+xml', 'sxc' => 'application/vnd.sun.xml.calc', 'sxd' => 'application/vnd.sun.xml.draw', 'sxg' => 'application/vnd.sun.xml.writer.global', 'sxi' => 'application/vnd.sun.xml.impress', 'sxm' => 'application/vnd.sun.xml.math', 'sxw' => 'application/vnd.sun.xml.writer', 't' => 'text/troff', 't3' => 'application/x-t3vm-image', 't38' => 'image/t38', 'taglet' => 'application/vnd.mynfc', 'tao' => 'application/vnd.tao.intent-module-archive', 'tap' => 'image/vnd.tencent.tap', 'tar' => 'application/x-tar', 'tcap' => 'application/vnd.3gpp2.tcap', 'tcl' => 'application/x-tcl', 'td' => 'application/urc-targetdesc+xml', 'teacher' => 'application/vnd.smart.teacher', 'tei' => 'application/tei+xml', 'teicorpus' => 'application/tei+xml', 'tex' => 'application/x-tex', 'texi' => 'application/x-texinfo', 'texinfo' => 'application/x-texinfo', 'text' => 'text/plain', 'tfi' => 'application/thraud+xml', 'tfm' => 'application/x-tex-tfm', 'tfx' => 'image/tiff-fx', 'tga' => 'image/x-tga', 'tgz' => 'application/x-tar', 'thmx' => 'application/vnd.ms-officetheme', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'tk' => 'application/x-tcl', 'tmo' => 'application/vnd.tmobile-livetv', 'toml' => 'application/toml', 'torrent' => 'application/x-bittorrent', 'tpl' => 'application/vnd.groove-tool-template', 'tpt' => 'application/vnd.trid.tpt', 'tr' => 'text/troff', 'tra' => 'application/vnd.trueapp', 'trig' => 'application/trig', 'trm' => 'application/x-msterminal', 'ts' => 'video/mp2t', 'tsd' => 'application/timestamped-data', 'tsv' => 'text/tab-separated-values', 'ttc' => 'font/collection', 'ttf' => 'font/ttf', 'ttl' => 'text/turtle', 'ttml' => 'application/ttml+xml', 'twd' => 'application/vnd.simtech-mindmapper', 'twds' => 'application/vnd.simtech-mindmapper', 'txd' => 'application/vnd.genomatix.tuxedo', 'txf' => 'application/vnd.mobius.txf', 'txt' => 'text/plain', 'u3d' => 'model/u3d', 'u8dsn' => 'message/global-delivery-status', 'u8hdr' => 'message/global-headers', 'u8mdn' => 'message/global-disposition-notification', 'u8msg' => 'message/global', 'u32' => 'application/x-authorware-bin', 'ubj' => 'application/ubjson', 'udeb' => 'application/x-debian-package', 'ufd' => 'application/vnd.ufdl', 'ufdl' => 'application/vnd.ufdl', 'ulx' => 'application/x-glulx', 'umj' => 'application/vnd.umajin', 'unityweb' => 'application/vnd.unity', 'uo' => 'application/vnd.uoml+xml', 'uoml' => 'application/vnd.uoml+xml', 'uri' => 'text/uri-list', 'uris' => 'text/uri-list', 'urls' => 'text/uri-list', 'usda' => 'model/vnd.usda', 'usdz' => 'model/vnd.usdz+zip', 'ustar' => 'application/x-ustar', 'utz' => 'application/vnd.uiq.theme', 'uu' => 'text/x-uuencode', 'uva' => 'audio/vnd.dece.audio', 'uvd' => 'application/vnd.dece.data', 'uvf' => 'application/vnd.dece.data', 'uvg' => 'image/vnd.dece.graphic', 'uvh' => 'video/vnd.dece.hd', 'uvi' => 'image/vnd.dece.graphic', 'uvm' => 'video/vnd.dece.mobile', 'uvp' => 'video/vnd.dece.pd', 'uvs' => 'video/vnd.dece.sd', 'uvt' => 'application/vnd.dece.ttml+xml', 'uvu' => 'video/vnd.uvvu.mp4', 'uvv' => 'video/vnd.dece.video', 'uvva' => 'audio/vnd.dece.audio', 'uvvd' => 'application/vnd.dece.data', 'uvvf' => 'application/vnd.dece.data', 'uvvg' => 'image/vnd.dece.graphic', 'uvvh' => 'video/vnd.dece.hd', 'uvvi' => 'image/vnd.dece.graphic', 'uvvm' => 'video/vnd.dece.mobile', 'uvvp' => 'video/vnd.dece.pd', 'uvvs' => 'video/vnd.dece.sd', 'uvvt' => 'application/vnd.dece.ttml+xml', 'uvvu' => 'video/vnd.uvvu.mp4', 'uvvv' => 'video/vnd.dece.video', 'uvvx' => 'application/vnd.dece.unspecified', 'uvvz' => 'application/vnd.dece.zip', 'uvx' => 'application/vnd.dece.unspecified', 'uvz' => 'application/vnd.dece.zip', 'vbox' => 'application/x-virtualbox-vbox', 'vbox-extpack' => 'application/x-virtualbox-vbox-extpack', 'vcard' => 'text/vcard', 'vcd' => 'application/x-cdlink', 'vcf' => 'text/x-vcard', 'vcg' => 'application/vnd.groove-vcard', 'vcs' => 'text/x-vcalendar', 'vcx' => 'application/vnd.vcx', 'vdi' => 'application/x-virtualbox-vdi', 'vds' => 'model/vnd.sap.vds', 'vhd' => 'application/x-virtualbox-vhd', 'vis' => 'application/vnd.visionary', 'viv' => 'video/vnd.vivo', 'vlc' => 'application/videolan', 'vmdk' => 'application/x-virtualbox-vmdk', 'vob' => 'video/x-ms-vob', 'vor' => 'application/vnd.stardivision.writer', 'vox' => 'application/x-authorware-bin', 'vrml' => 'model/vrml', 'vsd' => 'application/vnd.visio', 'vsf' => 'application/vnd.vsf', 'vss' => 'application/vnd.visio', 'vst' => 'application/vnd.visio', 'vsw' => 'application/vnd.visio', 'vtf' => 'image/vnd.valve.source.texture', 'vtt' => 'text/vtt', 'vtu' => 'model/vnd.vtu', 'vxml' => 'application/voicexml+xml', 'w3d' => 'application/x-director', 'wad' => 'application/x-doom', 'wadl' => 'application/vnd.sun.wadl+xml', 'war' => 'application/java-archive', 'wasm' => 'application/wasm', 'wav' => 'audio/x-wav', 'wax' => 'audio/x-ms-wax', 'wbmp' => 'image/vnd.wap.wbmp', 'wbs' => 'application/vnd.criticaltools.wbs+xml', 'wbxml' => 'application/wbxml', 'wcm' => 'application/vnd.ms-works', 'wdb' => 'application/vnd.ms-works', 'wdp' => 'image/vnd.ms-photo', 'weba' => 'audio/webm', 'webapp' => 'application/x-web-app-manifest+json', 'webm' => 'video/webm', 'webmanifest' => 'application/manifest+json', 'webp' => 'image/webp', 'wg' => 'application/vnd.pmi.widget', 'wgsl' => 'text/wgsl', 'wgt' => 'application/widget', 'wif' => 'application/watcherinfo+xml', 'wks' => 'application/vnd.ms-works', 'wm' => 'video/x-ms-wm', 'wma' => 'audio/x-ms-wma', 'wmd' => 'application/x-ms-wmd', 'wmf' => 'image/wmf', 'wml' => 'text/vnd.wap.wml', 'wmlc' => 'application/wmlc', 'wmls' => 'text/vnd.wap.wmlscript', 'wmlsc' => 'application/vnd.wap.wmlscriptc', 'wmv' => 'video/x-ms-wmv', 'wmx' => 'video/x-ms-wmx', 'wmz' => 'application/x-msmetafile', 'woff' => 'font/woff', 'woff2' => 'font/woff2', 'word' => 'application/msword', 'wpd' => 'application/vnd.wordperfect', 'wpl' => 'application/vnd.ms-wpl', 'wps' => 'application/vnd.ms-works', 'wqd' => 'application/vnd.wqd', 'wri' => 'application/x-mswrite', 'wrl' => 'model/vrml', 'wsc' => 'message/vnd.wfa.wsc', 'wsdl' => 'application/wsdl+xml', 'wspolicy' => 'application/wspolicy+xml', 'wtb' => 'application/vnd.webturbo', 'wvx' => 'video/x-ms-wvx', 'x3d' => 'model/x3d+xml', 'x3db' => 'model/x3d+fastinfoset', 'x3dbz' => 'model/x3d+binary', 'x3dv' => 'model/x3d-vrml', 'x3dvz' => 'model/x3d+vrml', 'x3dz' => 'model/x3d+xml', 'x32' => 'application/x-authorware-bin', 'x_b' => 'model/vnd.parasolid.transmit.binary', 'x_t' => 'model/vnd.parasolid.transmit.text', 'xaml' => 'application/xaml+xml', 'xap' => 'application/x-silverlight-app', 'xar' => 'application/vnd.xara', 'xav' => 'application/xcap-att+xml', 'xbap' => 'application/x-ms-xbap', 'xbd' => 'application/vnd.fujixerox.docuworks.binder', 'xbm' => 'image/x-xbitmap', 'xca' => 'application/xcap-caps+xml', 'xcs' => 'application/calendar+xml', 'xdf' => 'application/xcap-diff+xml', 'xdm' => 'application/vnd.syncml.dm+xml', 'xdp' => 'application/vnd.adobe.xdp+xml', 'xdssc' => 'application/dssc+xml', 'xdw' => 'application/vnd.fujixerox.docuworks', 'xel' => 'application/xcap-el+xml', 'xenc' => 'application/xenc+xml', 'xer' => 'application/patch-ops-error+xml', 'xfdf' => 'application/xfdf', 'xfdl' => 'application/vnd.xfdl', 'xht' => 'application/xhtml+xml', 'xhtm' => 'application/vnd.pwg-xhtml-print+xml', 'xhtml' => 'application/xhtml+xml', 'xhvml' => 'application/xv+xml', 'xif' => 'image/vnd.xiff', 'xl' => 'application/excel', 'xla' => 'application/vnd.ms-excel', 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', 'xlc' => 'application/vnd.ms-excel', 'xlf' => 'application/xliff+xml', 'xlm' => 'application/vnd.ms-excel', 'xls' => 'application/vnd.ms-excel', 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlt' => 'application/vnd.ms-excel', 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', 'xlw' => 'application/vnd.ms-excel', 'xm' => 'audio/xm', 'xml' => 'application/xml', 'xns' => 'application/xcap-ns+xml', 'xo' => 'application/vnd.olpc-sugar', 'xop' => 'application/xop+xml', 'xpi' => 'application/x-xpinstall', 'xpl' => 'application/xproc+xml', 'xpm' => 'image/x-xpixmap', 'xpr' => 'application/vnd.is-xpr', 'xps' => 'application/vnd.ms-xpsdocument', 'xpw' => 'application/vnd.intercon.formnet', 'xpx' => 'application/vnd.intercon.formnet', 'xsd' => 'application/xml', 'xsf' => 'application/prs.xsf+xml', 'xsl' => 'application/xml', 'xslt' => 'application/xslt+xml', 'xsm' => 'application/vnd.syncml+xml', 'xspf' => 'application/xspf+xml', 'xul' => 'application/vnd.mozilla.xul+xml', 'xvm' => 'application/xv+xml', 'xvml' => 'application/xv+xml', 'xwd' => 'image/x-xwindowdump', 'xyz' => 'chemical/x-xyz', 'xz' => 'application/x-xz', 'yaml' => 'text/yaml', 'yang' => 'application/yang', 'yin' => 'application/yin+xml', 'yml' => 'text/yaml', 'ymp' => 'text/x-suse-ymp', 'z' => 'application/x-compress', 'z1' => 'application/x-zmachine', 'z2' => 'application/x-zmachine', 'z3' => 'application/x-zmachine', 'z4' => 'application/x-zmachine', 'z5' => 'application/x-zmachine', 'z6' => 'application/x-zmachine', 'z7' => 'application/x-zmachine', 'z8' => 'application/x-zmachine', 'zaz' => 'application/vnd.zzazz.deck+xml', 'zip' => 'application/zip', 'zir' => 'application/vnd.zul', 'zirz' => 'application/vnd.zul', 'zmm' => 'application/vnd.handheld-entertainment+xml', 'zsh' => 'text/x-scriptzsh']; /** * Determines the mimetype of a file by looking at its extension. * - * @param string $filename - * - * @return string|null + * @see https://raw.githubusercontent.com/jshttp/mime-db/master/db.json */ - public static function fromFilename($filename) + public static function fromFilename(string $filename) : ?string { return self::fromExtension(\pathinfo($filename, \PATHINFO_EXTENSION)); } /** * Maps a file extensions to a mimetype. * - * @param string $extension string The file extension. - * - * @return string|null - * - * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types + * @see https://raw.githubusercontent.com/jshttp/mime-db/master/db.json */ - public static function fromExtension($extension) + public static function fromExtension(string $extension) : ?string { - static $mimetypes = ['3gp' => 'video/3gpp', '7z' => 'application/x-7z-compressed', 'aac' => 'audio/x-aac', 'ai' => 'application/postscript', 'aif' => 'audio/x-aiff', 'asc' => 'text/plain', 'asf' => 'video/x-ms-asf', 'atom' => 'application/atom+xml', 'avi' => 'video/x-msvideo', 'bmp' => 'image/bmp', 'bz2' => 'application/x-bzip2', 'cer' => 'application/pkix-cert', 'crl' => 'application/pkix-crl', 'crt' => 'application/x-x509-ca-cert', 'css' => 'text/css', 'csv' => 'text/csv', 'cu' => 'application/cu-seeme', 'deb' => 'application/x-debian-package', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'dvi' => 'application/x-dvi', 'eot' => 'application/vnd.ms-fontobject', 'eps' => 'application/postscript', 'epub' => 'application/epub+zip', 'etx' => 'text/x-setext', 'flac' => 'audio/flac', 'flv' => 'video/x-flv', 'gif' => 'image/gif', 'gz' => 'application/gzip', 'htm' => 'text/html', 'html' => 'text/html', 'ico' => 'image/x-icon', 'ics' => 'text/calendar', 'ini' => 'text/plain', 'iso' => 'application/x-iso9660-image', 'jar' => 'application/java-archive', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'js' => 'text/javascript', 'json' => 'application/json', 'latex' => 'application/x-latex', 'log' => 'text/plain', 'm4a' => 'audio/mp4', 'm4v' => 'video/mp4', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'mov' => 'video/quicktime', 'mkv' => 'video/x-matroska', 'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4', 'mp4a' => 'audio/mp4', 'mp4v' => 'video/mp4', 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'mpg4' => 'video/mp4', 'oga' => 'audio/ogg', 'ogg' => 'audio/ogg', 'ogv' => 'video/ogg', 'ogx' => 'application/ogg', 'pbm' => 'image/x-portable-bitmap', 'pdf' => 'application/pdf', 'pgm' => 'image/x-portable-graymap', 'png' => 'image/png', 'pnm' => 'image/x-portable-anymap', 'ppm' => 'image/x-portable-pixmap', 'ppt' => 'application/vnd.ms-powerpoint', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'ps' => 'application/postscript', 'qt' => 'video/quicktime', 'rar' => 'application/x-rar-compressed', 'ras' => 'image/x-cmu-raster', 'rss' => 'application/rss+xml', 'rtf' => 'application/rtf', 'sgm' => 'text/sgml', 'sgml' => 'text/sgml', 'svg' => 'image/svg+xml', 'swf' => 'application/x-shockwave-flash', 'tar' => 'application/x-tar', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'torrent' => 'application/x-bittorrent', 'ttf' => 'application/x-font-ttf', 'txt' => 'text/plain', 'wav' => 'audio/x-wav', 'webm' => 'video/webm', 'webp' => 'image/webp', 'wma' => 'audio/x-ms-wma', 'wmv' => 'video/x-ms-wmv', 'woff' => 'application/x-font-woff', 'wsdl' => 'application/wsdl+xml', 'xbm' => 'image/x-xbitmap', 'xls' => 'application/vnd.ms-excel', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xml' => 'application/xml', 'xpm' => 'image/x-xpixmap', 'xwd' => 'image/x-xwindowdump', 'yaml' => 'text/yaml', 'yml' => 'text/yaml', 'zip' => 'application/zip']; - $extension = \strtolower($extension); - return isset($mimetypes[$extension]) ? $mimetypes[$extension] : null; + return self::MIME_TYPES[\strtolower($extension)] ?? null; } } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/MultipartStream.php b/vendor-prefixed/guzzlehttp/psr7/src/MultipartStream.php index de83e60..1f1cd9a 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/MultipartStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/MultipartStream.php @@ -1,18 +1,20 @@ boundary = $boundary ?: \sha1(\uniqid('', \true)); + $this->boundary = $boundary ?: \bin2hex(\random_bytes(20)); $this->stream = $this->createStream($elements); } - /** - * Get the boundary - * - * @return string - */ - public function getBoundary() + public function getBoundary() : string { return $this->boundary; } - public function isWritable() + public function isWritable() : bool { return \false; } /** * Get the headers needed before transferring the content of a POST file + * + * @param string[] $headers */ - private function getHeaders(array $headers) + private function getHeaders(array $headers) : string { $str = ''; foreach ($headers as $key => $value) { @@ -57,17 +56,20 @@ private function getHeaders(array $headers) /** * Create the aggregate stream that will be used to upload the POST data */ - protected function createStream(array $elements) + protected function createStream(array $elements = []) : StreamInterface { $stream = new AppendStream(); foreach ($elements as $element) { + if (!\is_array($element)) { + throw new \UnexpectedValueException('An array is expected'); + } $this->addElement($stream, $element); } // Add the trailing boundary with CRLF $stream->addStream(Utils::streamFor("--{$this->boundary}--\r\n")); return $stream; } - private function addElement(AppendStream $stream, array $element) + private function addElement(AppendStream $stream, array $element) : void { foreach (['contents', 'name'] as $key) { if (!\array_key_exists($key, $element)) { @@ -77,46 +79,49 @@ private function addElement(AppendStream $stream, array $element) $element['contents'] = Utils::streamFor($element['contents']); if (empty($element['filename'])) { $uri = $element['contents']->getMetadata('uri'); - if (\substr($uri, 0, 6) !== 'php://') { + if ($uri && \is_string($uri) && \substr($uri, 0, 6) !== 'php://' && \substr($uri, 0, 7) !== 'data://') { $element['filename'] = $uri; } } - list($body, $headers) = $this->createElement($element['name'], $element['contents'], isset($element['filename']) ? $element['filename'] : null, isset($element['headers']) ? $element['headers'] : []); + [$body, $headers] = $this->createElement($element['name'], $element['contents'], $element['filename'] ?? null, $element['headers'] ?? []); $stream->addStream(Utils::streamFor($this->getHeaders($headers))); $stream->addStream($body); $stream->addStream(Utils::streamFor("\r\n")); } /** - * @return array + * @param string[] $headers + * + * @return array{0: StreamInterface, 1: string[]} */ - private function createElement($name, StreamInterface $stream, $filename, array $headers) + private function createElement(string $name, StreamInterface $stream, ?string $filename, array $headers) : array { // Set a default content-disposition header if one was no provided - $disposition = $this->getHeader($headers, 'content-disposition'); + $disposition = self::getHeader($headers, 'content-disposition'); if (!$disposition) { $headers['Content-Disposition'] = $filename === '0' || $filename ? \sprintf('form-data; name="%s"; filename="%s"', $name, \basename($filename)) : "form-data; name=\"{$name}\""; } // Set a default content-length header if one was no provided - $length = $this->getHeader($headers, 'content-length'); + $length = self::getHeader($headers, 'content-length'); if (!$length) { if ($length = $stream->getSize()) { $headers['Content-Length'] = (string) $length; } } // Set a default Content-Type if one was not supplied - $type = $this->getHeader($headers, 'content-type'); + $type = self::getHeader($headers, 'content-type'); if (!$type && ($filename === '0' || $filename)) { - if ($type = MimeType::fromFilename($filename)) { - $headers['Content-Type'] = $type; - } + $headers['Content-Type'] = MimeType::fromFilename($filename) ?? 'application/octet-stream'; } return [$stream, $headers]; } - private function getHeader(array $headers, $key) + /** + * @param string[] $headers + */ + private static function getHeader(array $headers, string $key) : ?string { $lowercaseHeader = \strtolower($key); foreach ($headers as $k => $v) { - if (\strtolower($k) === $lowercaseHeader) { + if (\strtolower((string) $k) === $lowercaseHeader) { return $v; } } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/NoSeekStream.php b/vendor-prefixed/guzzlehttp/psr7/src/NoSeekStream.php index 9f8d29e..08bd7c3 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/NoSeekStream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/NoSeekStream.php @@ -1,21 +1,22 @@ source = $source; - $this->size = isset($options['size']) ? $options['size'] : null; - $this->metadata = isset($options['metadata']) ? $options['metadata'] : []; + $this->size = $options['size'] ?? null; + $this->metadata = $options['metadata'] ?? []; $this->buffer = new BufferStream(); } - public function __toString() + public function __toString() : string { try { return Utils::copyToString($this); - } catch (\Exception $e) { + } catch (\Throwable $e) { + if (\PHP_VERSION_ID >= 70400) { + throw $e; + } + \trigger_error(\sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR); return ''; } } - public function close() + public function close() : void { $this->detach(); } public function detach() { - $this->tellPos = \false; + $this->tellPos = 0; $this->source = null; return null; } - public function getSize() + public function getSize() : ?int { return $this->size; } - public function tell() + public function tell() : int { return $this->tellPos; } - public function eof() + public function eof() : bool { - return !$this->source; + return $this->source === null; } - public function isSeekable() + public function isSeekable() : bool { return \false; } - public function rewind() + public function rewind() : void { $this->seek(0); } - public function seek($offset, $whence = \SEEK_SET) + public function seek($offset, $whence = \SEEK_SET) : void { throw new \RuntimeException('Cannot seek a PumpStream'); } - public function isWritable() + public function isWritable() : bool { return \false; } - public function write($string) + public function write($string) : int { throw new \RuntimeException('Cannot write to a PumpStream'); } - public function isReadable() + public function isReadable() : bool { return \true; } - public function read($length) + public function read($length) : string { $data = $this->buffer->read($length); $readLen = \strlen($data); @@ -111,7 +114,7 @@ public function read($length) } return $data; } - public function getContents() + public function getContents() : string { $result = ''; while (!$this->eof()) { @@ -119,18 +122,21 @@ public function getContents() } return $result; } + /** + * @return mixed + */ public function getMetadata($key = null) { if (!$key) { return $this->metadata; } - return isset($this->metadata[$key]) ? $this->metadata[$key] : null; + return $this->metadata[$key] ?? null; } - private function pump($length) + private function pump(int $length) : void { - if ($this->source) { + if ($this->source !== null) { do { - $data = \call_user_func($this->source, $length); + $data = ($this->source)($length); if ($data === \false || $data === null) { $this->source = null; return; diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Query.php b/vendor-prefixed/guzzlehttp/psr7/src/Query.php index da0e0e4..851fb4b 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Query.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Query.php @@ -1,5 +1,6 @@ $v) { - $k = $encoder($k); + $k = $encoder((string) $k); if (!\is_array($v)) { $qs .= $k; + $v = \is_bool($v) ? $castBool($v) : $v; if ($v !== null) { - $qs .= '=' . $encoder($v); + $qs .= '=' . $encoder((string) $v); } $qs .= '&'; } else { foreach ($v as $vv) { $qs .= $k; + $vv = \is_bool($vv) ? $castBool($vv) : $vv; if ($vv !== null) { - $qs .= '=' . $encoder($vv); + $qs .= '=' . $encoder((string) $vv); } $qs .= '&'; } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Request.php b/vendor-prefixed/guzzlehttp/psr7/src/Request.php index 64538ef..1b39fc4 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Request.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Request.php @@ -1,5 +1,6 @@ assertMethod($method); if (!$uri instanceof UriInterface) { @@ -42,13 +43,13 @@ public function __construct($method, $uri, array $headers = [], $body = null, $v $this->stream = Utils::streamFor($body); } } - public function getRequestTarget() + public function getRequestTarget() : string { if ($this->requestTarget !== null) { return $this->requestTarget; } $target = $this->uri->getPath(); - if ($target == '') { + if ($target === '') { $target = '/'; } if ($this->uri->getQuery() != '') { @@ -56,7 +57,7 @@ public function getRequestTarget() } return $target; } - public function withRequestTarget($requestTarget) + public function withRequestTarget($requestTarget) : RequestInterface { if (\preg_match('#\\s#', $requestTarget)) { throw new InvalidArgumentException('Invalid request target provided; cannot contain whitespace'); @@ -65,22 +66,22 @@ public function withRequestTarget($requestTarget) $new->requestTarget = $requestTarget; return $new; } - public function getMethod() + public function getMethod() : string { return $this->method; } - public function withMethod($method) + public function withMethod($method) : RequestInterface { $this->assertMethod($method); $new = clone $this; $new->method = \strtoupper($method); return $new; } - public function getUri() + public function getUri() : UriInterface { return $this->uri; } - public function withUri(UriInterface $uri, $preserveHost = \false) + public function withUri(UriInterface $uri, $preserveHost = \false) : RequestInterface { if ($uri === $this->uri) { return $this; @@ -92,7 +93,7 @@ public function withUri(UriInterface $uri, $preserveHost = \false) } return $new; } - private function updateHostFromUri() + private function updateHostFromUri() : void { $host = $this->uri->getHost(); if ($host == '') { @@ -108,13 +109,16 @@ private function updateHostFromUri() $this->headerNames['host'] = 'Host'; } // Ensure Host is the first header. - // See: http://tools.ietf.org/html/rfc7230#section-5.4 + // See: https://datatracker.ietf.org/doc/html/rfc7230#section-5.4 $this->headers = [$header => [$host]] + $this->headers; } - private function assertMethod($method) + /** + * @param mixed $method + */ + private function assertMethod($method) : void { if (!\is_string($method) || $method === '') { - throw new \InvalidArgumentException('Method must be a non-empty string.'); + throw new InvalidArgumentException('Method must be a non-empty string.'); } } } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Response.php b/vendor-prefixed/guzzlehttp/psr7/src/Response.php index bcf090c..bf03e4f 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Response.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Response.php @@ -1,5 +1,6 @@ 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-status', 208 => 'Already Reported', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Switch Proxy', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Unordered Collection', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable For Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 511 => 'Network Authentication Required']; + /** Map of standard HTTP status code/reason phrases */ + private const PHRASES = [100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-status', 208 => 'Already Reported', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Switch Proxy', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Unordered Collection', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable For Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 510 => 'Not Extended', 511 => 'Network Authentication Required']; /** @var string */ - private $reasonPhrase = ''; + private $reasonPhrase; /** @var int */ - private $statusCode = 200; + private $statusCode; /** * @param int $status Status code - * @param array $headers Response headers + * @param (string|string[])[] $headers Response headers * @param string|resource|StreamInterface|null $body Response body * @param string $version Protocol version * @param string|null $reason Reason phrase (when empty a default will be used based on the status code) */ - public function __construct($status = 200, array $headers = [], $body = null, $version = '1.1', $reason = null) + public function __construct(int $status = 200, array $headers = [], $body = null, string $version = '1.1', ?string $reason = null) { - $this->assertStatusCodeIsInteger($status); - $status = (int) $status; $this->assertStatusCodeRange($status); $this->statusCode = $status; if ($body !== '' && $body !== null) { $this->stream = Utils::streamFor($body); } $this->setHeaders($headers); - if ($reason == '' && isset(self::$phrases[$this->statusCode])) { - $this->reasonPhrase = self::$phrases[$this->statusCode]; + if ($reason == '' && isset(self::PHRASES[$this->statusCode])) { + $this->reasonPhrase = self::PHRASES[$this->statusCode]; } else { $this->reasonPhrase = (string) $reason; } $this->protocol = $version; } - public function getStatusCode() + public function getStatusCode() : int { return $this->statusCode; } - public function getReasonPhrase() + public function getReasonPhrase() : string { return $this->reasonPhrase; } - public function withStatus($code, $reasonPhrase = '') + public function withStatus($code, $reasonPhrase = '') : ResponseInterface { $this->assertStatusCodeIsInteger($code); $code = (int) $code; $this->assertStatusCodeRange($code); $new = clone $this; $new->statusCode = $code; - if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) { - $reasonPhrase = self::$phrases[$new->statusCode]; + if ($reasonPhrase == '' && isset(self::PHRASES[$new->statusCode])) { + $reasonPhrase = self::PHRASES[$new->statusCode]; } $new->reasonPhrase = (string) $reasonPhrase; return $new; } - private function assertStatusCodeIsInteger($statusCode) + /** + * @param mixed $statusCode + */ + private function assertStatusCodeIsInteger($statusCode) : void { if (\filter_var($statusCode, \FILTER_VALIDATE_INT) === \false) { throw new \InvalidArgumentException('Status code must be an integer value.'); } } - private function assertStatusCodeRange($statusCode) + private function assertStatusCodeRange(int $statusCode) : void { if ($statusCode < 100 || $statusCode >= 600) { throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.'); diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Rfc7230.php b/vendor-prefixed/guzzlehttp/psr7/src/Rfc7230.php index c2518e7..2bf254e 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Rfc7230.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Rfc7230.php @@ -1,19 +1,22 @@ @,;:\\\"/[\\]?={}\x01- ]++):[ \t]*+((?:[ \t]*+[!-~\x80-\xff]++)*+)[ \t]*+\r?\n)m"; - const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)"; + public const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\\]?={}\x01- ]++):[ \t]*+((?:[ \t]*+[!-~\x80-\xff]++)*+)[ \t]*+\r?\n)m"; + public const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)"; } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/ServerRequest.php b/vendor-prefixed/guzzlehttp/psr7/src/ServerRequest.php index 48bc313..9de6838 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/ServerRequest.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/ServerRequest.php @@ -1,5 +1,6 @@ serverParams = $serverParams; parent::__construct($method, $uri, $headers, $body, $version); @@ -63,13 +64,11 @@ public function __construct($method, $uri, array $headers = [], $body = null, $v /** * Return an UploadedFile instance array. * - * @param array $files A array which respect $_FILES structure - * - * @return array + * @param array $files An array which respect $_FILES structure * * @throws InvalidArgumentException for unrecognized values */ - public static function normalizeFiles(array $files) + public static function normalizeFiles(array $files) : array { $normalized = []; foreach ($files as $key => $value) { @@ -94,7 +93,7 @@ public static function normalizeFiles(array $files) * * @param array $value $_FILES struct * - * @return array|UploadedFileInterface + * @return UploadedFileInterface|UploadedFileInterface[] */ private static function createUploadedFileFromSpec(array $value) { @@ -109,15 +108,13 @@ private static function createUploadedFileFromSpec(array $value) * Loops through all nested files and returns a normalized array of * UploadedFileInterface instances. * - * @param array $files - * * @return UploadedFileInterface[] */ - private static function normalizeNestedFileSpec(array $files = []) + private static function normalizeNestedFileSpec(array $files = []) : array { $normalizedFiles = []; foreach (\array_keys($files['tmp_name']) as $key) { - $spec = ['tmp_name' => $files['tmp_name'][$key], 'size' => $files['size'][$key], 'error' => $files['error'][$key], 'name' => $files['name'][$key], 'type' => $files['type'][$key]]; + $spec = ['tmp_name' => $files['tmp_name'][$key], 'size' => $files['size'][$key] ?? null, 'error' => $files['error'][$key] ?? null, 'name' => $files['name'][$key] ?? null, 'type' => $files['type'][$key] ?? null]; $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec); } return $normalizedFiles; @@ -129,12 +126,10 @@ private static function normalizeNestedFileSpec(array $files = []) * $_COOKIE * $_FILES * $_SERVER - * - * @return ServerRequestInterface */ - public static function fromGlobals() + public static function fromGlobals() : ServerRequestInterface { - $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET'; + $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; $headers = \getallheaders(); $uri = self::getUriFromGlobals(); $body = new CachingStream(new LazyOpenStream('php://input', 'r+')); @@ -142,29 +137,27 @@ public static function fromGlobals() $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER); return $serverRequest->withCookieParams($_COOKIE)->withQueryParams($_GET)->withParsedBody($_POST)->withUploadedFiles(self::normalizeFiles($_FILES)); } - private static function extractHostAndPortFromAuthority($authority) + private static function extractHostAndPortFromAuthority(string $authority) : array { $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; + $host = $parts['host'] ?? null; + $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() : UriInterface { $uri = new Uri(''); $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http'); $hasPort = \false; if (isset($_SERVER['HTTP_HOST'])) { - list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']); + [$host, $port] = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']); if ($host !== null) { $uri = $uri->withHost($host); } @@ -194,86 +187,59 @@ public static function getUriFromGlobals() } return $uri; } - /** - * {@inheritdoc} - */ - public function getServerParams() + public function getServerParams() : array { return $this->serverParams; } - /** - * {@inheritdoc} - */ - public function getUploadedFiles() + public function getUploadedFiles() : array { return $this->uploadedFiles; } - /** - * {@inheritdoc} - */ - public function withUploadedFiles(array $uploadedFiles) + public function withUploadedFiles(array $uploadedFiles) : ServerRequestInterface { $new = clone $this; $new->uploadedFiles = $uploadedFiles; return $new; } - /** - * {@inheritdoc} - */ - public function getCookieParams() + public function getCookieParams() : array { return $this->cookieParams; } - /** - * {@inheritdoc} - */ - public function withCookieParams(array $cookies) + public function withCookieParams(array $cookies) : ServerRequestInterface { $new = clone $this; $new->cookieParams = $cookies; return $new; } - /** - * {@inheritdoc} - */ - public function getQueryParams() + public function getQueryParams() : array { return $this->queryParams; } - /** - * {@inheritdoc} - */ - public function withQueryParams(array $query) + public function withQueryParams(array $query) : ServerRequestInterface { $new = clone $this; $new->queryParams = $query; return $new; } /** - * {@inheritdoc} + * @return array|object|null */ public function getParsedBody() { return $this->parsedBody; } - /** - * {@inheritdoc} - */ - public function withParsedBody($data) + public function withParsedBody($data) : ServerRequestInterface { $new = clone $this; $new->parsedBody = $data; return $new; } - /** - * {@inheritdoc} - */ - public function getAttributes() + public function getAttributes() : array { return $this->attributes; } /** - * {@inheritdoc} + * @return mixed */ public function getAttribute($attribute, $default = null) { @@ -282,19 +248,13 @@ public function getAttribute($attribute, $default = null) } return $this->attributes[$attribute]; } - /** - * {@inheritdoc} - */ - public function withAttribute($attribute, $value) + public function withAttribute($attribute, $value) : ServerRequestInterface { $new = clone $this; $new->attributes[$attribute] = $value; return $new; } - /** - * {@inheritdoc} - */ - public function withoutAttribute($attribute) + public function withoutAttribute($attribute) : ServerRequestInterface { if (\false === \array_key_exists($attribute, $this->attributes)) { return $this; diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Stream.php b/vendor-prefixed/guzzlehttp/psr7/src/Stream.php index 048e05a..782fa81 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Stream.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Stream.php @@ -1,31 +1,33 @@ size = $options['size']; } - $this->customMetadata = isset($options['metadata']) ? $options['metadata'] : []; + $this->customMetadata = $options['metadata'] ?? []; $this->stream = $stream; $meta = \stream_get_meta_data($this->stream); $this->seekable = $meta['seekable']; @@ -64,29 +66,32 @@ public function __destruct() { $this->close(); } - public function __toString() + public function __toString() : string { try { if ($this->isSeekable()) { $this->seek(0); } return $this->getContents(); - } catch (\Exception $e) { + } catch (\Throwable $e) { + if (\PHP_VERSION_ID >= 70400) { + throw $e; + } + \trigger_error(\sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR); return ''; } } - public function getContents() + public function getContents() : string { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); } - $contents = \stream_get_contents($this->stream); - if ($contents === \false) { - throw new \RuntimeException('Unable to read stream contents'); + if (!$this->readable) { + throw new \RuntimeException('Cannot read from non-readable stream'); } - return $contents; + return Utils::tryGetContents($this->stream); } - public function close() + public function close() : void { if (isset($this->stream)) { if (\is_resource($this->stream)) { @@ -106,7 +111,7 @@ public function detach() $this->readable = $this->writable = $this->seekable = \false; return $result; } - public function getSize() + public function getSize() : ?int { if ($this->size !== null) { return $this->size; @@ -119,32 +124,32 @@ public function getSize() \clearstatcache(\true, $this->uri); } $stats = \fstat($this->stream); - if (isset($stats['size'])) { + if (\is_array($stats) && isset($stats['size'])) { $this->size = $stats['size']; return $this->size; } return null; } - public function isReadable() + public function isReadable() : bool { return $this->readable; } - public function isWritable() + public function isWritable() : bool { return $this->writable; } - public function isSeekable() + public function isSeekable() : bool { return $this->seekable; } - public function eof() + public function eof() : bool { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); } return \feof($this->stream); } - public function tell() + public function tell() : int { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); @@ -155,11 +160,11 @@ public function tell() } return $result; } - public function rewind() + public function rewind() : void { $this->seek(0); } - public function seek($offset, $whence = \SEEK_SET) + public function seek($offset, $whence = \SEEK_SET) : void { $whence = (int) $whence; if (!isset($this->stream)) { @@ -172,7 +177,7 @@ public function seek($offset, $whence = \SEEK_SET) throw new \RuntimeException('Unable to seek to stream position ' . $offset . ' with whence ' . \var_export($whence, \true)); } } - public function read($length) + public function read($length) : string { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); @@ -186,13 +191,17 @@ public function read($length) if (0 === $length) { return ''; } - $string = \fread($this->stream, $length); + try { + $string = \fread($this->stream, $length); + } catch (\Exception $e) { + throw new \RuntimeException('Unable to read from stream', 0, $e); + } if (\false === $string) { throw new \RuntimeException('Unable to read from stream'); } return $string; } - public function write($string) + public function write($string) : int { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); @@ -208,6 +217,9 @@ public function write($string) } return $result; } + /** + * @return mixed + */ public function getMetadata($key = null) { if (!isset($this->stream)) { @@ -218,6 +230,6 @@ public function getMetadata($key = null) return $this->customMetadata[$key]; } $meta = \stream_get_meta_data($this->stream); - return isset($meta[$key]) ? $meta[$key] : null; + return $meta[$key] ?? null; } } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/StreamDecoratorTrait.php b/vendor-prefixed/guzzlehttp/psr7/src/StreamDecoratorTrait.php index ee11557..b5bf15f 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/StreamDecoratorTrait.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/StreamDecoratorTrait.php @@ -1,12 +1,13 @@ stream = $this->createStream(); return $this->stream; } throw new \UnexpectedValueException("{$name} not found on class"); } - public function __toString() + public function __toString() : string { try { if ($this->isSeekable()) { $this->seek(0); } return $this->getContents(); - } catch (\Exception $e) { - // Really, PHP? https://bugs.php.net/bug.php?id=53648 - \trigger_error('StreamDecorator::__toString exception: ' . (string) $e, \E_USER_ERROR); + } catch (\Throwable $e) { + if (\PHP_VERSION_ID >= 70400) { + throw $e; + } + \trigger_error(\sprintf('%s::__toString exception: %s', self::class, (string) $e), \E_USER_ERROR); return ''; } } - public function getContents() + public function getContents() : string { return Utils::copyToString($this); } /** * Allow decorators to implement custom methods * - * @param string $method Missing method name - * @param array $args Method arguments - * * @return mixed */ - public function __call($method, array $args) + public function __call(string $method, array $args) { - $result = \call_user_func_array([$this->stream, $method], $args); + /** @var callable $callable */ + $callable = [$this->stream, $method]; + $result = $callable(...$args); // Always return the wrapped object if the result is a return $this return $result === $this->stream ? $this : $result; } - public function close() + public function close() : void { $this->stream->close(); } + /** + * @return mixed + */ public function getMetadata($key = null) { return $this->stream->getMetadata($key); @@ -76,54 +79,52 @@ public function detach() { return $this->stream->detach(); } - public function getSize() + public function getSize() : ?int { return $this->stream->getSize(); } - public function eof() + public function eof() : bool { return $this->stream->eof(); } - public function tell() + public function tell() : int { return $this->stream->tell(); } - public function isReadable() + public function isReadable() : bool { return $this->stream->isReadable(); } - public function isWritable() + public function isWritable() : bool { return $this->stream->isWritable(); } - public function isSeekable() + public function isSeekable() : bool { return $this->stream->isSeekable(); } - public function rewind() + public function rewind() : void { $this->seek(0); } - public function seek($offset, $whence = \SEEK_SET) + public function seek($offset, $whence = \SEEK_SET) : void { $this->stream->seek($offset, $whence); } - public function read($length) + public function read($length) : string { return $this->stream->read($length); } - public function write($string) + public function write($string) : int { return $this->stream->write($string); } /** * Implement in subclasses to dynamically create streams when requested. * - * @return StreamInterface - * * @throws \BadMethodCallException */ - protected function createStream() + protected function createStream() : StreamInterface { throw new \BadMethodCallException('Not implemented'); } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/StreamWrapper.php b/vendor-prefixed/guzzlehttp/psr7/src/StreamWrapper.php index 685aff6..a0cf89c 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/StreamWrapper.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/StreamWrapper.php @@ -1,14 +1,15 @@ context); if (!isset($options['guzzle']['stream'])) { @@ -67,38 +66,79 @@ public function stream_open($path, $mode, $options, &$opened_path) $this->stream = $options['guzzle']['stream']; return \true; } - public function stream_read($count) + public function stream_read(int $count) : string { return $this->stream->read($count); } - public function stream_write($data) + public function stream_write(string $data) : int { - return (int) $this->stream->write($data); + return $this->stream->write($data); } - public function stream_tell() + public function stream_tell() : int { return $this->stream->tell(); } - public function stream_eof() + public function stream_eof() : bool { return $this->stream->eof(); } - public function stream_seek($offset, $whence) + public function stream_seek(int $offset, int $whence) : bool { $this->stream->seek($offset, $whence); return \true; } - public function stream_cast($cast_as) + /** + * @return resource|false + */ + public function stream_cast(int $cast_as) { $stream = clone $this->stream; - return $stream->detach(); + $resource = $stream->detach(); + return $resource ?? \false; } + /** + * @return array{ + * dev: int, + * ino: int, + * mode: int, + * nlink: int, + * uid: int, + * gid: int, + * rdev: int, + * size: int, + * atime: int, + * mtime: int, + * ctime: int, + * blksize: int, + * blocks: int + * }|false + */ public function stream_stat() { + if ($this->stream->getSize() === null) { + return \false; + } static $modeMap = ['r' => 33060, 'rb' => 33060, 'r+' => 33206, 'w' => 33188, 'wb' => 33188]; return ['dev' => 0, 'ino' => 0, 'mode' => $modeMap[$this->mode], 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'size' => $this->stream->getSize() ?: 0, 'atime' => 0, 'mtime' => 0, 'ctime' => 0, 'blksize' => 0, 'blocks' => 0]; } - public function url_stat($path, $flags) + /** + * @return array{ + * dev: int, + * ino: int, + * mode: int, + * nlink: int, + * uid: int, + * gid: int, + * rdev: int, + * size: int, + * atime: int, + * mtime: int, + * ctime: int, + * blksize: int, + * blocks: int + * } + */ + public function url_stat(string $path, int $flags) : array { 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]; } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/UploadedFile.php b/vendor-prefixed/guzzlehttp/psr7/src/UploadedFile.php index 0882581..b21378a 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/UploadedFile.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/UploadedFile.php @@ -1,5 +1,6 @@ 'UPLOAD_ERR_OK', \UPLOAD_ERR_INI_SIZE => 'UPLOAD_ERR_INI_SIZE', \UPLOAD_ERR_FORM_SIZE => 'UPLOAD_ERR_FORM_SIZE', \UPLOAD_ERR_PARTIAL => 'UPLOAD_ERR_PARTIAL', \UPLOAD_ERR_NO_FILE => 'UPLOAD_ERR_NO_FILE', \UPLOAD_ERR_NO_TMP_DIR => 'UPLOAD_ERR_NO_TMP_DIR', \UPLOAD_ERR_CANT_WRITE => 'UPLOAD_ERR_CANT_WRITE', \UPLOAD_ERR_EXTENSION => 'UPLOAD_ERR_EXTENSION']; /** - * @var int[] - */ - private static $errors = [\UPLOAD_ERR_OK, \UPLOAD_ERR_INI_SIZE, \UPLOAD_ERR_FORM_SIZE, \UPLOAD_ERR_PARTIAL, \UPLOAD_ERR_NO_FILE, \UPLOAD_ERR_NO_TMP_DIR, \UPLOAD_ERR_CANT_WRITE, \UPLOAD_ERR_EXTENSION]; - /** - * @var string + * @var string|null */ private $clientFilename; /** - * @var string + * @var string|null */ private $clientMediaType; /** @@ -33,7 +31,7 @@ class UploadedFile implements UploadedFileInterface */ private $moved = \false; /** - * @var int + * @var int|null */ private $size; /** @@ -42,17 +40,13 @@ class UploadedFile implements UploadedFileInterface private $stream; /** * @param StreamInterface|string|resource $streamOrFile - * @param int $size - * @param int $errorStatus - * @param string|null $clientFilename - * @param string|null $clientMediaType */ - public function __construct($streamOrFile, $size, $errorStatus, $clientFilename = null, $clientMediaType = null) + public function __construct($streamOrFile, ?int $size, int $errorStatus, ?string $clientFilename = null, ?string $clientMediaType = null) { $this->setError($errorStatus); - $this->setSize($size); - $this->setClientFilename($clientFilename); - $this->setClientMediaType($clientMediaType); + $this->size = $size; + $this->clientFilename = $clientFilename; + $this->clientMediaType = $clientMediaType; if ($this->isOk()) { $this->setStreamOrFile($streamOrFile); } @@ -60,11 +54,11 @@ public function __construct($streamOrFile, $size, $errorStatus, $clientFilename /** * Depending on the value set file or stream variable * - * @param mixed $streamOrFile + * @param StreamInterface|string|resource $streamOrFile * * @throws InvalidArgumentException */ - private function setStreamOrFile($streamOrFile) + private function setStreamOrFile($streamOrFile) : void { if (\is_string($streamOrFile)) { $this->file = $streamOrFile; @@ -77,136 +71,60 @@ private function setStreamOrFile($streamOrFile) } } /** - * @param int $error - * * @throws InvalidArgumentException */ - private function setError($error) + private function setError(int $error) : void { - if (\false === \is_int($error)) { - throw new InvalidArgumentException('Upload file error status must be an integer'); - } - if (\false === \in_array($error, UploadedFile::$errors)) { + if (!isset(UploadedFile::ERROR_MAP[$error])) { throw new InvalidArgumentException('Invalid error status for UploadedFile'); } $this->error = $error; } - /** - * @param int $size - * - * @throws InvalidArgumentException - */ - private function setSize($size) - { - if (\false === \is_int($size)) { - throw new InvalidArgumentException('Upload file size must be an integer'); - } - $this->size = $size; - } - /** - * @param mixed $param - * - * @return bool - */ - private function isStringOrNull($param) - { - return \in_array(\gettype($param), ['string', 'NULL']); - } - /** - * @param mixed $param - * - * @return bool - */ - private function isStringNotEmpty($param) + private static function isStringNotEmpty($param) : bool { return \is_string($param) && \false === empty($param); } - /** - * @param string|null $clientFilename - * - * @throws InvalidArgumentException - */ - private function setClientFilename($clientFilename) - { - if (\false === $this->isStringOrNull($clientFilename)) { - throw new InvalidArgumentException('Upload file client filename must be a string or null'); - } - $this->clientFilename = $clientFilename; - } - /** - * @param string|null $clientMediaType - * - * @throws InvalidArgumentException - */ - private function setClientMediaType($clientMediaType) - { - if (\false === $this->isStringOrNull($clientMediaType)) { - throw new InvalidArgumentException('Upload file client media type must be a string or null'); - } - $this->clientMediaType = $clientMediaType; - } /** * Return true if there is no upload error - * - * @return bool */ - private function isOk() + private function isOk() : bool { return $this->error === \UPLOAD_ERR_OK; } - /** - * @return bool - */ - public function isMoved() + public function isMoved() : bool { return $this->moved; } /** * @throws RuntimeException if is moved or not ok */ - private function validateActive() + private function validateActive() : void { if (\false === $this->isOk()) { - throw new RuntimeException('Cannot retrieve stream due to upload error'); + throw new RuntimeException(\sprintf('Cannot retrieve stream due to upload error (%s)', self::ERROR_MAP[$this->error])); } if ($this->isMoved()) { throw new RuntimeException('Cannot retrieve stream after it has already been moved'); } } - /** - * {@inheritdoc} - * - * @throws RuntimeException if the upload was not successful. - */ - public function getStream() + public function getStream() : StreamInterface { $this->validateActive(); if ($this->stream instanceof StreamInterface) { return $this->stream; } - return new LazyOpenStream($this->file, 'r+'); + /** @var string $file */ + $file = $this->file; + return new LazyOpenStream($file, 'r+'); } - /** - * {@inheritdoc} - * - * @see http://php.net/is_uploaded_file - * @see http://php.net/move_uploaded_file - * - * @param string $targetPath Path to which to move the uploaded file. - * - * @throws RuntimeException if the upload was not successful. - * @throws InvalidArgumentException if the $path specified is invalid. - * @throws RuntimeException on any error during the move operation, or on - * the second or subsequent call to the method. - */ - public function moveTo($targetPath) + public function moveTo($targetPath) : void { $this->validateActive(); - if (\false === $this->isStringNotEmpty($targetPath)) { + if (\false === self::isStringNotEmpty($targetPath)) { throw new InvalidArgumentException('Invalid path provided for move operation; must be a non-empty string'); } if ($this->file) { - $this->moved = \php_sapi_name() == 'cli' ? \rename($this->file, $targetPath) : \move_uploaded_file($this->file, $targetPath); + $this->moved = \PHP_SAPI === 'cli' ? \rename($this->file, $targetPath) : \move_uploaded_file($this->file, $targetPath); } else { Utils::copyToStream($this->getStream(), new LazyOpenStream($targetPath, 'w')); $this->moved = \true; @@ -215,40 +133,19 @@ public function moveTo($targetPath) throw new RuntimeException(\sprintf('Uploaded file could not be moved to %s', $targetPath)); } } - /** - * {@inheritdoc} - * - * @return int|null The file size in bytes or null if unknown. - */ - public function getSize() + public function getSize() : ?int { return $this->size; } - /** - * {@inheritdoc} - * - * @see http://php.net/manual/en/features.file-upload.errors.php - * - * @return int One of PHP's UPLOAD_ERR_XXX constants. - */ - public function getError() + public function getError() : int { return $this->error; } - /** - * {@inheritdoc} - * - * @return string|null The filename sent by the client or null if none - * was provided. - */ - public function getClientFilename() + public function getClientFilename() : ?string { return $this->clientFilename; } - /** - * {@inheritdoc} - */ - public function getClientMediaType() + public function getClientMediaType() : ?string { return $this->clientMediaType; } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Uri.php b/vendor-prefixed/guzzlehttp/psr7/src/Uri.php index a91e23a..48db49e 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Uri.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Uri.php @@ -1,7 +1,9 @@ 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']; + private const HTTP_DEFAULT_HOST = 'localhost'; + private const DEFAULT_PORTS = ['http' => 80, 'https' => 443, 'ftp' => 21, 'gopher' => 70, 'nntp' => 119, 'news' => 119, 'telnet' => 23, 'tn3270' => 23, 'imap' => 143, 'pop' => 110, 'ldap' => 389]; + /** + * Unreserved characters for use in a regex. + * + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.3 + */ + private const CHAR_UNRESERVED = 'a-zA-Z0-9_\\-\\.~'; + /** + * Sub-delims for use in a regex. + * + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-2.2 + */ + private const CHAR_SUB_DELIMS = '!\\$&\'\\(\\)\\*\\+,;='; + private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26']; /** @var string Uri scheme. */ private $scheme = ''; /** @var string Uri user info. */ @@ -37,16 +49,14 @@ class Uri implements UriInterface private $query = ''; /** @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); } @@ -64,18 +74,18 @@ public function __construct($uri = '') * @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)) { + if (\preg_match('%^(.*://\\[[0-9:a-fA-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) { return \urlencode($matches[0]); }, $url); @@ -85,9 +95,12 @@ private static function parse($url) } 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; } /** * Composes a URI reference string from its various components. @@ -105,17 +118,9 @@ public function __toString() * `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 + * @see https://datatracker.ietf.org/doc/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 = ''; // weak type checks to also accept null until we can add scalar type hints @@ -125,6 +130,9 @@ public static function composeComponents($scheme, $authority, $path, $query, $fr if ($authority != '' || $scheme === 'file') { $uri .= '//' . $authority; } + if ($authority != '' && $path != '' && $path[0] != '/') { + $path = '/' . $path; + } $uri .= $path; if ($query != '') { $uri .= '?' . $query; @@ -139,14 +147,10 @@ public static function composeComponents($scheme, $authority, $path, $query, $fr * * `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()]; + return $uri->getPort() === null || isset(self::DEFAULT_PORTS[$uri->getScheme()]) && $uri->getPort() === self::DEFAULT_PORTS[$uri->getScheme()]; } /** * Whether the URI is absolute, i.e. it has a scheme. @@ -158,16 +162,12 @@ public static function isDefaultPort(UriInterface $uri) * - 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 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4 */ - public static function isAbsolute(UriInterface $uri) + public static function isAbsolute(UriInterface $uri) : bool { return $uri->getScheme() !== ''; } @@ -176,13 +176,9 @@ public static function isAbsolute(UriInterface $uri) * * 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 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ - public static function isNetworkPathReference(UriInterface $uri) + public static function isNetworkPathReference(UriInterface $uri) : bool { return $uri->getScheme() === '' && $uri->getAuthority() !== ''; } @@ -191,13 +187,9 @@ public static function isNetworkPathReference(UriInterface $uri) * * 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 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ - public static function isAbsolutePathReference(UriInterface $uri) + public static function isAbsolutePathReference(UriInterface $uri) : bool { return $uri->getScheme() === '' && $uri->getAuthority() === '' && isset($uri->getPath()[0]) && $uri->getPath()[0] === '/'; } @@ -206,13 +198,9 @@ public static function isAbsolutePathReference(UriInterface $uri) * * 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 + * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 */ - public static function isRelativePathReference(UriInterface $uri) + public static function isRelativePathReference(UriInterface $uri) : bool { return $uri->getScheme() === '' && $uri->getAuthority() === '' && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/'); } @@ -226,11 +214,9 @@ public static function isRelativePathReference(UriInterface $uri) * @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 + * @see https://datatracker.ietf.org/doc/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); @@ -238,38 +224,6 @@ public static function isSameDocumentReference(UriInterface $uri, UriInterface $ } 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. * @@ -278,10 +232,8 @@ public static function resolve(UriInterface $base, $rel) * * @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]); return $uri->withQuery(\implode('&', $result)); @@ -298,10 +250,8 @@ public static function withoutQueryValue(UriInterface $uri, $key) * @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]); $result[] = self::generateQueryString($key, $value); @@ -312,42 +262,36 @@ public static function withQueryValue(UriInterface $uri, $key, $value) * * 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 (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)); } /** * Creates a URI from a hash of `parse_url` components. * - * @param array $parts + * @see https://www.php.net/manual/en/function.parse-url.php * - * @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); $uri->validateState(); 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 !== '') { @@ -358,31 +302,31 @@ public function getAuthority() } 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); if ($this->scheme === $scheme) { @@ -390,11 +334,12 @@ public function withScheme($scheme) } $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) { @@ -405,10 +350,11 @@ public function withUserInfo($user, $password = null) } $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); if ($this->host === $host) { @@ -416,10 +362,11 @@ public function withHost($host) } $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); if ($this->port === $port) { @@ -427,11 +374,12 @@ public function withPort($port) } $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); if ($this->path === $path) { @@ -439,10 +387,11 @@ public function withPath($path) } $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); if ($this->query === $query) { @@ -450,9 +399,10 @@ public function withQuery($query) } $new = clone $this; $new->query = $query; + $new->composedComponents = null; return $new; } - public function withFragment($fragment) + public function withFragment($fragment) : UriInterface { $fragment = $this->filterQueryAndFragment($fragment); if ($this->fragment === $fragment) { @@ -460,14 +410,19 @@ public function withFragment($fragment) } $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']) : ''; $this->userInfo = isset($parts['user']) ? $this->filterUserInfoComponent($parts['user']) : ''; @@ -482,13 +437,11 @@ private function applyParts(array $parts) $this->removeDefaultPort(); } /** - * @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'); @@ -496,27 +449,23 @@ private function filterScheme($scheme) return \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); } /** - * @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}))/', [$this, 'rawurlencodeMatchZero'], $component); + return \preg_replace_callback('/(?:[^%' . 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'); @@ -524,13 +473,11 @@ private function filterHost($host) return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); } /** - * @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; @@ -542,40 +489,35 @@ private function filterPort($port) return $port; } /** - * @param UriInterface $uri - * @param array $keys + * @param (string|int)[] $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(); if ($current === '') { return []; } - $decodedKeys = \array_map('rawurldecode', $keys); + $decodedKeys = \array_map(function ($k) : string { + return \rawurldecode((string) $k); + }, $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) + 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; @@ -584,55 +526,47 @@ private function removeDefaultPort() /** * 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}))/', [$this, 'rawurlencodeMatchZero'], $path); + return \preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\\/]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $path); } /** * 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}))/', [$this, 'rawurlencodeMatchZero'], $str); + return \preg_replace_callback('/(?:[^' . 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; } 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'); } } } diff --git a/vendor-prefixed/guzzlehttp/psr7/src/UriComparator.php b/vendor-prefixed/guzzlehttp/psr7/src/UriComparator.php index bfb4ccb..19d06a4 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/UriComparator.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/UriComparator.php @@ -1,5 +1,6 @@ getHost(), $modified->getHost()) !== 0) { return \true; @@ -29,10 +28,7 @@ public static function isCrossOrigin(UriInterface $original, UriInterface $modif } return \false; } - /** - * @return int - */ - private static function computePort(UriInterface $uri) + private static function computePort(UriInterface $uri) : int { $port = $uri->getPort(); if (null !== $port) { diff --git a/vendor-prefixed/guzzlehttp/psr7/src/UriNormalizer.php b/vendor-prefixed/guzzlehttp/psr7/src/UriNormalizer.php index bb07700..ba8e3b3 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/UriNormalizer.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/UriNormalizer.php @@ -1,5 +1,6 @@ withPath(\preg_replace_callback($regex, $callback, $uri->getPath()))->withQuery(\preg_replace_callback($regex, $callback, $uri->getQuery())); } - private static function decodeUnreservedCharacters(UriInterface $uri) + private static function decodeUnreservedCharacters(UriInterface $uri) : UriInterface { $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i'; - $callback = function (array $match) { + $callback = function (array $match) : string { return \rawurldecode($match[0]); }; return $uri->withPath(\preg_replace_callback($regex, $callback, $uri->getPath()))->withQuery(\preg_replace_callback($regex, $callback, $uri->getQuery())); diff --git a/vendor-prefixed/guzzlehttp/psr7/src/UriResolver.php b/vendor-prefixed/guzzlehttp/psr7/src/UriResolver.php index 39a6027..f1b82ee 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/UriResolver.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/UriResolver.php @@ -1,5 +1,6 @@ getScheme() !== '' && ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')) { return $target; @@ -150,12 +137,13 @@ public static function relativize(UriInterface $base, UriInterface $target) // inherit the base query component when resolving. if ($target->getQuery() === '') { $segments = \explode('/', $target->getPath()); + /** @var string $lastSegment */ $lastSegment = \end($segments); return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment); } return $emptyPathUri; } - private static function getRelativePath(UriInterface $base, UriInterface $target) + private static function getRelativePath(UriInterface $base, UriInterface $target) : string { $sourceSegments = \explode('/', $base->getPath()); $targetSegments = \explode('/', $target->getPath()); diff --git a/vendor-prefixed/guzzlehttp/psr7/src/Utils.php b/vendor-prefixed/guzzlehttp/psr7/src/Utils.php index 62578b4..ed8b481 100644 --- a/vendor-prefixed/guzzlehttp/psr7/src/Utils.php +++ b/vendor-prefixed/guzzlehttp/psr7/src/Utils.php @@ -1,5 +1,6 @@ $keys - * - * @return array + * @param (string|int)[] $keys */ - public static function caselessRemove($keys, array $data) + public static function caselessRemove(array $keys, array $data) : array { $result = []; foreach ($keys as &$key) { - $key = \strtolower($key); + $key = \strtolower((string) $key); } foreach ($data as $k => $v) { - if (!\in_array(\strtolower($k), $keys)) { + if (!\in_array(\strtolower((string) $k), $keys)) { $result[$k] = $v; } } @@ -39,7 +38,7 @@ public static function caselessRemove($keys, array $data) * * @throws \RuntimeException on error. */ - public static function copyToStream(StreamInterface $source, StreamInterface $dest, $maxLen = -1) + public static function copyToStream(StreamInterface $source, StreamInterface $dest, int $maxLen = -1) : void { $bufferSize = 8192; if ($maxLen === -1) { @@ -69,18 +68,15 @@ public static function copyToStream(StreamInterface $source, StreamInterface $de * @param int $maxLen Maximum number of bytes to read. Pass -1 * to read the entire stream. * - * @return string - * * @throws \RuntimeException on error. */ - public static function copyToString(StreamInterface $stream, $maxLen = -1) + public static function copyToString(StreamInterface $stream, int $maxLen = -1) : string { $buffer = ''; if ($maxLen === -1) { while (!$stream->eof()) { $buf = $stream->read(1048576); - // Using a loose equality here to match on '' and false. - if ($buf == null) { + if ($buf === '') { break; } $buffer .= $buf; @@ -90,8 +86,7 @@ public static function copyToString(StreamInterface $stream, $maxLen = -1) $len = 0; while (!$stream->eof() && $len < $maxLen) { $buf = $stream->read($maxLen - $len); - // Using a loose equality here to match on '' and false. - if ($buf == null) { + if ($buf === '') { break; } $buffer .= $buf; @@ -109,11 +104,9 @@ public static function copyToString(StreamInterface $stream, $maxLen = -1) * @param string $algo Hash algorithm (e.g. md5, crc32, etc) * @param bool $rawOutput Whether or not to use raw output * - * @return string Returns the hash of the stream - * * @throws \RuntimeException on error. */ - public static function hash(StreamInterface $stream, $algo, $rawOutput = \false) + public static function hash(StreamInterface $stream, string $algo, bool $rawOutput = \false) : string { $pos = $stream->tell(); if ($pos > 0) { @@ -123,7 +116,7 @@ public static function hash(StreamInterface $stream, $algo, $rawOutput = \false) while (!$stream->eof()) { \hash_update($ctx, $stream->read(1048576)); } - $out = \hash_final($ctx, (bool) $rawOutput); + $out = \hash_final($ctx, $rawOutput); $stream->seek($pos); return $out; } @@ -144,10 +137,8 @@ public static function hash(StreamInterface $stream, $algo, $rawOutput = \false) * * @param RequestInterface $request Request to clone and modify. * @param array $changes Changes to apply. - * - * @return RequestInterface */ - public static function modifyRequest(RequestInterface $request, array $changes) + public static function modifyRequest(RequestInterface $request, array $changes) : RequestInterface { if (!$changes) { return $request; @@ -180,29 +171,26 @@ public static function modifyRequest(RequestInterface $request, array $changes) $uri = $uri->withQuery($changes['query']); } if ($request instanceof ServerRequestInterface) { - $new = (new ServerRequest(isset($changes['method']) ? $changes['method'] : $request->getMethod(), $uri, $headers, isset($changes['body']) ? $changes['body'] : $request->getBody(), isset($changes['version']) ? $changes['version'] : $request->getProtocolVersion(), $request->getServerParams()))->withParsedBody($request->getParsedBody())->withQueryParams($request->getQueryParams())->withCookieParams($request->getCookieParams())->withUploadedFiles($request->getUploadedFiles()); + $new = (new ServerRequest($changes['method'] ?? $request->getMethod(), $uri, $headers, $changes['body'] ?? $request->getBody(), $changes['version'] ?? $request->getProtocolVersion(), $request->getServerParams()))->withParsedBody($request->getParsedBody())->withQueryParams($request->getQueryParams())->withCookieParams($request->getCookieParams())->withUploadedFiles($request->getUploadedFiles()); foreach ($request->getAttributes() as $key => $value) { $new = $new->withAttribute($key, $value); } return $new; } - return new Request(isset($changes['method']) ? $changes['method'] : $request->getMethod(), $uri, $headers, isset($changes['body']) ? $changes['body'] : $request->getBody(), isset($changes['version']) ? $changes['version'] : $request->getProtocolVersion()); + return new Request($changes['method'] ?? $request->getMethod(), $uri, $headers, $changes['body'] ?? $request->getBody(), $changes['version'] ?? $request->getProtocolVersion()); } /** * Read a line from the stream up to the maximum allowed buffer length. * * @param StreamInterface $stream Stream to read from * @param int|null $maxLength Maximum buffer length - * - * @return string */ - public static function readLine(StreamInterface $stream, $maxLength = null) + public static function readLine(StreamInterface $stream, ?int $maxLength = null) : string { $buffer = ''; $size = 0; while (!$stream->eof()) { - // Using a loose equality here to match on '' and false. - if (null == ($byte = $stream->read(1))) { + if ('' === ($byte = $stream->read(1))) { return $buffer; } $buffer .= $byte; @@ -213,6 +201,17 @@ public static function readLine(StreamInterface $stream, $maxLength = null) } return $buffer; } + /** + * Redact the password in the user info part of a URI. + */ + public static function redactUserInfo(UriInterface $uri) : UriInterface + { + $userInfo = $uri->getUserInfo(); + if (\false !== ($pos = \strpos($userInfo, ':'))) { + return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***'); + } + return $uri; + } /** * Create a new stream based on the input type. * @@ -243,18 +242,16 @@ public static function readLine(StreamInterface $stream, $maxLength = null) * buffered and used in subsequent reads. * * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data - * @param array $options Additional options - * - * @return StreamInterface + * @param array{size?: int, metadata?: array} $options Additional options * * @throws \InvalidArgumentException if the $resource arg is not valid. */ - public static function streamFor($resource = '', array $options = []) + public static function streamFor($resource = '', array $options = []) : StreamInterface { if (\is_scalar($resource)) { $stream = self::tryFopen('php://temp', 'r+'); if ($resource !== '') { - \fwrite($stream, $resource); + \fwrite($stream, (string) $resource); \fseek($stream, 0); } return new Stream($stream, $options); @@ -265,15 +262,16 @@ public static function streamFor($resource = '', array $options = []) * The 'php://input' is a special stream with quirks and inconsistencies. * We avoid using that stream by reading it into php://temp */ - $metaData = \stream_get_meta_data($resource); - if (isset($metaData['uri']) && $metaData['uri'] === 'php://input') { + /** @var resource $resource */ + if ((\stream_get_meta_data($resource)['uri'] ?? '') === 'php://input') { $stream = self::tryFopen('php://temp', 'w+'); - \fwrite($stream, \stream_get_contents($resource)); + \stream_copy_to_stream($resource, $stream); \fseek($stream, 0); $resource = $stream; } return new Stream($resource, $options); case 'object': + /** @var object $resource */ if ($resource instanceof StreamInterface) { return $resource; } elseif ($resource instanceof \Iterator) { @@ -286,7 +284,7 @@ public static function streamFor($resource = '', array $options = []) return $result; }, $options); } elseif (\method_exists($resource, '__toString')) { - return Utils::streamFor((string) $resource, $options); + return self::streamFor((string) $resource, $options); } break; case 'NULL': @@ -310,25 +308,60 @@ public static function streamFor($resource = '', array $options = []) * * @throws \RuntimeException if the file cannot be opened */ - public static function tryFopen($filename, $mode) + public static function tryFopen(string $filename, string $mode) { $ex = null; - \set_error_handler(function () use($filename, $mode, &$ex) { - $ex = new \RuntimeException(\sprintf('Unable to open "%s" using mode "%s": %s', $filename, $mode, \func_get_args()[1])); + \set_error_handler(static function (int $errno, string $errstr) use($filename, $mode, &$ex) : bool { + $ex = new \RuntimeException(\sprintf('Unable to open "%s" using mode "%s": %s', $filename, $mode, $errstr)); return \true; }); try { + /** @var resource $handle */ $handle = \fopen($filename, $mode); } catch (\Throwable $e) { $ex = new \RuntimeException(\sprintf('Unable to open "%s" using mode "%s": %s', $filename, $mode, $e->getMessage()), 0, $e); } \restore_error_handler(); if ($ex) { - /** @var $ex \RuntimeException */ + /** @var \RuntimeException $ex */ throw $ex; } return $handle; } + /** + * Safely gets the contents of a given stream. + * + * When stream_get_contents fails, PHP normally raises a warning. This + * function adds an error handler that checks for errors and throws an + * exception instead. + * + * @param resource $stream + * + * @throws \RuntimeException if the stream cannot be read + */ + public static function tryGetContents($stream) : string + { + $ex = null; + \set_error_handler(static function (int $errno, string $errstr) use(&$ex) : bool { + $ex = new \RuntimeException(\sprintf('Unable to read stream contents: %s', $errstr)); + return \true; + }); + try { + /** @var string|false $contents */ + $contents = \stream_get_contents($stream); + if ($contents === \false) { + $ex = new \RuntimeException('Unable to read stream contents'); + } + } catch (\Throwable $e) { + $ex = new \RuntimeException(\sprintf('Unable to read stream contents: %s', $e->getMessage()), 0, $e); + } + \restore_error_handler(); + if ($ex) { + /** @var \RuntimeException $ex */ + throw $ex; + } + return $contents; + } /** * Returns a UriInterface for the given value. * @@ -338,11 +371,9 @@ public static function tryFopen($filename, $mode) * * @param string|UriInterface $uri * - * @return UriInterface - * * @throws \InvalidArgumentException */ - public static function uriFor($uri) + public static function uriFor($uri) : UriInterface { if ($uri instanceof UriInterface) { return $uri; diff --git a/vendor-prefixed/guzzlehttp/psr7/src/functions.php b/vendor-prefixed/guzzlehttp/psr7/src/functions.php deleted file mode 100644 index fd23b72..0000000 --- a/vendor-prefixed/guzzlehttp/psr7/src/functions.php +++ /dev/null @@ -1,400 +0,0 @@ - '1', 'foo[b]' => '2'])`. - * - * @param string $str Query string to parse - * @param int|bool $urlEncoding How the query string is encoded - * - * @return array - * - * @deprecated parse_query will be removed in guzzlehttp/psr7:2.0. Use Query::parse instead. - */ -function parse_query($str, $urlEncoding = \true) -{ - return Query::parse($str, $urlEncoding); -} -/** - * Build a query string from an array of key value pairs. - * - * This function can use the return value of `parse_query()` to build a query - * string. This function does not modify the provided keys when an array is - * encountered (like `http_build_query()` would). - * - * @param array $params Query string parameters. - * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986 - * to encode using RFC3986, or PHP_QUERY_RFC1738 - * to encode using RFC1738. - * - * @return string - * - * @deprecated build_query will be removed in guzzlehttp/psr7:2.0. Use Query::build instead. - */ -function build_query(array $params, $encoding = \PHP_QUERY_RFC3986) -{ - return Query::build($params, $encoding); -} -/** - * Determines the mimetype of a file by looking at its extension. - * - * @param string $filename - * - * @return string|null - * - * @deprecated mimetype_from_filename will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromFilename instead. - */ -function mimetype_from_filename($filename) -{ - return MimeType::fromFilename($filename); -} -/** - * Maps a file extensions to a mimetype. - * - * @param $extension string The file extension. - * - * @return string|null - * - * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types - * @deprecated mimetype_from_extension will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromExtension instead. - */ -function mimetype_from_extension($extension) -{ - return MimeType::fromExtension($extension); -} -/** - * Parses an HTTP message into an associative array. - * - * The array contains the "start-line" key containing the start line of - * the message, "headers" key containing an associative array of header - * array values, and a "body" key containing the body of the message. - * - * @param string $message HTTP request or response to parse. - * - * @return array - * - * @internal - * - * @deprecated _parse_message will be removed in guzzlehttp/psr7:2.0. Use Message::parseMessage instead. - */ -function _parse_message($message) -{ - return Message::parseMessage($message); -} -/** - * Constructs a URI for an HTTP request message. - * - * @param string $path Path from the start-line - * @param array $headers Array of headers (each value an array). - * - * @return string - * - * @internal - * - * @deprecated _parse_request_uri will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequestUri instead. - */ -function _parse_request_uri($path, array $headers) -{ - return Message::parseRequestUri($path, $headers); -} -/** - * 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 string|null - * - * @deprecated get_message_body_summary will be removed in guzzlehttp/psr7:2.0. Use Message::bodySummary instead. - */ -function get_message_body_summary(MessageInterface $message, $truncateAt = 120) -{ - return Message::bodySummary($message, $truncateAt); -} -/** - * Remove the items given by the keys, case insensitively from the data. - * - * @param iterable $keys - * - * @return array - * - * @internal - * - * @deprecated _caseless_remove will be removed in guzzlehttp/psr7:2.0. Use Utils::caselessRemove instead. - */ -function _caseless_remove($keys, array $data) -{ - return Utils::caselessRemove($keys, $data); -} diff --git a/vendor-prefixed/guzzlehttp/psr7/src/functions_include.php b/vendor-prefixed/guzzlehttp/psr7/src/functions_include.php deleted file mode 100644 index 238cb99..0000000 --- a/vendor-prefixed/guzzlehttp/psr7/src/functions_include.php +++ /dev/null @@ -1,8 +0,0 @@ -=7.1", + "psr\/http-message": "^1.0 || ^2.0" + }, + "autoload": { + "psr-4": { + "Dekode\\GravityForms\\Vendor\\Psr\\Http\\Message\\": "src\/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} \ No newline at end of file diff --git a/vendor-prefixed/psr/http-factory/src/RequestFactoryInterface.php b/vendor-prefixed/psr/http-factory/src/RequestFactoryInterface.php new file mode 100644 index 0000000..57d93e1 --- /dev/null +++ b/vendor-prefixed/psr/http-factory/src/RequestFactoryInterface.php @@ -0,0 +1,18 @@ +