update niucloud

This commit is contained in:
全栈小学生 2023-08-12 16:08:19 +08:00
parent 00f6383d37
commit 3b14c33e5d
42 changed files with 451 additions and 243 deletions

View File

@ -8,5 +8,4 @@ $baseDir = dirname($vendorDir);
return array( return array(
'Pimple' => array($vendorDir . '/pimple/pimple/src'), 'Pimple' => array($vendorDir . '/pimple/pimple/src'),
'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'), 'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
'' => array($baseDir . '/extend'),
); );

View File

@ -486,10 +486,6 @@ class ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e
), ),
); );
public static $fallbackDirsPsr0 = array (
0 => __DIR__ . '/../..' . '/extend',
);
public static $classMap = array ( public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
@ -508,7 +504,6 @@ class ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e
$loader->prefixLengthsPsr4 = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$prefixLengthsPsr4; $loader->prefixLengthsPsr4 = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$prefixDirsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$prefixesPsr0; $loader->prefixesPsr0 = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$prefixesPsr0;
$loader->fallbackDirsPsr0 = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$fallbackDirsPsr0;
$loader->classMap = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$classMap; $loader->classMap = ComposerStaticInitf082efa3600aae2b847c3e8b4e641a4e::$classMap;
}, null, ClassLoader::class); }, null, ClassLoader::class);

View File

@ -1032,17 +1032,17 @@
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.5.0", "version": "2.6.0",
"version_normalized": "2.5.0.0", "version_normalized": "2.6.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "b635f279edd83fc275f822a1188157ffea568ff6" "reference": "8bd7c33a0734ae1c5d074360512beb716bef3f77"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", "url": "https://api.github.com/repos/guzzle/psr7/zipball/8bd7c33a0734ae1c5d074360512beb716bef3f77",
"reference": "b635f279edd83fc275f822a1188157ffea568ff6", "reference": "8bd7c33a0734ae1c5d074360512beb716bef3f77",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1069,7 +1069,7 @@
"suggest": { "suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
}, },
"time": "2023-04-17T16:11:26+00:00", "time": "2023-08-03T15:06:02+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"bamarni-bin": { "bamarni-bin": {
@ -1137,7 +1137,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.5.0" "source": "https://github.com/guzzle/psr7/tree/2.6.0"
}, },
"funding": [ "funding": [
{ {
@ -1398,17 +1398,17 @@
}, },
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
"version": "v1.2.2", "version": "v1.3.1",
"version_normalized": "1.2.2.0", "version_normalized": "1.3.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/serializable-closure.git", "url": "https://github.com/laravel/serializable-closure.git",
"reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae" "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/47afb7fae28ed29057fdca37e16a84f90cc62fae", "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/e5a3057a5591e1cfe8183034b0203921abe2c902",
"reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae", "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1426,7 +1426,7 @@
"phpstan/phpstan": "^1.8.2", "phpstan/phpstan": "^1.8.2",
"symfony/var-dumper": "^5.4.11" "symfony/var-dumper": "^5.4.11"
}, },
"time": "2022-09-08T13:45:54+00:00", "time": "2023-07-14T13:56:28+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@ -1679,17 +1679,17 @@
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "2.9.0", "version": "2.9.1",
"version_normalized": "2.9.0.0", "version_normalized": "2.9.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Seldaek/monolog.git", "url": "https://github.com/Seldaek/monolog.git",
"reference": "e1c0ae1528ce313a450e5e1ad782765c4a8dd3cb" "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/e1c0ae1528ce313a450e5e1ad782765c4a8dd3cb", "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
"reference": "e1c0ae1528ce313a450e5e1ad782765c4a8dd3cb", "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -1741,7 +1741,7 @@
"rollbar/rollbar": "Allow sending log messages to Rollbar", "rollbar/rollbar": "Allow sending log messages to Rollbar",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server" "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
}, },
"time": "2023-02-05T13:07:32+00:00", "time": "2023-02-06T13:44:46+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@ -1774,7 +1774,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/Seldaek/monolog/issues", "issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/2.9.0" "source": "https://github.com/Seldaek/monolog/tree/2.9.1"
}, },
"funding": [ "funding": [
{ {
@ -2040,17 +2040,17 @@
}, },
{ {
"name": "overtrue/socialite", "name": "overtrue/socialite",
"version": "4.8.0", "version": "4.8.1",
"version_normalized": "4.8.0.0", "version_normalized": "4.8.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/overtrue/socialite.git", "url": "https://github.com/overtrue/socialite.git",
"reference": "e55fdf50f8003be8f03a85a7e5a5b7c5716f4c9a" "reference": "470b781f288fbb24c8b105cfdada215d83d84d4b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/overtrue/socialite/zipball/e55fdf50f8003be8f03a85a7e5a5b7c5716f4c9a", "url": "https://api.github.com/repos/overtrue/socialite/zipball/470b781f288fbb24c8b105cfdada215d83d84d4b",
"reference": "e55fdf50f8003be8f03a85a7e5a5b7c5716f4c9a", "reference": "470b781f288fbb24c8b105cfdada215d83d84d4b",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -2074,7 +2074,7 @@
"phpstan/phpstan": "^1.7", "phpstan/phpstan": "^1.7",
"phpunit/phpunit": "^9.0" "phpunit/phpunit": "^9.0"
}, },
"time": "2023-01-10T14:29:55+00:00", "time": "2023-07-17T08:56:49+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -2110,7 +2110,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/overtrue/socialite/issues", "issues": "https://github.com/overtrue/socialite/issues",
"source": "https://github.com/overtrue/socialite/tree/4.8.0" "source": "https://github.com/overtrue/socialite/tree/4.8.1"
}, },
"funding": [ "funding": [
{ {
@ -3369,17 +3369,17 @@
}, },
{ {
"name": "symfony/cache", "name": "symfony/cache",
"version": "v5.4.23", "version": "v5.4.25",
"version_normalized": "5.4.23.0", "version_normalized": "5.4.25.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/cache.git", "url": "https://github.com/symfony/cache.git",
"reference": "983c79ff28612cdfd66d8e44e1a06e5afc87e107" "reference": "e2013521c0f07473ae69a01fce0af78fc3ec0f23"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/983c79ff28612cdfd66d8e44e1a06e5afc87e107", "url": "https://api.github.com/repos/symfony/cache/zipball/e2013521c0f07473ae69a01fce0af78fc3ec0f23",
"reference": "983c79ff28612cdfd66d8e44e1a06e5afc87e107", "reference": "e2013521c0f07473ae69a01fce0af78fc3ec0f23",
"shasum": "", "shasum": "",
"mirrors": [ "mirrors": [
{ {
@ -3423,7 +3423,7 @@
"symfony/messenger": "^4.4|^5.0|^6.0", "symfony/messenger": "^4.4|^5.0|^6.0",
"symfony/var-dumper": "^4.4|^5.0|^6.0" "symfony/var-dumper": "^4.4|^5.0|^6.0"
}, },
"time": "2023-04-21T15:38:51+00:00", "time": "2023-06-22T08:06:06+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -3455,7 +3455,7 @@
"psr6" "psr6"
], ],
"support": { "support": {
"source": "https://github.com/symfony/cache/tree/v5.4.23" "source": "https://github.com/symfony/cache/tree/v5.4.25"
}, },
"funding": [ "funding": [
{ {

View File

@ -3,7 +3,7 @@
'name' => 'topthink/think', 'name' => 'topthink/think',
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'reference' => 'bdc0c0b0594f0eff6e5ca8d8018f125190f8ee95', 'reference' => '46cb9e59a82446565af26a097aa185067c614ce4',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
@ -137,9 +137,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/psr7' => array( 'guzzlehttp/psr7' => array(
'pretty_version' => '2.5.0', 'pretty_version' => '2.6.0',
'version' => '2.5.0.0', 'version' => '2.6.0.0',
'reference' => 'b635f279edd83fc275f822a1188157ffea568ff6', 'reference' => '8bd7c33a0734ae1c5d074360512beb716bef3f77',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(), 'aliases' => array(),
@ -175,9 +175,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'laravel/serializable-closure' => array( 'laravel/serializable-closure' => array(
'pretty_version' => 'v1.2.2', 'pretty_version' => 'v1.3.1',
'version' => '1.2.2.0', 'version' => '1.3.1.0',
'reference' => '47afb7fae28ed29057fdca37e16a84f90cc62fae', 'reference' => 'e5a3057a5591e1cfe8183034b0203921abe2c902',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../laravel/serializable-closure', 'install_path' => __DIR__ . '/../laravel/serializable-closure',
'aliases' => array(), 'aliases' => array(),
@ -211,9 +211,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'monolog/monolog' => array( 'monolog/monolog' => array(
'pretty_version' => '2.9.0', 'pretty_version' => '2.9.1',
'version' => '2.9.0.0', 'version' => '2.9.1.0',
'reference' => 'e1c0ae1528ce313a450e5e1ad782765c4a8dd3cb', 'reference' => 'f259e2b15fb95494c83f52d3caad003bbf5ffaa1',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../monolog/monolog', 'install_path' => __DIR__ . '/../monolog/monolog',
'aliases' => array(), 'aliases' => array(),
@ -253,9 +253,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'overtrue/socialite' => array( 'overtrue/socialite' => array(
'pretty_version' => '4.8.0', 'pretty_version' => '4.8.1',
'version' => '4.8.0.0', 'version' => '4.8.1.0',
'reference' => 'e55fdf50f8003be8f03a85a7e5a5b7c5716f4c9a', 'reference' => '470b781f288fbb24c8b105cfdada215d83d84d4b',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../overtrue/socialite', 'install_path' => __DIR__ . '/../overtrue/socialite',
'aliases' => array(), 'aliases' => array(),
@ -472,9 +472,9 @@
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/cache' => array( 'symfony/cache' => array(
'pretty_version' => 'v5.4.23', 'pretty_version' => 'v5.4.25',
'version' => '5.4.23.0', 'version' => '5.4.25.0',
'reference' => '983c79ff28612cdfd66d8e44e1a06e5afc87e107', 'reference' => 'e2013521c0f07473ae69a01fce0af78fc3ec0f23',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache', 'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(), 'aliases' => array(),
@ -663,7 +663,7 @@
'topthink/think' => array( 'topthink/think' => array(
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'reference' => 'bdc0c0b0594f0eff6e5ca8d8018f125190f8ee95', 'reference' => '46cb9e59a82446565af26a097aa185067c614ce4',
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),

View File

@ -5,7 +5,22 @@ 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/) 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased ## 2.6.0 - 2023-08-03
### 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 ## 2.5.0 - 2023-04-17

View File

@ -8,16 +8,24 @@ functionality like query string parsing.
![Static analysis](https://github.com/guzzle/psr7/workflows/Static%20analysis/badge.svg) ![Static analysis](https://github.com/guzzle/psr7/workflows/Static%20analysis/badge.svg)
# Installation ## Features
This package comes with a number of stream implementations and stream
decorators.
## Installation
```shell ```shell
composer require guzzlehttp/psr7 composer require guzzlehttp/psr7
``` ```
# Stream implementation ## Version Guidance
This package comes with a number of stream implementations and stream | Version | Status | PHP Version |
decorators. |---------|---------------------|--------------|
| 1.x | Security fixes only | >=5.4,<8.1 |
| 2.x | Latest | >=7.2.5,<8.4 |
## AppendStream ## AppendStream
@ -855,14 +863,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. 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 ## 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. 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.

View File

@ -40,12 +40,14 @@ final class AppendStream implements StreamInterface
{ {
try { try {
$this->rewind(); $this->rewind();
return $this->getContents(); return $this->getContents();
} catch (\Throwable $e) { } catch (\Throwable $e) {
if (\PHP_VERSION_ID >= 70400) { if (\PHP_VERSION_ID >= 70400) {
throw $e; throw $e;
} }
trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR); trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);
return ''; return '';
} }
} }
@ -167,7 +169,7 @@ final class AppendStream implements StreamInterface
$stream->rewind(); $stream->rewind();
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \RuntimeException('Unable to seek stream ' throw new \RuntimeException('Unable to seek stream '
. $i . ' of the AppendStream', 0, $e); .$i.' of the AppendStream', 0, $e);
} }
} }
@ -197,7 +199,7 @@ final class AppendStream implements StreamInterface
if ($this->current === $total) { if ($this->current === $total) {
break; break;
} }
$this->current++; ++$this->current;
} }
$result = $this->streams[$this->current]->read($remaining); $result = $this->streams[$this->current]->read($remaining);

View File

@ -18,7 +18,7 @@ final class FnStream implements StreamInterface
private const SLOTS = [ private const SLOTS = [
'__toString', 'close', 'detach', 'rewind', '__toString', 'close', 'detach', 'rewind',
'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write', 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
'isReadable', 'read', 'getContents', 'getMetadata' 'isReadable', 'read', 'getContents', 'getMetadata',
]; ];
/** @var array<string, callable> */ /** @var array<string, callable> */
@ -33,7 +33,7 @@ final class FnStream implements StreamInterface
// Create the functions on the class // Create the functions on the class
foreach ($methods as $name => $fn) { foreach ($methods as $name => $fn) {
$this->{'_fn_' . $name} = $fn; $this->{'_fn_'.$name} = $fn;
} }
} }
@ -45,7 +45,7 @@ final class FnStream implements StreamInterface
public function __get(string $name): void public function __get(string $name): void
{ {
throw new \BadMethodCallException(str_replace('_fn_', '', $name) throw new \BadMethodCallException(str_replace('_fn_', '', $name)
. '() is not implemented in the FnStream'); .'() is not implemented in the FnStream');
} }
/** /**
@ -99,6 +99,7 @@ final class FnStream implements StreamInterface
throw $e; throw $e;
} }
trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR); trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);
return ''; return '';
} }
} }

View File

@ -89,7 +89,7 @@ final class Header
$v = ''; $v = '';
$isQuoted = false; $isQuoted = false;
$isEscaped = false; $isEscaped = false;
for ($i = 0, $max = \strlen($value); $i < $max; $i++) { for ($i = 0, $max = \strlen($value); $i < $max; ++$i) {
if ($isEscaped) { if ($isEscaped) {
$v .= $value[$i]; $v .= $value[$i];
$isEscaped = false; $isEscaped = false;

View File

@ -23,13 +23,7 @@ use Psr\Http\Message\UriInterface;
* Note: in consuming code it is recommended to require the implemented interfaces * Note: in consuming code it is recommended to require the implemented interfaces
* and inject the instance of this class multiple times. * and inject the instance of this class multiple times.
*/ */
final class HttpFactory implements final class HttpFactory implements RequestFactoryInterface, ResponseFactoryInterface, ServerRequestFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, UriFactoryInterface
RequestFactoryInterface,
ResponseFactoryInterface,
ServerRequestFactoryInterface,
StreamFactoryInterface,
UploadedFileFactoryInterface,
UriFactoryInterface
{ {
public function createUploadedFile( public function createUploadedFile(
StreamInterface $stream, StreamInterface $stream,

View File

@ -13,9 +13,9 @@ use Psr\Http\Message\StreamInterface;
* then appends the zlib.inflate filter. The stream is then converted back * then appends the zlib.inflate filter. The stream is then converted back
* to a Guzzle stream resource to be used as a Guzzle stream. * to a Guzzle stream resource to be used as a Guzzle stream.
* *
* @link http://tools.ietf.org/html/rfc1950 * @see http://tools.ietf.org/html/rfc1950
* @link http://tools.ietf.org/html/rfc1952 * @see http://tools.ietf.org/html/rfc1952
* @link http://php.net/manual/en/filters.compression.php * @see http://php.net/manual/en/filters.compression.php
*/ */
final class InflateStream implements StreamInterface final class InflateStream implements StreamInterface
{ {

View File

@ -18,16 +18,16 @@ final class Message
public static function toString(MessageInterface $message): string public static function toString(MessageInterface $message): string
{ {
if ($message instanceof RequestInterface) { if ($message instanceof RequestInterface) {
$msg = trim($message->getMethod() . ' ' $msg = trim($message->getMethod().' '
. $message->getRequestTarget()) .$message->getRequestTarget())
. ' HTTP/' . $message->getProtocolVersion(); .' HTTP/'.$message->getProtocolVersion();
if (!$message->hasHeader('host')) { if (!$message->hasHeader('host')) {
$msg .= "\r\nHost: " . $message->getUri()->getHost(); $msg .= "\r\nHost: ".$message->getUri()->getHost();
} }
} elseif ($message instanceof ResponseInterface) { } elseif ($message instanceof ResponseInterface) {
$msg = 'HTTP/' . $message->getProtocolVersion() . ' ' $msg = 'HTTP/'.$message->getProtocolVersion().' '
. $message->getStatusCode() . ' ' .$message->getStatusCode().' '
. $message->getReasonPhrase(); .$message->getReasonPhrase();
} else { } else {
throw new \InvalidArgumentException('Unknown message type'); throw new \InvalidArgumentException('Unknown message type');
} }
@ -35,14 +35,14 @@ final class Message
foreach ($message->getHeaders() as $name => $values) { foreach ($message->getHeaders() as $name => $values) {
if (strtolower($name) === 'set-cookie') { if (strtolower($name) === 'set-cookie') {
foreach ($values as $value) { foreach ($values as $value) {
$msg .= "\r\n{$name}: " . $value; $msg .= "\r\n{$name}: ".$value;
} }
} else { } else {
$msg .= "\r\n{$name}: " . implode(', ', $values); $msg .= "\r\n{$name}: ".implode(', ', $values);
} }
} }
return "{$msg}\r\n\r\n" . $message->getBody(); return "{$msg}\r\n\r\n".$message->getBody();
} }
/** /**
@ -190,7 +190,7 @@ final class Message
$host = $headers[reset($hostKey)][0]; $host = $headers[reset($hostKey)][0];
$scheme = substr($host, -4) === ':443' ? 'https' : 'http'; $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
return $scheme . '://' . $host . '/' . ltrim($path, '/'); return $scheme.'://'.$host.'/'.ltrim($path, '/');
} }
/** /**
@ -231,7 +231,7 @@ final class Message
// between status-code and reason-phrase is required. But browsers accept // between status-code and reason-phrase is required. But browsers accept
// responses without space and reason as well. // responses without space and reason as well.
if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) { if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']); throw new \InvalidArgumentException('Invalid response string: '.$data['start-line']);
} }
$parts = explode(' ', $data['start-line'], 3); $parts = explode(' ', $data['start-line'], 3);

View File

@ -16,7 +16,7 @@ trait MessageTrait
private $headers = []; private $headers = [];
/** @var array<string, string> Map of lowercase header name => original name at registration */ /** @var array<string, string> Map of lowercase header name => original name at registration */
private $headerNames = []; private $headerNames = [];
/** @var string */ /** @var string */
private $protocol = '1.1'; private $protocol = '1.1';
@ -37,6 +37,7 @@ trait MessageTrait
$new = clone $this; $new = clone $this;
$new->protocol = $version; $new->protocol = $version;
return $new; return $new;
} }
@ -135,6 +136,7 @@ trait MessageTrait
$new = clone $this; $new = clone $this;
$new->stream = $body; $new->stream = $body;
return $new; return $new;
} }
@ -224,7 +226,7 @@ trait MessageTrait
)); ));
} }
if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) { if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
sprintf('"%s" is not valid header name.', $header) sprintf('"%s" is not valid header name.', $header)
); );
@ -254,7 +256,7 @@ trait MessageTrait
// Clients must not send a request with line folding and a server sending folded headers is // Clients must not send a request with line folding and a server sending folded headers is
// likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting
// folding is not likely to break any legitimate use case. // folding is not likely to break any legitimate use case.
if (! preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D', $value)) { if (!preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D', $value)) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
sprintf('"%s" is not valid header value.', $value) sprintf('"%s" is not valid header value.', $value)
); );

View File

@ -18,7 +18,7 @@ final class MimeType
'7zip' => 'application/x-7z-compressed', '7zip' => 'application/x-7z-compressed',
'123' => 'application/vnd.lotus-1-2-3', '123' => 'application/vnd.lotus-1-2-3',
'aab' => 'application/x-authorware-bin', 'aab' => 'application/x-authorware-bin',
'aac' => 'audio/x-acc', 'aac' => 'audio/aac',
'aam' => 'application/x-authorware-map', 'aam' => 'application/x-authorware-map',
'aas' => 'application/x-authorware-seg', 'aas' => 'application/x-authorware-seg',
'abw' => 'application/x-abiword', 'abw' => 'application/x-abiword',
@ -29,6 +29,7 @@ final class MimeType
'acu' => 'application/vnd.acucobol', 'acu' => 'application/vnd.acucobol',
'acutc' => 'application/vnd.acucorp', 'acutc' => 'application/vnd.acucorp',
'adp' => 'audio/adpcm', 'adp' => 'audio/adpcm',
'adts' => 'audio/aac',
'aep' => 'application/vnd.audiograph', 'aep' => 'application/vnd.audiograph',
'afm' => 'application/x-font-type1', 'afm' => 'application/x-font-type1',
'afp' => 'application/vnd.ibm.modcap', 'afp' => 'application/vnd.ibm.modcap',
@ -41,11 +42,16 @@ final class MimeType
'air' => 'application/vnd.adobe.air-application-installer-package+zip', 'air' => 'application/vnd.adobe.air-application-installer-package+zip',
'ait' => 'application/vnd.dvb.ait', 'ait' => 'application/vnd.dvb.ait',
'ami' => 'application/vnd.amiga.ami', 'ami' => 'application/vnd.amiga.ami',
'aml' => 'application/automationml-aml+xml',
'amlx' => 'application/automationml-amlx+zip',
'amr' => 'audio/amr', 'amr' => 'audio/amr',
'apk' => 'application/vnd.android.package-archive', 'apk' => 'application/vnd.android.package-archive',
'apng' => 'image/apng', 'apng' => 'image/apng',
'appcache' => 'text/cache-manifest', 'appcache' => 'text/cache-manifest',
'appinstaller' => 'application/appinstaller',
'application' => 'application/x-ms-application', 'application' => 'application/x-ms-application',
'appx' => 'application/appx',
'appxbundle' => 'application/appxbundle',
'apr' => 'application/vnd.lotus-approach', 'apr' => 'application/vnd.lotus-approach',
'arc' => 'application/x-freearc', 'arc' => 'application/x-freearc',
'arj' => 'application/x-arj', 'arj' => 'application/x-arj',
@ -90,6 +96,7 @@ final class MimeType
'bpk' => 'application/octet-stream', 'bpk' => 'application/octet-stream',
'bpmn' => 'application/octet-stream', 'bpmn' => 'application/octet-stream',
'bsp' => 'model/vnd.valve.source.compiled-map', 'bsp' => 'model/vnd.valve.source.compiled-map',
'btf' => 'image/prs.btif',
'btif' => 'image/prs.btif', 'btif' => 'image/prs.btif',
'buffer' => 'application/octet-stream', 'buffer' => 'application/octet-stream',
'bz' => 'application/x-bzip', 'bz' => 'application/x-bzip',
@ -141,6 +148,7 @@ final class MimeType
'cjs' => 'application/node', 'cjs' => 'application/node',
'cla' => 'application/vnd.claymore', 'cla' => 'application/vnd.claymore',
'class' => 'application/octet-stream', 'class' => 'application/octet-stream',
'cld' => 'model/vnd.cld',
'clkk' => 'application/vnd.crick.clicker.keyboard', 'clkk' => 'application/vnd.crick.clicker.keyboard',
'clkp' => 'application/vnd.crick.clicker.palette', 'clkp' => 'application/vnd.crick.clicker.palette',
'clkt' => 'application/vnd.crick.clicker.template', 'clkt' => 'application/vnd.crick.clicker.template',
@ -175,6 +183,7 @@ final class MimeType
'csv' => 'text/csv', 'csv' => 'text/csv',
'cu' => 'application/cu-seeme', 'cu' => 'application/cu-seeme',
'curl' => 'text/vnd.curl', 'curl' => 'text/vnd.curl',
'cwl' => 'application/cwl',
'cww' => 'application/prs.cww', 'cww' => 'application/prs.cww',
'cxt' => 'application/x-director', 'cxt' => 'application/x-director',
'cxx' => 'text/x-c', 'cxx' => 'text/x-c',
@ -197,6 +206,7 @@ final class MimeType
'der' => 'application/x-x509-ca-cert', 'der' => 'application/x-x509-ca-cert',
'dfac' => 'application/vnd.dreamfactory', 'dfac' => 'application/vnd.dreamfactory',
'dgc' => 'application/x-dgc-compressed', 'dgc' => 'application/x-dgc-compressed',
'dib' => 'image/bmp',
'dic' => 'text/x-c', 'dic' => 'text/x-c',
'dir' => 'application/x-director', 'dir' => 'application/x-director',
'dis' => 'application/vnd.mobius.dis', 'dis' => 'application/vnd.mobius.dis',
@ -219,6 +229,7 @@ final class MimeType
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'dp' => 'application/vnd.osgi.dp', 'dp' => 'application/vnd.osgi.dp',
'dpg' => 'application/vnd.dpgraph', 'dpg' => 'application/vnd.dpgraph',
'dpx' => 'image/dpx',
'dra' => 'audio/vnd.dra', 'dra' => 'audio/vnd.dra',
'drle' => 'image/dicom-rle', 'drle' => 'image/dicom-rle',
'dsc' => 'text/prs.lines.tag', 'dsc' => 'text/prs.lines.tag',
@ -255,7 +266,6 @@ final class MimeType
'eot' => 'application/vnd.ms-fontobject', 'eot' => 'application/vnd.ms-fontobject',
'eps' => 'application/postscript', 'eps' => 'application/postscript',
'epub' => 'application/epub+zip', 'epub' => 'application/epub+zip',
'es' => 'application/ecmascript',
'es3' => 'application/vnd.eszigno3+xml', 'es3' => 'application/vnd.eszigno3+xml',
'esa' => 'application/vnd.osgi.subsystem', 'esa' => 'application/vnd.osgi.subsystem',
'esf' => 'application/vnd.epson.esf', 'esf' => 'application/vnd.epson.esf',
@ -448,6 +458,7 @@ final class MimeType
'jsonld' => 'application/ld+json', 'jsonld' => 'application/ld+json',
'jsonml' => 'application/jsonml+json', 'jsonml' => 'application/jsonml+json',
'jsx' => 'text/jsx', 'jsx' => 'text/jsx',
'jt' => 'model/jt',
'jxr' => 'image/jxr', 'jxr' => 'image/jxr',
'jxra' => 'image/jxra', 'jxra' => 'image/jxra',
'jxrs' => 'image/jxrs', 'jxrs' => 'image/jxrs',
@ -552,7 +563,7 @@ final class MimeType
'mime' => 'message/rfc822', 'mime' => 'message/rfc822',
'mj2' => 'video/mj2', 'mj2' => 'video/mj2',
'mjp2' => 'video/mj2', 'mjp2' => 'video/mj2',
'mjs' => 'application/javascript', 'mjs' => 'text/javascript',
'mk3d' => 'video/x-matroska', 'mk3d' => 'video/x-matroska',
'mka' => 'audio/x-matroska', 'mka' => 'audio/x-matroska',
'mkd' => 'text/x-markdown', 'mkd' => 'text/x-markdown',
@ -602,6 +613,8 @@ final class MimeType
'msg' => 'application/vnd.ms-outlook', 'msg' => 'application/vnd.ms-outlook',
'msh' => 'model/mesh', 'msh' => 'model/mesh',
'msi' => 'application/x-msdownload', 'msi' => 'application/x-msdownload',
'msix' => 'application/msix',
'msixbundle' => 'application/msixbundle',
'msl' => 'application/vnd.mobius.msl', 'msl' => 'application/vnd.mobius.msl',
'msm' => 'application/octet-stream', 'msm' => 'application/octet-stream',
'msp' => 'application/octet-stream', 'msp' => 'application/octet-stream',
@ -775,6 +788,8 @@ final class MimeType
'pvb' => 'application/vnd.3gpp.pic-bw-var', 'pvb' => 'application/vnd.3gpp.pic-bw-var',
'pwn' => 'application/vnd.3m.post-it-notes', 'pwn' => 'application/vnd.3m.post-it-notes',
'pya' => 'audio/vnd.ms-playready.media.pya', 'pya' => 'audio/vnd.ms-playready.media.pya',
'pyo' => 'model/vnd.pytha.pyox',
'pyox' => 'model/vnd.pytha.pyox',
'pyv' => 'video/vnd.ms-playready.media.pyv', 'pyv' => 'video/vnd.ms-playready.media.pyv',
'qam' => 'application/vnd.epson.quickanime', 'qam' => 'application/vnd.epson.quickanime',
'qbo' => 'application/vnd.intu.qbo', 'qbo' => 'application/vnd.intu.qbo',
@ -923,10 +938,12 @@ final class MimeType
'st' => 'application/vnd.sailingtracker.track', 'st' => 'application/vnd.sailingtracker.track',
'stc' => 'application/vnd.sun.xml.calc.template', 'stc' => 'application/vnd.sun.xml.calc.template',
'std' => 'application/vnd.sun.xml.draw.template', 'std' => 'application/vnd.sun.xml.draw.template',
'step' => 'application/STEP',
'stf' => 'application/vnd.wt.stf', 'stf' => 'application/vnd.wt.stf',
'sti' => 'application/vnd.sun.xml.impress.template', 'sti' => 'application/vnd.sun.xml.impress.template',
'stk' => 'application/hyperstudio', 'stk' => 'application/hyperstudio',
'stl' => 'model/stl', 'stl' => 'model/stl',
'stp' => 'application/STEP',
'stpx' => 'model/step+xml', 'stpx' => 'model/step+xml',
'stpxz' => 'model/step-xml+zip', 'stpxz' => 'model/step-xml+zip',
'stpz' => 'model/step+zip', 'stpz' => 'model/step+zip',
@ -1013,10 +1030,12 @@ final class MimeType
'ulx' => 'application/x-glulx', 'ulx' => 'application/x-glulx',
'umj' => 'application/vnd.umajin', 'umj' => 'application/vnd.umajin',
'unityweb' => 'application/vnd.unity', 'unityweb' => 'application/vnd.unity',
'uo' => 'application/vnd.uoml+xml',
'uoml' => 'application/vnd.uoml+xml', 'uoml' => 'application/vnd.uoml+xml',
'uri' => 'text/uri-list', 'uri' => 'text/uri-list',
'uris' => 'text/uri-list', 'uris' => 'text/uri-list',
'urls' => 'text/uri-list', 'urls' => 'text/uri-list',
'usda' => 'model/vnd.usda',
'usdz' => 'model/vnd.usdz+zip', 'usdz' => 'model/vnd.usdz+zip',
'ustar' => 'application/x-ustar', 'ustar' => 'application/x-ustar',
'utz' => 'application/vnd.uiq.theme', 'utz' => 'application/vnd.uiq.theme',
@ -1096,6 +1115,7 @@ final class MimeType
'webmanifest' => 'application/manifest+json', 'webmanifest' => 'application/manifest+json',
'webp' => 'image/webp', 'webp' => 'image/webp',
'wg' => 'application/vnd.pmi.widget', 'wg' => 'application/vnd.pmi.widget',
'wgsl' => 'text/wgsl',
'wgt' => 'application/widget', 'wgt' => 'application/widget',
'wif' => 'application/watcherinfo+xml', 'wif' => 'application/watcherinfo+xml',
'wks' => 'application/vnd.ms-works', 'wks' => 'application/vnd.ms-works',
@ -1150,9 +1170,10 @@ final class MimeType
'xel' => 'application/xcap-el+xml', 'xel' => 'application/xcap-el+xml',
'xenc' => 'application/xenc+xml', 'xenc' => 'application/xenc+xml',
'xer' => 'application/patch-ops-error+xml', 'xer' => 'application/patch-ops-error+xml',
'xfdf' => 'application/vnd.adobe.xfdf', 'xfdf' => 'application/xfdf',
'xfdl' => 'application/vnd.xfdl', 'xfdl' => 'application/vnd.xfdl',
'xht' => 'application/xhtml+xml', 'xht' => 'application/xhtml+xml',
'xhtm' => 'application/vnd.pwg-xhtml-print+xml',
'xhtml' => 'application/xhtml+xml', 'xhtml' => 'application/xhtml+xml',
'xhvml' => 'application/xv+xml', 'xhvml' => 'application/xv+xml',
'xif' => 'image/vnd.xiff', 'xif' => 'image/vnd.xiff',
@ -1183,6 +1204,7 @@ final class MimeType
'xpw' => 'application/vnd.intercon.formnet', 'xpw' => 'application/vnd.intercon.formnet',
'xpx' => 'application/vnd.intercon.formnet', 'xpx' => 'application/vnd.intercon.formnet',
'xsd' => 'application/xml', 'xsd' => 'application/xml',
'xsf' => 'application/prs.xsf+xml',
'xsl' => 'application/xml', 'xsl' => 'application/xml',
'xslt' => 'application/xslt+xml', 'xslt' => 'application/xslt+xml',
'xsm' => 'application/vnd.syncml+xml', 'xsm' => 'application/vnd.syncml+xml',
@ -1218,7 +1240,7 @@ final class MimeType
/** /**
* Determines the mimetype of a file by looking at its extension. * Determines the mimetype of a file by looking at its extension.
* *
* @link https://raw.githubusercontent.com/jshttp/mime-db/master/db.json * @see https://raw.githubusercontent.com/jshttp/mime-db/master/db.json
*/ */
public static function fromFilename(string $filename): ?string public static function fromFilename(string $filename): ?string
{ {
@ -1228,7 +1250,7 @@ final class MimeType
/** /**
* Maps a file extensions to a mimetype. * Maps a file extensions to a mimetype.
* *
* @link https://raw.githubusercontent.com/jshttp/mime-db/master/db.json * @see https://raw.githubusercontent.com/jshttp/mime-db/master/db.json
*/ */
public static function fromExtension(string $extension): ?string public static function fromExtension(string $extension): ?string
{ {

View File

@ -60,7 +60,7 @@ final class MultipartStream implements StreamInterface
$str .= "{$key}: {$value}\r\n"; $str .= "{$key}: {$value}\r\n";
} }
return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n"; return "--{$this->boundary}\r\n".trim($str)."\r\n\r\n";
} }
/** /**
@ -72,7 +72,7 @@ final class MultipartStream implements StreamInterface
foreach ($elements as $element) { foreach ($elements as $element) {
if (!is_array($element)) { if (!is_array($element)) {
throw new \UnexpectedValueException("An array is expected"); throw new \UnexpectedValueException('An array is expected');
} }
$this->addElement($stream, $element); $this->addElement($stream, $element);
} }
@ -137,9 +137,7 @@ final class MultipartStream implements StreamInterface
// Set a default Content-Type if one was not supplied // Set a default Content-Type if one was not supplied
$type = $this->getHeader($headers, 'content-type'); $type = $this->getHeader($headers, 'content-type');
if (!$type && ($filename === '0' || $filename)) { if (!$type && ($filename === '0' || $filename)) {
if ($type = MimeType::fromFilename($filename)) { $headers['Content-Type'] = MimeType::fromFilename($filename) ?? 'application/octet-stream';
$headers['Content-Type'] = $type;
}
} }
return [$stream, $headers]; return [$stream, $headers];

View File

@ -60,6 +60,7 @@ final class PumpStream implements StreamInterface
throw $e; throw $e;
} }
trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR); trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);
return ''; return '';
} }
} }
@ -169,6 +170,7 @@ final class PumpStream implements StreamInterface
$data = call_user_func($this->source, $length); $data = call_user_func($this->source, $length);
if ($data === false || $data === null) { if ($data === false || $data === null) {
$this->source = null; $this->source = null;
return; return;
} }
$this->buffer->write($data); $this->buffer->write($data);

View File

@ -93,7 +93,7 @@ final class Query
$qs .= $k; $qs .= $k;
$v = is_bool($v) ? (int) $v : $v; $v = is_bool($v) ? (int) $v : $v;
if ($v !== null) { if ($v !== null) {
$qs .= '=' . $encoder((string) $v); $qs .= '='.$encoder((string) $v);
} }
$qs .= '&'; $qs .= '&';
} else { } else {
@ -101,7 +101,7 @@ final class Query
$qs .= $k; $qs .= $k;
$vv = is_bool($vv) ? (int) $vv : $vv; $vv = is_bool($vv) ? (int) $vv : $vv;
if ($vv !== null) { if ($vv !== null) {
$qs .= '=' . $encoder((string) $vv); $qs .= '='.$encoder((string) $vv);
} }
$qs .= '&'; $qs .= '&';
} }

View File

@ -69,7 +69,7 @@ class Request implements RequestInterface
$target = '/'; $target = '/';
} }
if ($this->uri->getQuery() != '') { if ($this->uri->getQuery() != '') {
$target .= '?' . $this->uri->getQuery(); $target .= '?'.$this->uri->getQuery();
} }
return $target; return $target;
@ -85,6 +85,7 @@ class Request implements RequestInterface
$new = clone $this; $new = clone $this;
$new->requestTarget = $requestTarget; $new->requestTarget = $requestTarget;
return $new; return $new;
} }
@ -98,6 +99,7 @@ class Request implements RequestInterface
$this->assertMethod($method); $this->assertMethod($method);
$new = clone $this; $new = clone $this;
$new->method = strtoupper($method); $new->method = strtoupper($method);
return $new; return $new;
} }
@ -131,7 +133,7 @@ class Request implements RequestInterface
} }
if (($port = $this->uri->getPort()) !== null) { if (($port = $this->uri->getPort()) !== null) {
$host .= ':' . $port; $host .= ':'.$port;
} }
if (isset($this->headerNames['host'])) { if (isset($this->headerNames['host'])) {

View File

@ -138,6 +138,7 @@ class Response implements ResponseInterface
$reasonPhrase = self::PHRASES[$new->statusCode]; $reasonPhrase = self::PHRASES[$new->statusCode];
} }
$new->reasonPhrase = (string) $reasonPhrase; $new->reasonPhrase = (string) $reasonPhrase;
return $new; return $new;
} }

View File

@ -14,7 +14,7 @@ final class Rfc7230
* *
* Note: header delimiter (\r\n) is modified to \r?\n to accept line feed only delimiters for BC reasons. * Note: header delimiter (\r\n) is modified to \r?\n to accept line feed only delimiters for BC reasons.
* *
* @link https://github.com/amphp/http/blob/v1.0.1/src/Rfc7230.php#L12-L15 * @see https://github.com/amphp/http/blob/v1.0.1/src/Rfc7230.php#L12-L15
* *
* @license https://github.com/amphp/http/blob/v1.0.1/LICENSE * @license https://github.com/amphp/http/blob/v1.0.1/LICENSE
*/ */

View File

@ -144,10 +144,10 @@ class ServerRequest extends Request implements ServerRequestInterface
foreach (array_keys($files['tmp_name']) as $key) { foreach (array_keys($files['tmp_name']) as $key) {
$spec = [ $spec = [
'tmp_name' => $files['tmp_name'][$key], 'tmp_name' => $files['tmp_name'][$key],
'size' => $files['size'][$key] ?? null, 'size' => $files['size'][$key] ?? null,
'error' => $files['error'][$key] ?? null, 'error' => $files['error'][$key] ?? null,
'name' => $files['name'][$key] ?? null, 'name' => $files['name'][$key] ?? null,
'type' => $files['type'][$key] ?? null, 'type' => $files['type'][$key] ?? null,
]; ];
$normalizedFiles[$key] = self::createUploadedFileFromSpec($spec); $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
} }
@ -182,7 +182,7 @@ class ServerRequest extends Request implements ServerRequestInterface
private static function extractHostAndPortFromAuthority(string $authority): array private static function extractHostAndPortFromAuthority(string $authority): array
{ {
$uri = 'http://' . $authority; $uri = 'http://'.$authority;
$parts = parse_url($uri); $parts = parse_url($uri);
if (false === $parts) { if (false === $parts) {
return [null, null]; return [null, null];

View File

@ -61,8 +61,8 @@ class Stream implements StreamInterface
$this->stream = $stream; $this->stream = $stream;
$meta = stream_get_meta_data($this->stream); $meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable']; $this->seekable = $meta['seekable'];
$this->readable = (bool)preg_match(self::READABLE_MODES, $meta['mode']); $this->readable = (bool) preg_match(self::READABLE_MODES, $meta['mode']);
$this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta['mode']); $this->writable = (bool) preg_match(self::WRITABLE_MODES, $meta['mode']);
$this->uri = $this->getMetadata('uri'); $this->uri = $this->getMetadata('uri');
} }
@ -80,12 +80,14 @@ class Stream implements StreamInterface
if ($this->isSeekable()) { if ($this->isSeekable()) {
$this->seek(0); $this->seek(0);
} }
return $this->getContents(); return $this->getContents();
} catch (\Throwable $e) { } catch (\Throwable $e) {
if (\PHP_VERSION_ID >= 70400) { if (\PHP_VERSION_ID >= 70400) {
throw $e; throw $e;
} }
trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR); trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);
return ''; return '';
} }
} }
@ -145,6 +147,7 @@ class Stream implements StreamInterface
$stats = fstat($this->stream); $stats = fstat($this->stream);
if (is_array($stats) && isset($stats['size'])) { if (is_array($stats) && isset($stats['size'])) {
$this->size = $stats['size']; $this->size = $stats['size'];
return $this->size; return $this->size;
} }
@ -207,7 +210,7 @@ class Stream implements StreamInterface
} }
if (fseek($this->stream, $offset, $whence) === -1) { if (fseek($this->stream, $offset, $whence) === -1) {
throw new \RuntimeException('Unable to seek to stream position ' throw new \RuntimeException('Unable to seek to stream position '
. $offset . ' with whence ' . var_export($whence, true)); .$offset.' with whence '.var_export($whence, true));
} }
} }

View File

@ -31,6 +31,7 @@ trait StreamDecoratorTrait
{ {
if ($name === 'stream') { if ($name === 'stream') {
$this->stream = $this->createStream(); $this->stream = $this->createStream();
return $this->stream; return $this->stream;
} }
@ -43,12 +44,14 @@ trait StreamDecoratorTrait
if ($this->isSeekable()) { if ($this->isSeekable()) {
$this->seek(0); $this->seek(0);
} }
return $this->getContents(); return $this->getContents();
} catch (\Throwable $e) { } catch (\Throwable $e) {
if (\PHP_VERSION_ID >= 70400) { if (\PHP_VERSION_ID >= 70400) {
throw $e; throw $e;
} }
trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR); trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);
return ''; return '';
} }
} }

View File

@ -41,7 +41,7 @@ final class StreamWrapper
$mode = 'w'; $mode = 'w';
} else { } else {
throw new \InvalidArgumentException('The stream must be readable, ' throw new \InvalidArgumentException('The stream must be readable, '
. 'writable, or both.'); .'writable, or both.');
} }
return fopen('guzzle://stream', $mode, false, self::createStreamContext($stream)); return fopen('guzzle://stream', $mode, false, self::createStreamContext($stream));
@ -55,7 +55,7 @@ final class StreamWrapper
public static function createStreamContext(StreamInterface $stream) public static function createStreamContext(StreamInterface $stream)
{ {
return stream_context_create([ return stream_context_create([
'guzzle' => ['stream' => $stream] 'guzzle' => ['stream' => $stream],
]); ]);
} }
@ -115,7 +115,7 @@ final class StreamWrapper
*/ */
public function stream_cast(int $cast_as) public function stream_cast(int $cast_as)
{ {
$stream = clone($this->stream); $stream = clone $this->stream;
$resource = $stream->detach(); $resource = $stream->detach();
return $resource ?? false; return $resource ?? false;
@ -127,27 +127,27 @@ final class StreamWrapper
public function stream_stat(): array public function stream_stat(): array
{ {
static $modeMap = [ static $modeMap = [
'r' => 33060, 'r' => 33060,
'rb' => 33060, 'rb' => 33060,
'r+' => 33206, 'r+' => 33206,
'w' => 33188, 'w' => 33188,
'wb' => 33188 'wb' => 33188,
]; ];
return [ return [
'dev' => 0, 'dev' => 0,
'ino' => 0, 'ino' => 0,
'mode' => $modeMap[$this->mode], 'mode' => $modeMap[$this->mode],
'nlink' => 0, 'nlink' => 0,
'uid' => 0, 'uid' => 0,
'gid' => 0, 'gid' => 0,
'rdev' => 0, 'rdev' => 0,
'size' => $this->stream->getSize() ?: 0, 'size' => $this->stream->getSize() ?: 0,
'atime' => 0, 'atime' => 0,
'mtime' => 0, 'mtime' => 0,
'ctime' => 0, 'ctime' => 0,
'blksize' => 0, 'blksize' => 0,
'blocks' => 0 'blocks' => 0,
]; ];
} }
@ -157,19 +157,19 @@ final class StreamWrapper
public function url_stat(string $path, int $flags): array public function url_stat(string $path, int $flags): array
{ {
return [ return [
'dev' => 0, 'dev' => 0,
'ino' => 0, 'ino' => 0,
'mode' => 0, 'mode' => 0,
'nlink' => 0, 'nlink' => 0,
'uid' => 0, 'uid' => 0,
'gid' => 0, 'gid' => 0,
'rdev' => 0, 'rdev' => 0,
'size' => 0, 'size' => 0,
'atime' => 0, 'atime' => 0,
'mtime' => 0, 'mtime' => 0,
'ctime' => 0, 'ctime' => 0,
'blksize' => 0, 'blksize' => 0,
'blocks' => 0 'blocks' => 0,
]; ];
} }
} }

View File

@ -25,7 +25,7 @@ class Uri implements UriInterface, \JsonSerializable
private const HTTP_DEFAULT_HOST = 'localhost'; private const HTTP_DEFAULT_HOST = 'localhost';
private const DEFAULT_PORTS = [ private const DEFAULT_PORTS = [
'http' => 80, 'http' => 80,
'https' => 443, 'https' => 443,
'ftp' => 21, 'ftp' => 21,
'gopher' => 70, 'gopher' => 70,
@ -41,14 +41,14 @@ class Uri implements UriInterface, \JsonSerializable
/** /**
* Unreserved characters for use in a regex. * Unreserved characters for use in a regex.
* *
* @link https://tools.ietf.org/html/rfc3986#section-2.3 * @see https://tools.ietf.org/html/rfc3986#section-2.3
*/ */
private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~'; private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~';
/** /**
* Sub-delims for use in a regex. * Sub-delims for use in a regex.
* *
* @link https://tools.ietf.org/html/rfc3986#section-2.2 * @see https://tools.ietf.org/html/rfc3986#section-2.2
*/ */
private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;='; private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';
private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26']; private const QUERY_SEPARATORS_REPLACEMENT = ['=' => '%3D', '&' => '%26'];
@ -87,6 +87,7 @@ class Uri implements UriInterface, \JsonSerializable
$this->applyParts($parts); $this->applyParts($parts);
} }
} }
/** /**
* UTF-8 aware \parse_url() replacement. * UTF-8 aware \parse_url() replacement.
* *
@ -121,7 +122,7 @@ class Uri implements UriInterface, \JsonSerializable
$url $url
); );
$result = parse_url($prefix . $encodedUrl); $result = parse_url($prefix.$encodedUrl);
if ($result === false) { if ($result === false) {
return false; return false;
@ -161,7 +162,7 @@ class Uri implements UriInterface, \JsonSerializable
* `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
* that format). * that format).
* *
* @link https://tools.ietf.org/html/rfc3986#section-5.3 * @see https://tools.ietf.org/html/rfc3986#section-5.3
*/ */
public static function composeComponents(?string $scheme, ?string $authority, string $path, ?string $query, ?string $fragment): string public static function composeComponents(?string $scheme, ?string $authority, string $path, ?string $query, ?string $fragment): string
{ {
@ -169,25 +170,25 @@ class Uri implements UriInterface, \JsonSerializable
// weak type checks to also accept null until we can add scalar type hints // weak type checks to also accept null until we can add scalar type hints
if ($scheme != '') { if ($scheme != '') {
$uri .= $scheme . ':'; $uri .= $scheme.':';
} }
if ($authority != '' || $scheme === 'file') { if ($authority != '' || $scheme === 'file') {
$uri .= '//' . $authority; $uri .= '//'.$authority;
} }
if ($authority != '' && $path != '' && $path[0] != '/') { if ($authority != '' && $path != '' && $path[0] != '/') {
$path = '/' . $path; $path = '/'.$path;
} }
$uri .= $path; $uri .= $path;
if ($query != '') { if ($query != '') {
$uri .= '?' . $query; $uri .= '?'.$query;
} }
if ($fragment != '') { if ($fragment != '') {
$uri .= '#' . $fragment; $uri .= '#'.$fragment;
} }
return $uri; return $uri;
@ -218,7 +219,7 @@ class Uri implements UriInterface, \JsonSerializable
* @see Uri::isNetworkPathReference * @see Uri::isNetworkPathReference
* @see Uri::isAbsolutePathReference * @see Uri::isAbsolutePathReference
* @see Uri::isRelativePathReference * @see Uri::isRelativePathReference
* @link https://tools.ietf.org/html/rfc3986#section-4 * @see https://tools.ietf.org/html/rfc3986#section-4
*/ */
public static function isAbsolute(UriInterface $uri): bool public static function isAbsolute(UriInterface $uri): bool
{ {
@ -230,7 +231,7 @@ class Uri implements UriInterface, \JsonSerializable
* *
* A relative reference that begins with two slash characters is termed an network-path reference. * A relative reference that begins with two slash characters is termed an network-path reference.
* *
* @link https://tools.ietf.org/html/rfc3986#section-4.2 * @see https://tools.ietf.org/html/rfc3986#section-4.2
*/ */
public static function isNetworkPathReference(UriInterface $uri): bool public static function isNetworkPathReference(UriInterface $uri): bool
{ {
@ -242,7 +243,7 @@ class Uri implements UriInterface, \JsonSerializable
* *
* A relative reference that begins with a single slash character is termed an absolute-path reference. * A relative reference that begins with a single slash character is termed an absolute-path reference.
* *
* @link https://tools.ietf.org/html/rfc3986#section-4.2 * @see https://tools.ietf.org/html/rfc3986#section-4.2
*/ */
public static function isAbsolutePathReference(UriInterface $uri): bool public static function isAbsolutePathReference(UriInterface $uri): bool
{ {
@ -257,7 +258,7 @@ class Uri implements UriInterface, \JsonSerializable
* *
* A relative reference that does not begin with a slash character is termed a relative-path reference. * A relative reference that does not begin with a slash character is termed a relative-path reference.
* *
* @link https://tools.ietf.org/html/rfc3986#section-4.2 * @see https://tools.ietf.org/html/rfc3986#section-4.2
*/ */
public static function isRelativePathReference(UriInterface $uri): bool public static function isRelativePathReference(UriInterface $uri): bool
{ {
@ -276,7 +277,7 @@ class Uri implements UriInterface, \JsonSerializable
* @param UriInterface $uri The URI to check * @param UriInterface $uri The URI to check
* @param UriInterface|null $base An optional base URI to compare against * @param UriInterface|null $base An optional base URI to compare against
* *
* @link https://tools.ietf.org/html/rfc3986#section-4.4 * @see https://tools.ietf.org/html/rfc3986#section-4.4
*/ */
public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool
{ {
@ -352,7 +353,7 @@ class Uri implements UriInterface, \JsonSerializable
/** /**
* Creates a URI from a hash of `parse_url` components. * Creates a URI from a hash of `parse_url` components.
* *
* @link http://php.net/manual/en/function.parse-url.php * @see http://php.net/manual/en/function.parse-url.php
* *
* @throws MalformedUriException If the components do not form a valid URI. * @throws MalformedUriException If the components do not form a valid URI.
*/ */
@ -374,11 +375,11 @@ class Uri implements UriInterface, \JsonSerializable
{ {
$authority = $this->host; $authority = $this->host;
if ($this->userInfo !== '') { if ($this->userInfo !== '') {
$authority = $this->userInfo . '@' . $authority; $authority = $this->userInfo.'@'.$authority;
} }
if ($this->port !== null) { if ($this->port !== null) {
$authority .= ':' . $this->port; $authority .= ':'.$this->port;
} }
return $authority; return $authority;
@ -435,7 +436,7 @@ class Uri implements UriInterface, \JsonSerializable
{ {
$info = $this->filterUserInfoComponent($user); $info = $this->filterUserInfoComponent($user);
if ($password !== null) { if ($password !== null) {
$info .= ':' . $this->filterUserInfoComponent($password); $info .= ':'.$this->filterUserInfoComponent($password);
} }
if ($this->userInfo === $info) { if ($this->userInfo === $info) {
@ -563,7 +564,7 @@ class Uri implements UriInterface, \JsonSerializable
? $this->filterQueryAndFragment($parts['fragment']) ? $this->filterQueryAndFragment($parts['fragment'])
: ''; : '';
if (isset($parts['pass'])) { if (isset($parts['pass'])) {
$this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']); $this->userInfo .= ':'.$this->filterUserInfoComponent($parts['pass']);
} }
$this->removeDefaultPort(); $this->removeDefaultPort();
@ -595,7 +596,7 @@ class Uri implements UriInterface, \JsonSerializable
} }
return preg_replace_callback( return preg_replace_callback(
'/(?:[^%' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . ']+|%(?![A-Fa-f0-9]{2}))/', '/(?:[^%'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.']+|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'], [$this, 'rawurlencodeMatchZero'],
$component $component
); );
@ -627,7 +628,7 @@ class Uri implements UriInterface, \JsonSerializable
} }
$port = (int) $port; $port = (int) $port;
if (0 > $port || 0xffff < $port) { if (0 > $port || 0xFFFF < $port) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
sprintf('Invalid port: %d. Must be between 0 and 65535', $port) sprintf('Invalid port: %d. Must be between 0 and 65535', $port)
); );
@ -664,7 +665,7 @@ class Uri implements UriInterface, \JsonSerializable
$queryString = strtr($key, self::QUERY_SEPARATORS_REPLACEMENT); $queryString = strtr($key, self::QUERY_SEPARATORS_REPLACEMENT);
if ($value !== null) { if ($value !== null) {
$queryString .= '=' . strtr($value, self::QUERY_SEPARATORS_REPLACEMENT); $queryString .= '='.strtr($value, self::QUERY_SEPARATORS_REPLACEMENT);
} }
return $queryString; return $queryString;
@ -691,7 +692,7 @@ class Uri implements UriInterface, \JsonSerializable
} }
return preg_replace_callback( return preg_replace_callback(
'/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/', '/(?:[^'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.'%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'], [$this, 'rawurlencodeMatchZero'],
$path $path
); );
@ -711,7 +712,7 @@ class Uri implements UriInterface, \JsonSerializable
} }
return preg_replace_callback( return preg_replace_callback(
'/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/', '/(?:[^'.self::CHAR_UNRESERVED.self::CHAR_SUB_DELIMS.'%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'], [$this, 'rawurlencodeMatchZero'],
$str $str
); );

View File

@ -11,7 +11,7 @@ use Psr\Http\Message\UriInterface;
* *
* @author Tobias Schultze * @author Tobias Schultze
* *
* @link https://tools.ietf.org/html/rfc3986#section-6 * @see https://tools.ietf.org/html/rfc3986#section-6
*/ */
final class UriNormalizer final class UriNormalizer
{ {
@ -119,7 +119,7 @@ final class UriNormalizer
* @param UriInterface $uri The URI to normalize * @param UriInterface $uri The URI to normalize
* @param int $flags A bitmask of normalizations to apply, see constants * @param int $flags A bitmask of normalizations to apply, see constants
* *
* @link https://tools.ietf.org/html/rfc3986#section-6.2 * @see https://tools.ietf.org/html/rfc3986#section-6.2
*/ */
public static function normalize(UriInterface $uri, int $flags = self::PRESERVING_NORMALIZATIONS): UriInterface public static function normalize(UriInterface $uri, int $flags = self::PRESERVING_NORMALIZATIONS): UriInterface
{ {
@ -174,7 +174,7 @@ final class UriNormalizer
* @param UriInterface $uri2 An URI to compare * @param UriInterface $uri2 An URI to compare
* @param int $normalizations A bitmask of normalizations to apply, see constants * @param int $normalizations A bitmask of normalizations to apply, see constants
* *
* @link https://tools.ietf.org/html/rfc3986#section-6.1 * @see https://tools.ietf.org/html/rfc3986#section-6.1
*/ */
public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, int $normalizations = self::PRESERVING_NORMALIZATIONS): bool public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, int $normalizations = self::PRESERVING_NORMALIZATIONS): bool
{ {

View File

@ -11,14 +11,14 @@ use Psr\Http\Message\UriInterface;
* *
* @author Tobias Schultze * @author Tobias Schultze
* *
* @link https://tools.ietf.org/html/rfc3986#section-5 * @see https://tools.ietf.org/html/rfc3986#section-5
*/ */
final class UriResolver final class UriResolver
{ {
/** /**
* Removes dot segments from a path and returns the new path. * Removes dot segments from a path and returns the new path.
* *
* @link http://tools.ietf.org/html/rfc3986#section-5.2.4 * @see http://tools.ietf.org/html/rfc3986#section-5.2.4
*/ */
public static function removeDotSegments(string $path): string public static function removeDotSegments(string $path): string
{ {
@ -40,7 +40,7 @@ final class UriResolver
if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) { if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {
// Re-add the leading slash if necessary for cases like "/.." // Re-add the leading slash if necessary for cases like "/.."
$newPath = '/' . $newPath; $newPath = '/'.$newPath;
} elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) { } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {
// Add the trailing slash if necessary // Add the trailing slash if necessary
// If newPath is not empty, then $segment must be set and is the last segment from the foreach // If newPath is not empty, then $segment must be set and is the last segment from the foreach
@ -53,7 +53,7 @@ final class UriResolver
/** /**
* Converts the relative URI into a new URI that is resolved against the base URI. * Converts the relative URI into a new URI that is resolved against the base URI.
* *
* @link http://tools.ietf.org/html/rfc3986#section-5.2 * @see http://tools.ietf.org/html/rfc3986#section-5.2
*/ */
public static function resolve(UriInterface $base, UriInterface $rel): UriInterface public static function resolve(UriInterface $base, UriInterface $rel): UriInterface
{ {
@ -80,13 +80,13 @@ final class UriResolver
$targetPath = $rel->getPath(); $targetPath = $rel->getPath();
} else { } else {
if ($targetAuthority != '' && $base->getPath() === '') { if ($targetAuthority != '' && $base->getPath() === '') {
$targetPath = '/' . $rel->getPath(); $targetPath = '/'.$rel->getPath();
} else { } else {
$lastSlashPos = strrpos($base->getPath(), '/'); $lastSlashPos = strrpos($base->getPath(), '/');
if ($lastSlashPos === false) { if ($lastSlashPos === false) {
$targetPath = $rel->getPath(); $targetPath = $rel->getPath();
} else { } else {
$targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath(); $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1).$rel->getPath();
} }
} }
} }
@ -185,7 +185,7 @@ final class UriResolver
} }
} }
$targetSegments[] = $targetLastSegment; $targetSegments[] = $targetLastSegment;
$relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments); $relativePath = str_repeat('../', count($sourceSegments)).implode('/', $targetSegments);
// A reference to am empty last segment or an empty first sub-segment must be prefixed with "./". // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
// This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used

View File

@ -90,6 +90,7 @@ final class Utils
} }
$buffer .= $buf; $buffer .= $buf;
} }
return $buffer; return $buffer;
} }
@ -174,7 +175,7 @@ final class Utils
$standardPorts = ['http' => 80, 'https' => 443]; $standardPorts = ['http' => 80, 'https' => 443];
$scheme = $changes['uri']->getScheme(); $scheme = $changes['uri']->getScheme();
if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) { if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
$changes['set_headers']['Host'] .= ':' . $port; $changes['set_headers']['Host'] .= ':'.$port;
} }
} }
} }
@ -291,6 +292,7 @@ final class Utils
fwrite($stream, (string) $resource); fwrite($stream, (string) $resource);
fseek($stream, 0); fseek($stream, 0);
} }
return new Stream($stream, $options); return new Stream($stream, $options);
} }
@ -308,6 +310,7 @@ final class Utils
fseek($stream, 0); fseek($stream, 0);
$resource = $stream; $resource = $stream;
} }
return new Stream($resource, $options); return new Stream($resource, $options);
case 'object': case 'object':
/** @var object $resource */ /** @var object $resource */
@ -320,6 +323,7 @@ final class Utils
} }
$result = $resource->current(); $result = $resource->current();
$resource->next(); $resource->next();
return $result; return $result;
}, $options); }, $options);
} elseif (method_exists($resource, '__toString')) { } elseif (method_exists($resource, '__toString')) {
@ -334,7 +338,7 @@ final class Utils
return new PumpStream($resource, $options); return new PumpStream($resource, $options);
} }
throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource)); throw new \InvalidArgumentException('Invalid resource type: '.gettype($resource));
} }
/** /**

View File

@ -51,8 +51,10 @@ echo $closure(); // james;
### Caveats ### Caveats
1. Creating **anonymous classes** within closures is not supported. * Anonymous classes cannot be created within closures.
2. Using attributes within closures is not supported. * Attributes cannot be used within closures.
* Serializing closures on REPL environments like Laravel Tinker is not supported.
* Serializing closures that reference objects with readonly properties is not supported.
## Contributing ## Contributing

View File

@ -62,6 +62,17 @@ class SerializableClosure
return $this->serializable->getClosure(); return $this->serializable->getClosure();
} }
/**
* Create a new unsigned serializable closure instance.
*
* @param Closure $closure
* @return \Laravel\SerializableClosure\UnsignedSerializableClosure
*/
public static function unsigned(Closure $closure)
{
return new UnsignedSerializableClosure($closure);
}
/** /**
* Sets the serializable closure secret key. * Sets the serializable closure secret key.
* *

View File

@ -10,6 +10,7 @@ use Laravel\SerializableClosure\Support\ClosureScope;
use Laravel\SerializableClosure\Support\ClosureStream; use Laravel\SerializableClosure\Support\ClosureStream;
use Laravel\SerializableClosure\Support\ReflectionClosure; use Laravel\SerializableClosure\Support\ReflectionClosure;
use Laravel\SerializableClosure\Support\SelfReference; use Laravel\SerializableClosure\Support\SelfReference;
use Laravel\SerializableClosure\UnsignedSerializableClosure;
use ReflectionObject; use ReflectionObject;
use UnitEnum; use UnitEnum;
@ -379,7 +380,7 @@ class Native implements Serializable
$item = $property->getValue($data); $item = $property->getValue($data);
if ($item instanceof SerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) { if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) {
$this->code['objects'][] = [ $this->code['objects'][] = [
'instance' => $data, 'instance' => $data,
'property' => $property, 'property' => $property,
@ -452,7 +453,7 @@ class Native implements Serializable
} }
unset($value); unset($value);
} elseif (is_object($data) && ! $data instanceof SerializableClosure) { } elseif (is_object($data) && ! $data instanceof SerializableClosure && ! $data instanceof UnsignedSerializableClosure) {
if (isset($this->scope[$data])) { if (isset($this->scope[$data])) {
$data = $this->scope[$data]; $data = $this->scope[$data];

View File

@ -511,8 +511,7 @@ class ReflectionClosure extends ReflectionFunction
// named arguments... // named arguments...
case ':': case ':':
if ($lastState === 'closure' && $context === 'root') { if ($lastState === 'closure' && $context === 'root') {
$state = 'ignore_next'; $state = 'closure';
$lastState = 'closure';
$code .= $id_start.$token; $code .= $id_start.$token;
} }
@ -651,7 +650,7 @@ class ReflectionClosure extends ReflectionFunction
$state = 'id_name'; $state = 'id_name';
$context = 'extends'; $context = 'extends';
$lastState = 'anonymous'; $lastState = 'anonymous';
break; break;
case '{': case '{':
$state = 'closure'; $state = 'closure';
if (! $inside_structure) { if (! $inside_structure) {

View File

@ -0,0 +1,82 @@
<?php
namespace Laravel\SerializableClosure;
use Closure;
use Laravel\SerializableClosure\Exceptions\PhpVersionNotSupportedException;
class UnsignedSerializableClosure
{
/**
* The closure's serializable.
*
* @var \Laravel\SerializableClosure\Contracts\Serializable
*/
protected $serializable;
/**
* Creates a new serializable closure instance.
*
* @param \Closure $closure
* @return void
*/
public function __construct(Closure $closure)
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
$this->serializable = new Serializers\Native($closure);
}
/**
* Resolve the closure with the given arguments.
*
* @return mixed
*/
public function __invoke()
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
return call_user_func_array($this->serializable, func_get_args());
}
/**
* Gets the closure.
*
* @return \Closure
*/
public function getClosure()
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
return $this->serializable->getClosure();
}
/**
* Get the serializable representation of the closure.
*
* @return array
*/
public function __serialize()
{
return [
'serializable' => $this->serializable,
];
}
/**
* Restore the closure after serialization.
*
* @param array $data
* @return void
*/
public function __unserialize($data)
{
$this->serializable = $data['serializable'];
}
}

View File

@ -1,3 +1,7 @@
### 2.9.1 (2023-02-06)
* Fixed Logger not being serializable anymore (#1792)
### 2.9.0 (2023-02-05) ### 2.9.0 (2023-02-05)
* Deprecated FlowdockHandler & Formatter as the flowdock service was shutdown (#1748) * Deprecated FlowdockHandler & Formatter as the flowdock service was shutdown (#1748)

View File

@ -722,4 +722,40 @@ class Logger implements LoggerInterface, ResettableInterface
($this->exceptionHandler)($e, $record); ($this->exceptionHandler)($e, $record);
} }
/**
* @return array<string, mixed>
*/
public function __serialize(): array
{
return [
'name' => $this->name,
'handlers' => $this->handlers,
'processors' => $this->processors,
'microsecondTimestamps' => $this->microsecondTimestamps,
'timezone' => $this->timezone,
'exceptionHandler' => $this->exceptionHandler,
'logDepth' => $this->logDepth,
'detectCycles' => $this->detectCycles,
];
}
/**
* @param array<string, mixed> $data
*/
public function __unserialize(array $data): void
{
foreach (['name', 'handlers', 'processors', 'microsecondTimestamps', 'timezone', 'exceptionHandler', 'logDepth', 'detectCycles'] as $property) {
if (isset($data[$property])) {
$this->$property = $data[$property];
}
}
if (\PHP_VERSION_ID >= 80100) {
// Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412
/** @var \WeakMap<\Fiber, int> $fiberLogDepth */
$fiberLogDepth = new \WeakMap();
$this->fiberLogDepth = $fiberLogDepth;
}
}
} }

View File

@ -51,7 +51,7 @@ class Linkedin extends Base
$response = $this->getHttpClient()->get($url, [ $response = $this->getHttpClient()->get($url, [
'headers' => [ 'headers' => [
'Authorization' => 'Bearer '.$token, 'Authorization' => 'Bearer ' . $token,
'X-RestLi-Protocol-Version' => '2.0.0', 'X-RestLi-Protocol-Version' => '2.0.0',
], ],
]); ]);
@ -65,22 +65,23 @@ class Linkedin extends Base
$response = $this->getHttpClient()->get($url, [ $response = $this->getHttpClient()->get($url, [
'headers' => [ 'headers' => [
'Authorization' => 'Bearer '.$token, 'Authorization' => 'Bearer ' . $token,
'X-RestLi-Protocol-Version' => '2.0.0', 'X-RestLi-Protocol-Version' => '2.0.0',
], ],
]); ]);
return $this->fromJsonBody($response)['elements.0.handle~'] ?? []; return $this->fromJsonBody($response)['elements'][0]['handle~'] ?? [];
} }
protected function mapUserToObject(array $user): Contracts\UserInterface protected function mapUserToObject(array $user): Contracts\UserInterface
{ {
$preferredLocale = ($user['firstName.preferredLocale.language'] ?? null).'_'.($user['firstName.preferredLocale.country'] ?? null); $preferredLocale = ($user['firstName']['preferredLocale']['language'] ?? null) . '_' .
$firstName = $user['firstName.localized.'.$preferredLocale] ?? null; ($user['firstName']['preferredLocale']['country'] ?? null);
$lastName = $user['lastName.localized.'.$preferredLocale] ?? null; $firstName = $user['firstName']['localized'][$preferredLocale] ?? null;
$name = $firstName.' '.$lastName; $lastName = $user['lastName']['localized'][$preferredLocale] ?? null;
$name = $firstName . ' ' . $lastName;
$images = $user['profilePicture.displayImage~.elements'] ?? []; $images = $user['profilePicture']['displayImage~']['elements'] ?? [];
$avatars = \array_filter($images, static fn ($image) => ($image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] ?? 0) === 100); $avatars = \array_filter($images, static fn ($image) => ($image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] ?? 0) === 100);
$avatar = \array_shift($avatars); $avatar = \array_shift($avatars);
$originalAvatars = \array_filter($images, static fn ($image) => ($image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] ?? 0) === 800); $originalAvatars = \array_filter($images, static fn ($image) => ($image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] ?? 0) === 800);
@ -91,8 +92,8 @@ class Linkedin extends Base
Contracts\ABNF_NICKNAME => $name, Contracts\ABNF_NICKNAME => $name,
Contracts\ABNF_NAME => $name, Contracts\ABNF_NAME => $name,
Contracts\ABNF_EMAIL => $user['emailAddress'] ?? null, Contracts\ABNF_EMAIL => $user['emailAddress'] ?? null,
Contracts\ABNF_AVATAR => $avatar['identifiers.0.identifier'] ?? null, Contracts\ABNF_AVATAR => $avatar['identifiers']['0']['identifier'] ?? null,
'avatar_original' => $originalAvatar['identifiers.0.identifier'] ?? null, 'avatar_original' => $originalAvatar['identifiers']['0']['identifier'] ?? null,
]); ]);
} }
} }

View File

@ -1,5 +1,5 @@
<?php <?php
// This file is automatically generated at:2023-06-13 17:34:02 // This file is automatically generated at:2023-08-08 15:06:44
declare (strict_types = 1); declare (strict_types = 1);
return array ( return array (
0 => 'think\\captcha\\CaptchaService', 0 => 'think\\captcha\\CaptchaService',

View File

@ -11,13 +11,17 @@
namespace Symfony\Component\Cache\Adapter; namespace Symfony\Component\Cache\Adapter;
use Doctrine\DBAL\ArrayParameterType;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\Exception\TableNotFoundException;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Tools\DsnParser;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Marshaller\DefaultMarshaller; use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Marshaller\MarshallerInterface;
@ -68,7 +72,28 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface
if (!class_exists(DriverManager::class)) { if (!class_exists(DriverManager::class)) {
throw new InvalidArgumentException(sprintf('Failed to parse the DSN "%s". Try running "composer require doctrine/dbal".', $connOrDsn)); throw new InvalidArgumentException(sprintf('Failed to parse the DSN "%s". Try running "composer require doctrine/dbal".', $connOrDsn));
} }
$this->conn = DriverManager::getConnection(['url' => $connOrDsn]); if (class_exists(DsnParser::class)) {
$params = (new DsnParser([
'db2' => 'ibm_db2',
'mssql' => 'pdo_sqlsrv',
'mysql' => 'pdo_mysql',
'mysql2' => 'pdo_mysql',
'postgres' => 'pdo_pgsql',
'postgresql' => 'pdo_pgsql',
'pgsql' => 'pdo_pgsql',
'sqlite' => 'pdo_sqlite',
'sqlite3' => 'pdo_sqlite',
]))->parse($connOrDsn);
} else {
$params = ['url' => $connOrDsn];
}
$config = new Configuration();
if (class_exists(DefaultSchemaManagerFactory::class)) {
$config->setSchemaManagerFactory(new DefaultSchemaManagerFactory());
}
$this->conn = DriverManager::getConnection($params, $config);
} else { } else {
throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be "%s" or string, "%s" given.', __METHOD__, Connection::class, get_debug_type($connOrDsn))); throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be "%s" or string, "%s" given.', __METHOD__, Connection::class, get_debug_type($connOrDsn)));
} }
@ -156,7 +181,7 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface
$ids, $ids,
], [ ], [
ParameterType::INTEGER, ParameterType::INTEGER,
Connection::PARAM_STR_ARRAY, class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY,
])->iterateNumeric(); ])->iterateNumeric();
foreach ($result as $row) { foreach ($result as $row) {
@ -174,7 +199,7 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface
$expired, $expired,
], [ ], [
ParameterType::INTEGER, ParameterType::INTEGER,
Connection::PARAM_STR_ARRAY, class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY,
]); ]);
} }
} }
@ -226,7 +251,7 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface
{ {
$sql = "DELETE FROM $this->table WHERE $this->idCol IN (?)"; $sql = "DELETE FROM $this->table WHERE $this->idCol IN (?)";
try { try {
$this->conn->executeStatement($sql, [array_values($ids)], [Connection::PARAM_STR_ARRAY]); $this->conn->executeStatement($sql, [array_values($ids)], [class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY]);
} catch (TableNotFoundException $e) { } catch (TableNotFoundException $e) {
} }
@ -285,35 +310,42 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface
$stmt = $this->conn->prepare($sql); $stmt = $this->conn->prepare($sql);
} }
// $id and $data are defined later in the loop. Binding is done by reference, values are read on execution.
if ('sqlsrv' === $platformName || 'oci' === $platformName) { if ('sqlsrv' === $platformName || 'oci' === $platformName) {
$stmt->bindParam(1, $id); $bind = static function ($id, $data) use ($stmt) {
$stmt->bindParam(2, $id); $stmt->bindValue(1, $id);
$stmt->bindParam(3, $data, ParameterType::LARGE_OBJECT); $stmt->bindValue(2, $id);
$stmt->bindValue(3, $data, ParameterType::LARGE_OBJECT);
$stmt->bindValue(6, $data, ParameterType::LARGE_OBJECT);
};
$stmt->bindValue(4, $lifetime, ParameterType::INTEGER); $stmt->bindValue(4, $lifetime, ParameterType::INTEGER);
$stmt->bindValue(5, $now, ParameterType::INTEGER); $stmt->bindValue(5, $now, ParameterType::INTEGER);
$stmt->bindParam(6, $data, ParameterType::LARGE_OBJECT);
$stmt->bindValue(7, $lifetime, ParameterType::INTEGER); $stmt->bindValue(7, $lifetime, ParameterType::INTEGER);
$stmt->bindValue(8, $now, ParameterType::INTEGER); $stmt->bindValue(8, $now, ParameterType::INTEGER);
} elseif (null !== $platformName) { } elseif (null !== $platformName) {
$stmt->bindParam(1, $id); $bind = static function ($id, $data) use ($stmt) {
$stmt->bindParam(2, $data, ParameterType::LARGE_OBJECT); $stmt->bindValue(1, $id);
$stmt->bindValue(2, $data, ParameterType::LARGE_OBJECT);
};
$stmt->bindValue(3, $lifetime, ParameterType::INTEGER); $stmt->bindValue(3, $lifetime, ParameterType::INTEGER);
$stmt->bindValue(4, $now, ParameterType::INTEGER); $stmt->bindValue(4, $now, ParameterType::INTEGER);
} else { } else {
$stmt->bindParam(1, $data, ParameterType::LARGE_OBJECT);
$stmt->bindValue(2, $lifetime, ParameterType::INTEGER); $stmt->bindValue(2, $lifetime, ParameterType::INTEGER);
$stmt->bindValue(3, $now, ParameterType::INTEGER); $stmt->bindValue(3, $now, ParameterType::INTEGER);
$stmt->bindParam(4, $id);
$insertStmt = $this->conn->prepare($insertSql); $insertStmt = $this->conn->prepare($insertSql);
$insertStmt->bindParam(1, $id);
$insertStmt->bindParam(2, $data, ParameterType::LARGE_OBJECT);
$insertStmt->bindValue(3, $lifetime, ParameterType::INTEGER); $insertStmt->bindValue(3, $lifetime, ParameterType::INTEGER);
$insertStmt->bindValue(4, $now, ParameterType::INTEGER); $insertStmt->bindValue(4, $now, ParameterType::INTEGER);
$bind = static function ($id, $data) use ($stmt, $insertStmt) {
$stmt->bindValue(1, $data, ParameterType::LARGE_OBJECT);
$stmt->bindValue(4, $id);
$insertStmt->bindValue(1, $id);
$insertStmt->bindValue(2, $data, ParameterType::LARGE_OBJECT);
};
} }
foreach ($values as $id => $data) { foreach ($values as $id => $data) {
$bind($id, $data);
try { try {
$rowCount = $stmt->executeStatement(); $rowCount = $stmt->executeStatement();
} catch (TableNotFoundException $e) { } catch (TableNotFoundException $e) {

View File

@ -174,6 +174,11 @@ trait RedisTrait
throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package or the "redis" extension v5.2 or higher: "%s".', $dsn)); throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package or the "redis" extension v5.2 or higher: "%s".', $dsn));
} }
if (isset($params['lazy'])) {
$params['lazy'] = filter_var($params['lazy'], \FILTER_VALIDATE_BOOLEAN);
}
$params['redis_cluster'] = filter_var($params['redis_cluster'], \FILTER_VALIDATE_BOOLEAN);
if ($params['redis_cluster'] && isset($params['redis_sentinel'])) { if ($params['redis_cluster'] && isset($params['redis_sentinel'])) {
throw new InvalidArgumentException(sprintf('Cannot use both "redis_cluster" and "redis_sentinel" at the same time: "%s".', $dsn)); throw new InvalidArgumentException(sprintf('Cannot use both "redis_cluster" and "redis_sentinel" at the same time: "%s".', $dsn));
} }

View File

@ -2,7 +2,6 @@
namespace yunwuxin\cron; namespace yunwuxin\cron;
use app\service\core\schedule\CoreScheduleService;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use think\App; use think\App;
@ -27,23 +26,19 @@ class Scheduler
public function __construct(App $app) public function __construct(App $app)
{ {
$this->app = $app; $this->app = $app;
// $this->tasks = $app->config->get('cron.tasks', []); $this->tasks = $app->config->get('cron.tasks', []);
$this->tasks = (new CoreScheduleService())->getList(); $this->cache = $app->cache->store($app->config->get('cron.store', null));
$this->cache = $app->cache->store();
} }
public function run() public function run()
{ {
$this->startedAt = Carbon::now(); $this->startedAt = Carbon::now();
$file = root_path('runtime').'.schedule'; foreach ($this->tasks as $taskClass) {
file_put_contents($file, time());
$taskClass = 'app\command\schedule\Schedule';
foreach ($this->tasks as $task_value) {
if (is_subclass_of($taskClass, Task::class)) { if (is_subclass_of($taskClass, Task::class)) {
/** @var Task $task */ /** @var Task $task */
$task = $this->app->invokeClass($taskClass, [$task_value]); $task = $this->app->invokeClass($taskClass, [$this->cache]);
if ($task->isDue()) { if ($task->isDue()) {
if (!$task->filtersPass()) { if (!$task->filtersPass()) {

View File

@ -36,15 +36,10 @@ abstract class Task
/** @var App */ /** @var App */
protected $app; protected $app;
protected $vars; public function __construct(App $app, Cache $cache)
public function __construct(App $app, $vars)
{ {
$this->app = $app; $this->app = $app;
// $this->cache = $cache; $this->cache = $cache;
$this->cache = $app->cache->store();
$this->vars = $vars;
$this->configure(); $this->configure();
} }

View File

@ -17,8 +17,9 @@ class Schedule extends Command
protected function execute(Input $input, Output $output) protected function execute(Input $input, Output $output)
{ {
if ('\\' == DIRECTORY_SEPARATOR) { if ('\\' == DIRECTORY_SEPARATOR) {
$command = 'start /B "Niucloud Schedule" "' . PHP_BINARY . '" think cron:run'; $command = 'start /B "' . PHP_BINARY . '" think cron:run';
} else { } else {
$command = 'nohup "' . PHP_BINARY . '" think cron:run >> /dev/null 2>&1 &'; $command = 'nohup "' . PHP_BINARY . '" think cron:run >> /dev/null 2>&1 &';
} }