Merge pull request 'dev' (#3) from dev into master

Reviewed-on: #3
This commit is contained in:
weiz 2023-10-16 10:41:42 +08:00
commit 8f05b08b3f
809 changed files with 15896 additions and 21344 deletions

View File

@ -8,7 +8,7 @@ use think\response\Json;
class SuYuanController extends BaseAdminController
{
public array $notNeedLogin = ['areaLists','areaDetail','monitorDetail','imageUpload'];
public array $notNeedLogin = ['areaLists','areaDetail','monitorDetail','imageUpload','monitorList'];
//添加种植基地
public function addArea(): Json
@ -113,15 +113,21 @@ class SuYuanController extends BaseAdminController
if(empty($params['id']) || empty($params['flag'])){
return $this->fail('参数错误');
}
$data = Db::name('environmental_data')->where('id',$params['id'])->where('flag',$params['flag'])->order('id desc')->findOrEmpty();
if($data->isEmpty()){
return $this->success('请求成功',[]);
}
$content = Db::name('production_base')->where('id',$data['production_base_id'])->field('content')->findOrEmpty();
$data['content'] = $content['content'];
$data = Db::name('environmental_data')->where('production_base_id',$params['id'])->where('flag',$params['flag'])->order('id desc')->findOrEmpty();
return $this->success('请求成功',$data);
}
public function monitorList(): Json
{
$params = $this->request->get(['id','flag']);
if(empty($params['id']) || empty($params['flag'])){
return $this->fail('参数错误');
}
$data = Db::name('environmental_data')->where('production_base_id',$params['id'])->where('flag',$params['flag'])->limit(6)->select();
$content = Db::name('production_base')->where('id',$params['id'])->field('content')->findOrEmpty();
return $this->success('请求成功',['data'=>$data,'content'=>$content['content']]);
}
//上传图片
public function imageUpload(): Json
{

1082
composer.lock generated

File diff suppressed because it is too large Load Diff

119
vendor/bin/jp.php vendored Normal file
View File

@ -0,0 +1,119 @@
#!/usr/bin/env php
<?php
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../mtdowling/jmespath.php/bin/jp.php)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
*/
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
if (!class_exists('Composer\BinProxyWrapper')) {
/**
* @internal
*/
final class BinProxyWrapper
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
return (bool) $this->handle;
}
public function stream_read($count)
{
$data = fread($this->handle, $count);
if ($this->position === 0) {
$data = preg_replace('{^#!.*\r?\n}', '', $data);
}
$this->position += strlen($data);
return $data;
}
public function stream_cast($castAs)
{
return $this->handle;
}
public function stream_close()
{
fclose($this->handle);
}
public function stream_lock($operation)
{
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_stat()
{
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/mtdowling/jmespath.php/bin/jp.php');
}
}
return include __DIR__ . '/..'.'/mtdowling/jmespath.php/bin/jp.php';

5
vendor/bin/jp.php.bat vendored Normal file
View File

@ -0,0 +1,5 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/jp.php
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

View File

@ -7,13 +7,14 @@ $baseDir = dirname($vendorDir);
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'CURLStringFile' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Requests' => $vendorDir . '/rmccue/requests/library/Requests.php',
'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Stringable' => $vendorDir . '/myclabs/php-enum/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);

View File

@ -8,7 +8,6 @@ $baseDir = dirname($vendorDir);
return array(
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',

View File

@ -9,7 +9,7 @@ return array(
'think\\view\\driver\\' => array($vendorDir . '/topthink/think-view/src'),
'think\\trace\\' => array($vendorDir . '/topthink/think-trace/src'),
'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'),
'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-template/src', $vendorDir . '/topthink/think-filesystem/src'),
'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-filesystem/src', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-template/src'),
'clagiordano\\weblibs\\configmanager\\' => array($vendorDir . '/clagiordano/weblibs-configmanager/src'),
'app\\' => array($baseDir . '/app'),
'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
@ -50,7 +50,6 @@ return array(
'Nyholm\\Psr7\\' => array($vendorDir . '/nyholm/psr7/src'),
'Nyholm\\Psr7Server\\' => array($vendorDir . '/nyholm/psr7-server/src'),
'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'),
'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'),
'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'),

View File

@ -9,7 +9,6 @@ class ComposerStaticInitd2a74ba94e266cc4f45a64c54a292d7e
public static $files = array (
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
@ -114,7 +113,6 @@ class ComposerStaticInitd2a74ba94e266cc4f45a64c54a292d7e
'M' =>
array (
'MyCLabs\\Enum\\' => 13,
'Monolog\\' => 8,
'Matrix\\' => 7,
),
'L' =>
@ -167,10 +165,10 @@ class ComposerStaticInitd2a74ba94e266cc4f45a64c54a292d7e
'think\\' =>
array (
0 => __DIR__ . '/..' . '/topthink/framework/src/think',
1 => __DIR__ . '/..' . '/topthink/think-helper/src',
2 => __DIR__ . '/..' . '/topthink/think-orm/src',
3 => __DIR__ . '/..' . '/topthink/think-template/src',
4 => __DIR__ . '/..' . '/topthink/think-filesystem/src',
1 => __DIR__ . '/..' . '/topthink/think-filesystem/src',
2 => __DIR__ . '/..' . '/topthink/think-helper/src',
3 => __DIR__ . '/..' . '/topthink/think-orm/src',
4 => __DIR__ . '/..' . '/topthink/think-template/src',
),
'clagiordano\\weblibs\\configmanager\\' =>
array (
@ -334,10 +332,6 @@ class ComposerStaticInitd2a74ba94e266cc4f45a64c54a292d7e
array (
0 => __DIR__ . '/..' . '/myclabs/php-enum/src',
),
'Monolog\\' =>
array (
0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog',
),
'Matrix\\' =>
array (
0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src',
@ -416,13 +410,14 @@ class ComposerStaticInitd2a74ba94e266cc4f45a64c54a292d7e
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'CURLStringFile' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Requests' => __DIR__ . '/..' . '/rmccue/requests/library/Requests.php',
'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Stringable' => __DIR__ . '/..' . '/myclabs/php-enum/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
'name' => 'topthink/think',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '8c9212052304a213c45338424760aea2d904f258',
'reference' => '0b6b29a77bea7bf509dd19e4bc1e20a33d3946d9',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -47,9 +47,9 @@
'dev_requirement' => false,
),
'dragonmantank/cron-expression' => array(
'pretty_version' => 'v3.3.1',
'version' => '3.3.1.0',
'reference' => 'be85b3f05b46c39bbc0d95f6c071ddff669510fa',
'pretty_version' => 'v3.3.3',
'version' => '3.3.3.0',
'reference' => 'adfb1f505deb6384dc8b39804c5065dd3c8c8c0a',
'type' => 'library',
'install_path' => __DIR__ . '/../dragonmantank/cron-expression',
'aliases' => array(),
@ -65,54 +65,54 @@
'dev_requirement' => false,
),
'guzzlehttp/command' => array(
'pretty_version' => '1.2.3',
'version' => '1.2.3.0',
'reference' => '3c9383aaf2e39fa8d39375ae37b95b55964aaef4',
'pretty_version' => '1.3.0',
'version' => '1.3.0.0',
'reference' => '3372bcfd79d4b357b6871665bf06155515e8d844',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/command',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '7.5.1',
'version' => '7.5.1.0',
'reference' => 'b964ca597e86b752cd994f27293e9fa6b6a95ed9',
'pretty_version' => '7.8.0',
'version' => '7.8.0.0',
'reference' => '1110f66a6530a40fe7aea0378fe608ee2b2248f9',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/guzzle-services' => array(
'pretty_version' => '1.3.2',
'version' => '1.3.2.0',
'reference' => '4989d902dd4e0411b320e851c46f3c94d652d891',
'pretty_version' => '1.4.0',
'version' => '1.4.0.0',
'reference' => 'f4bb1c205152a56741624b88753732e01a60565c',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle-services',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '1.5.2',
'version' => '1.5.2.0',
'reference' => 'b94b2807d85443f9719887892882d0329d1e2598',
'pretty_version' => '2.0.1',
'version' => '2.0.1.0',
'reference' => '111166291a0f8130081195ac4556a5587d7f1b5d',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '2.5.0',
'version' => '2.5.0.0',
'reference' => 'b635f279edd83fc275f822a1188157ffea568ff6',
'pretty_version' => '2.6.1',
'version' => '2.6.1.0',
'reference' => 'be45764272e8873c72dbe3d2edcfdfcc3bc9f727',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/uri-template' => array(
'pretty_version' => 'v1.0.1',
'version' => '1.0.1.0',
'reference' => 'b945d74a55a25a949158444f09ec0d3c120d69e2',
'pretty_version' => 'v1.0.2',
'version' => '1.0.2.0',
'reference' => '61bf437fc2197f587f6857d3ff903a24f1731b5d',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/uri-template',
'aliases' => array(),
@ -163,15 +163,6 @@
'aliases' => array(),
'dev_requirement' => false,
),
'monolog/monolog' => array(
'pretty_version' => '2.9.0',
'version' => '2.9.0.0',
'reference' => 'e1c0ae1528ce313a450e5e1ad782765c4a8dd3cb',
'type' => 'library',
'install_path' => __DIR__ . '/../monolog/monolog',
'aliases' => array(),
'dev_requirement' => false,
),
'mtdowling/cron-expression' => array(
'dev_requirement' => false,
'replaced' => array(
@ -179,18 +170,18 @@
),
),
'mtdowling/jmespath.php' => array(
'pretty_version' => '2.6.1',
'version' => '2.6.1.0',
'reference' => '9b87907a81b87bc76d19a7fb2d61e61486ee9edb',
'pretty_version' => '2.7.0',
'version' => '2.7.0.0',
'reference' => 'bbb69a935c2cbb0c03d7f481a238027430f6440b',
'type' => 'library',
'install_path' => __DIR__ . '/../mtdowling/jmespath.php',
'aliases' => array(),
'dev_requirement' => false,
),
'myclabs/php-enum' => array(
'pretty_version' => '1.8.3',
'version' => '1.8.3.0',
'reference' => 'b942d263c641ddb5190929ff840c68f78713e937',
'pretty_version' => '1.8.4',
'version' => '1.8.4.0',
'reference' => 'a867478eae49c9f59ece437ae7f9506bfaa27483',
'type' => 'library',
'install_path' => __DIR__ . '/../myclabs/php-enum',
'aliases' => array(),
@ -215,9 +206,9 @@
'dev_requirement' => false,
),
'overtrue/socialite' => array(
'pretty_version' => '4.8.0',
'version' => '4.8.0.0',
'reference' => 'e55fdf50f8003be8f03a85a7e5a5b7c5716f4c9a',
'pretty_version' => '4.9.0',
'version' => '4.9.0.0',
'reference' => 'dcbb1eed948fe036e6de8cdf0b125f5af1bc73fb',
'type' => 'library',
'install_path' => __DIR__ . '/../overtrue/socialite',
'aliases' => array(),
@ -242,9 +233,9 @@
),
),
'phpoffice/phpspreadsheet' => array(
'pretty_version' => '1.28.0',
'version' => '1.28.0.0',
'reference' => '6e81cf39bbd93ebc3a4e8150444c41e8aa9b769a',
'pretty_version' => '1.29.0',
'version' => '1.29.0.0',
'reference' => 'fde2ccf55eaef7e86021ff1acce26479160a0fa0',
'type' => 'library',
'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet',
'aliases' => array(),
@ -275,9 +266,9 @@
'dev_requirement' => false,
),
'psr/http-client' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
'pretty_version' => '1.0.3',
'version' => '1.0.3.0',
'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-client',
'aliases' => array(),
@ -328,12 +319,6 @@
'aliases' => array(),
'dev_requirement' => false,
),
'psr/log-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '1.0.0 || 2.0.0 || 3.0.0',
),
),
'psr/simple-cache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
@ -350,9 +335,9 @@
),
),
'qcloud/cos-sdk-v5' => array(
'pretty_version' => 'v2.6.2',
'version' => '2.6.2.0',
'reference' => '92a1ee62b85ed4e7bf6836a684df5d7e3158d0ed',
'pretty_version' => 'v2.6.6',
'version' => '2.6.6.0',
'reference' => '9d82ccb550fe2dca1adfb53835791d314023a9a8',
'type' => 'library',
'install_path' => __DIR__ . '/../qcloud/cos-sdk-v5',
'aliases' => array(),
@ -377,18 +362,18 @@
'dev_requirement' => false,
),
'rmccue/requests' => array(
'pretty_version' => 'v2.0.5',
'version' => '2.0.5.0',
'reference' => 'b717f1d2f4ef7992ec0c127747ed8b7e170c2f49',
'pretty_version' => 'v2.0.8',
'version' => '2.0.8.0',
'reference' => 'fae75bcb83d9d00d0e31ee86a472a036f9f91519',
'type' => 'library',
'install_path' => __DIR__ . '/../rmccue/requests',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/cache' => array(
'pretty_version' => 'v5.4.23',
'version' => '5.4.23.0',
'reference' => '983c79ff28612cdfd66d8e44e1a06e5afc87e107',
'pretty_version' => 'v5.4.29',
'version' => '5.4.29.0',
'reference' => 'e29c5a97bc2d81269973c3e1d7ceb9d48b4d5151',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(),
@ -461,81 +446,81 @@
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '5bbc823adecdae860bb64756d639ecfec17b050a',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-idn' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '639084e360537a19f9ee352433b84ce831f3d2da',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => 'ecaafce9f77234a6a449d29e49267ba10499116d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '19bd1e4fcd5b91116f14d8533c57831ed00571b6',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '42292d99c55abe617799667f454222c54c60e229',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php72' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '869329b1e9894268a8a61dabb69153029b7a8c97',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '70f4aebd92afca2f865444d30a4d2151c13c3179',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php72',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php73' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '9e8ecb5f92152187c4799efd3c96b78ccab18ff9',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => 'fe2f306d1d9d346a7fee353d0d5012e401e984b5',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php73',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php81' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '707403074c8ea6e2edaf8794b0157a0bfa52157a',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '7581cd600fa9fd681b797d00b02f068e2f13263b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php81',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/psr-http-message-bridge' => array(
'pretty_version' => 'v2.2.0',
'version' => '2.2.0.0',
'reference' => '28a732c05bbad801304ad5a5c674cf2970508993',
'pretty_version' => 'v2.3.1',
'version' => '2.3.1.0',
'reference' => '581ca6067eb62640de5ff08ee1ba6850a0ee472e',
'type' => 'symfony-bridge',
'install_path' => __DIR__ . '/../symfony/psr-http-message-bridge',
'aliases' => array(),
@ -578,18 +563,18 @@
'dev_requirement' => false,
),
'tencentcloud/common' => array(
'pretty_version' => '3.0.990',
'version' => '3.0.990.0',
'reference' => '0c2705d31c42443ab54422aec7965561141e99ca',
'pretty_version' => '3.0.995',
'version' => '3.0.995.0',
'reference' => '60cb44ef1c52d26964ca1f8974c33b04a20bf36c',
'type' => 'library',
'install_path' => __DIR__ . '/../tencentcloud/common',
'aliases' => array(),
'dev_requirement' => false,
),
'tencentcloud/sms' => array(
'pretty_version' => '3.0.990',
'version' => '3.0.990.0',
'reference' => '2dc4e09ae59950778370f6f438643046deee9882',
'pretty_version' => '3.0.995',
'version' => '3.0.995.0',
'reference' => 'd0de23eea0cd54bf84a2fccab0990deae0d06d48',
'type' => 'library',
'install_path' => __DIR__ . '/../tencentcloud/sms',
'aliases' => array(),
@ -605,9 +590,9 @@
'dev_requirement' => false,
),
'topthink/framework' => array(
'pretty_version' => 'v6.1.2',
'version' => '6.1.2.0',
'reference' => '67235be5b919aaaf1de5aed9839f65d8e766aca3',
'pretty_version' => 'v6.1.4',
'version' => '6.1.4.0',
'reference' => '66eb9cf4d627df12911344cd328faf9bb596bf2c',
'type' => 'library',
'install_path' => __DIR__ . '/../topthink/framework',
'aliases' => array(),
@ -616,7 +601,7 @@
'topthink/think' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '8c9212052304a213c45338424760aea2d904f258',
'reference' => '0b6b29a77bea7bf509dd19e4bc1e20a33d3946d9',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -641,9 +626,9 @@
'dev_requirement' => false,
),
'topthink/think-multi-app' => array(
'pretty_version' => 'v1.0.16',
'version' => '1.0.16.0',
'reference' => '07b9183855150455e1f76f8cbe9d77d6d1bc399f',
'pretty_version' => 'v1.0.17',
'version' => '1.0.17.0',
'reference' => '4055a6187296ac16c0bc7bbab4ed5d92f82f791c',
'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-multi-app',
'aliases' => array(),
@ -686,9 +671,9 @@
'dev_requirement' => false,
),
'w7corp/easywechat' => array(
'pretty_version' => '6.8.0',
'version' => '6.8.0.0',
'reference' => '60f0b4ba2ac3144df1a2291193daa34beb949d26',
'pretty_version' => '6.12.11',
'version' => '6.12.11.0',
'reference' => '81594e1068dadfb6caf354052689cedb2b6394f8',
'type' => 'library',
'install_path' => __DIR__ . '/../w7corp/easywechat',
'aliases' => array(),

View File

@ -1,5 +1,28 @@
# Change Log
## [3.3.3] - 2024-08-10
### Added
- N/A
### Changed
- N/A
### Fixed
- Added fixes for making sure `?` is not passed for both DOM and DOW (#148, thank you https://github.com/LeoVie)
- Fixed bug in Next Execution Time by sorting minutes properly (#160, thank you https://github.com/imyip)
## [3.3.2] - 2022-09-19
### Added
- N/A
### Changed
- Skip some daylight savings time tests for PHP 8.1 daylight savings time weirdness (#146)
### Fixed
- Changed string interpolations to work better with PHP 8.2 (#142)
## [3.3.1] - 2022-01-18
### Added

View File

@ -84,4 +84,4 @@ Projects that Use cron-expression
=================================
* Part of the [Laravel Framework](https://github.com/laravel/framework/)
* Available as a [Symfony Bundle - setono/cron-expression-bundle](https://github.com/Setono/CronExpressionBundle)
* Framework agnostic, PHP-based job scheduler - [Crunz](https://github.com/lavary/crunz)
* Framework agnostic, PHP-based job scheduler - [Crunz](https://github.com/crunzphp/crunz)

View File

@ -37,5 +37,11 @@
"scripts": {
"phpstan": "./vendor/bin/phpstan analyze",
"test": "phpunit"
},
"config": {
"allow-plugins": {
"ocramius/package-versions": true,
"phpstan/extension-installer": true
}
}
}

View File

@ -1,15 +0,0 @@
parameters:
checkMissingIterableValueType: false
ignoreErrors:
- '#Call to an undefined method DateTimeInterface::add\(\)#'
- '#Call to an undefined method DateTimeInterface::modify\(\)#'
- '#Call to an undefined method DateTimeInterface::setDate\(\)#'
- '#Call to an undefined method DateTimeInterface::setTime\(\)#'
- '#Call to an undefined method DateTimeInterface::setTimezone\(\)#'
- '#Call to an undefined method DateTimeInterface::sub\(\)#'
level: max
paths:
- src/

View File

@ -177,6 +177,7 @@ class CronExpression
*
* @param string $expression CRON expression (e.g. '8 * * * *')
* @param null|FieldFactoryInterface $fieldFactory Factory to create cron fields
* @throws InvalidArgumentException
*/
public function __construct(string $expression, FieldFactoryInterface $fieldFactory = null)
{
@ -201,13 +202,22 @@ class CronExpression
$split = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY);
Assert::isArray($split);
$this->cronParts = $split;
if (\count($this->cronParts) < 5) {
$notEnoughParts = \count($split) < 5;
$questionMarkInInvalidPart = array_key_exists(0, $split) && $split[0] === '?'
|| array_key_exists(1, $split) && $split[1] === '?'
|| array_key_exists(3, $split) && $split[3] === '?';
$tooManyQuestionMarks = array_key_exists(2, $split) && $split[2] === '?'
&& array_key_exists(4, $split) && $split[4] === '?';
if ($notEnoughParts || $questionMarkInInvalidPart || $tooManyQuestionMarks) {
throw new InvalidArgumentException(
$value . ' is not a valid CRON expression'
);
}
$this->cronParts = $split;
foreach ($this->cronParts as $position => $part) {
$this->setPart($position, $part);
}

View File

@ -49,7 +49,7 @@ class DayOfMonthField extends AbstractField
private static function getNearestWeekday(int $currentYear, int $currentMonth, int $targetDay): ?DateTime
{
$tday = str_pad((string) $targetDay, 2, '0', STR_PAD_LEFT);
$target = DateTime::createFromFormat('Y-m-d', "${currentYear}-${currentMonth}-${tday}");
$target = DateTime::createFromFormat('Y-m-d', "{$currentYear}-{$currentMonth}-{$tday}");
if ($target === false) {
return null;
@ -94,9 +94,9 @@ class DayOfMonthField extends AbstractField
}
// Check to see if this is the nearest weekday to a particular value
if (strpos($value, 'W')) {
if ($wPosition = strpos($value, 'W')) {
// Parse the target day
$targetDay = (int) substr($value, 0, strpos($value, 'W'));
$targetDay = (int) substr($value, 0, $wPosition);
// Find out if the current day is the nearest day of the week
$nearest = self::getNearestWeekday(
(int) $date->format('Y'),

View File

@ -68,8 +68,8 @@ class DayOfWeekField extends AbstractField
$lastDayOfMonth = (int) $date->format('t');
// Find out if this is the last specific weekday of the month
if (strpos($value, 'L')) {
$weekday = $this->convertLiterals(substr($value, 0, strpos($value, 'L')));
if ($lPosition = strpos($value, 'L')) {
$weekday = $this->convertLiterals(substr($value, 0, $lPosition));
$weekday %= 7;
$daysInMonth = (int) $date->format('t');

View File

@ -25,7 +25,7 @@ class HoursField extends AbstractField
/**
* @var array|null Transitions returned by DateTimeZone::getTransitions()
*/
protected $transitions = null;
protected $transitions = [];
/**
* @var int|null Timestamp of the start of the transitions range
@ -92,7 +92,7 @@ class HoursField extends AbstractField
$dtLimitStart->getTimestamp(),
$dtLimitEnd->getTimestamp()
);
if ($this->transitions === false) {
if (empty($this->transitions)) {
return null;
}
$this->transitionsStart = $dtLimitStart->getTimestamp();

View File

@ -49,6 +49,7 @@ class MinutesField extends AbstractField
$current_minute = (int) $date->format('i');
$parts = false !== strpos($parts, ',') ? explode(',', $parts) : [$parts];
sort($parts);
$minutes = [];
foreach ($parts as $part) {
$minutes = array_merge($minutes, $this->getRangeForExpression($part, 59));

View File

@ -0,0 +1,26 @@
<?php
$config = (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PHP71Migration:risky' => true,
'@PHPUnit75Migration:risky' => true,
'@Symfony' => true,
'declare_strict_types' => false,
'global_namespace_import' => false,
'phpdoc_annotation_without_dot' => false,
'phpdoc_summary' => false,
'phpdoc_to_comment' => false,
'single_line_throw' => false,
'void_return' => false,
'yoda_style' => false,
])
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->name('*.php')
)
;
return $config;

View File

@ -27,19 +27,29 @@
"require": {
"php": "^7.2.5 || ^8.0",
"guzzlehttp/guzzle": "^7.5.1",
"guzzlehttp/promises": "^1.5.2",
"guzzlehttp/promises": "^1.5.3 || ^2.0",
"guzzlehttp/psr7": "^1.9.1 || ^2.4.5"
},
"require-dev": {
"phpunit/phpunit": "^8.5.19"
"bamarni/composer-bin-plugin": "^1.8.1",
"phpunit/phpunit": "^8.5.19 || ^9.5.8"
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Command\\": "src/"
}
},
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"config": {
"preferred-install": "dist",
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"bamarni/composer-bin-plugin": true
}
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command;
use GuzzleHttp\HandlerStack;

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command;
use GuzzleHttp\HandlerStack;

View File

@ -1,7 +1,10 @@
<?php
namespace GuzzleHttp\Command\Exception;
/**
* Exception encountered when a 4xx level response is received for a request
*/
class CommandClientException extends CommandException {}
class CommandClientException extends CommandException
{
}

View File

@ -1,9 +1,10 @@
<?php
namespace GuzzleHttp\Command\Exception;
use GuzzleHttp\Command\CommandInterface;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Command\CommandInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
@ -22,8 +23,6 @@ class CommandException extends \RuntimeException implements GuzzleException
private $response;
/**
* @param CommandInterface $command
* @param \Exception $prev
* @return CommandException
*/
public static function fromPrevious(CommandInterface $command, \Exception $prev)
@ -50,18 +49,17 @@ class CommandException extends \RuntimeException implements GuzzleException
}
// Prepare the message.
$message = 'There was an error executing the ' . $command->getName()
. ' command: ' . $prev->getMessage();
$message = 'There was an error executing the '.$command->getName()
.' command: '.$prev->getMessage();
// Create the exception.
return new $class($message, $command, $prev, $request, $response);
}
/**
* @param string $message Exception message
* @param CommandInterface $command
* @param \Exception $previous Previous exception (if any)
* @param RequestInterface $request
* @param string $message Exception message
* @param \Exception $previous Previous exception (if any)
* @param RequestInterface $request
* @param ResponseInterface $response
*/
public function __construct(

View File

@ -1,7 +1,10 @@
<?php
namespace GuzzleHttp\Command\Exception;
/**
* Exception encountered when a 5xx level response is received for a request
*/
class CommandServerException extends CommandException {}
class CommandServerException extends CommandException
{
}

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command;
/**
@ -8,9 +9,6 @@ class Result implements ResultInterface
{
use HasDataTrait;
/**
* @param array $data
*/
public function __construct(array $data = [])
{
$this->data = $data;

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command;
/**

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command;
use GuzzleHttp\ClientInterface as HttpClient;
@ -20,7 +21,7 @@ class ServiceClient implements ServiceClientInterface
/** @var HandlerStack */
private $handlerStack;
/** @var callable */
private $commandToRequestTransformer;
@ -30,19 +31,19 @@ class ServiceClient implements ServiceClientInterface
/**
* Instantiates a Guzzle ServiceClient for making requests to a web service.
*
* @param HttpClient $httpClient A fully-configured Guzzle HTTP client that
* will be used to perform the underlying HTTP requests.
* @param callable $commandToRequestTransformer A callable that transforms
* a Command into a Request. The function should accept a
* `GuzzleHttp\Command\CommandInterface` object and return a
* `Psr\Http\Message\RequestInterface` object.
* @param callable $responseToResultTransformer A callable that transforms a
* Response into a Result. The function should accept a
* `Psr\Http\Message\ResponseInterface` object (and optionally a
* `Psr\Http\Message\RequestInterface` object) and return a
* `GuzzleHttp\Command\ResultInterface` object.
* @param HandlerStack $commandHandlerStack A Guzzle HandlerStack, which can
* be used to add command-level middleware to the service client.
* @param HttpClient $httpClient A fully-configured Guzzle HTTP client that
* will be used to perform the underlying HTTP requests.
* @param callable $commandToRequestTransformer A callable that transforms
* a Command into a Request. The function should accept a
* `GuzzleHttp\Command\CommandInterface` object and return a
* `Psr\Http\Message\RequestInterface` object.
* @param callable $responseToResultTransformer A callable that transforms a
* Response into a Result. The function should accept a
* `Psr\Http\Message\ResponseInterface` object (and optionally a
* `Psr\Http\Message\RequestInterface` object) and return a
* `GuzzleHttp\Command\ResultInterface` object.
* @param HandlerStack $commandHandlerStack A Guzzle HandlerStack, which can
* be used to add command-level middleware to the service client.
*/
public function __construct(
HttpClient $httpClient,
@ -106,6 +107,7 @@ class ServiceClient implements ServiceClientInterface
return $this->executeAllAsync($commands, $options)
->then(function () use (&$results) {
ksort($results);
return $results;
})
->wait();
@ -119,12 +121,12 @@ class ServiceClient implements ServiceClientInterface
}
// Convert the iterator of commands to a generator of promises.
$commands = Promise\iter_for($commands);
$commands = Promise\Create::iterFor($commands);
$promises = function () use ($commands) {
foreach ($commands as $key => $command) {
if (!$command instanceof CommandInterface) {
throw new \InvalidArgumentException('The iterator must '
. 'yield instances of ' . CommandInterface::class);
.'yield instances of '.CommandInterface::class);
}
yield $key => $this->executeAsync($command);
}
@ -138,9 +140,10 @@ class ServiceClient implements ServiceClientInterface
* Creates and executes a command for an operation by name.
*
* @param string $name Name of the command to execute.
* @param array $args Arguments to pass to the getCommand method.
* @param array $args Arguments to pass to the getCommand method.
*
* @return ResultInterface|PromiseInterface
*
* @see \GuzzleHttp\Command\ServiceClientInterface::getCommand
*/
public function __call($name, array $args)
@ -148,6 +151,7 @@ class ServiceClient implements ServiceClientInterface
$args = isset($args[0]) ? $args[0] : [];
if (substr($name, -5) === 'Async') {
$command = $this->getCommand(substr($name, 0, -5), $args);
return $this->executeAsync($command);
} else {
return $this->execute($this->getCommand($name, $args));
@ -162,7 +166,7 @@ class ServiceClient implements ServiceClientInterface
private function createCommandHandler()
{
return function (CommandInterface $command) {
return Promise\coroutine(function () use ($command) {
return Promise\Coroutine::of(function () use ($command) {
// Prepare the HTTP options.
$opts = $command['@http'] ?: [];
unset($command['@http']);
@ -185,7 +189,6 @@ class ServiceClient implements ServiceClientInterface
/**
* Transforms a Command object into a Request object.
*
* @param CommandInterface $command
* @return RequestInterface
*/
private function transformCommandToRequest(CommandInterface $command)
@ -195,14 +198,10 @@ class ServiceClient implements ServiceClientInterface
return $transform($command);
}
/**
* Transforms a Response object, also using data from the Request object,
* into a Result object.
*
* @param ResponseInterface $response
* @param RequestInterface $request
* @param CommandInterface $command
* @return ResultInterface
*/
private function transformResponseToResult(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command;
use GuzzleHttp\ClientInterface;
@ -22,6 +23,7 @@ interface ServiceClientInterface
* @param array $args Arguments to pass to the command
*
* @return CommandInterface
*
* @throws \InvalidArgumentException if no command can be found by name
*/
public function getCommand($name, array $args = []);
@ -32,6 +34,7 @@ interface ServiceClientInterface
* @param CommandInterface $command Command to execute
*
* @return ResultInterface The result of the executed command
*
* @throws CommandException
*/
public function execute(CommandInterface $command);
@ -49,13 +52,14 @@ interface ServiceClientInterface
* Executes multiple commands concurrently using a fixed pool size.
*
* @param array|\Iterator $commands Array or iterator that contains
* CommandInterface objects to execute with the client.
* @param array $options Associative array of options to apply.
* - concurrency: (int) Max number of commands to execute concurrently.
* - fulfilled: (callable) Function to invoke when a command completes.
* - rejected: (callable) Function to invoke when a command fails.
* CommandInterface objects to execute with the client.
* @param array $options Associative array of options to apply.
* - concurrency: (int) Max number of commands to execute concurrently.
* - fulfilled: (callable) Function to invoke when a command completes.
* - rejected: (callable) Function to invoke when a command fails.
*
* @return array
*
* @see GuzzleHttp\Command\ServiceClientInterface::createPool for options.
*/
public function executeAll($commands, array $options = []);
@ -65,13 +69,14 @@ interface ServiceClientInterface
* fixed pool size.
*
* @param array|\Iterator $commands Array or iterator that contains
* CommandInterface objects to execute with the client.
* @param array $options Associative array of options to apply.
* - concurrency: (int) Max number of commands to execute concurrently.
* - fulfilled: (callable) Function to invoke when a command completes.
* - rejected: (callable) Function to invoke when a command fails.
* CommandInterface objects to execute with the client.
* @param array $options Associative array of options to apply.
* - concurrency: (int) Max number of commands to execute concurrently.
* - fulfilled: (callable) Function to invoke when a command completes.
* - rejected: (callable) Function to invoke when a command fails.
*
* @return PromiseInterface
*
* @see GuzzleHttp\Command\ServiceClientInterface::createPool for options.
*/
public function executeAllAsync($commands, array $options = []);

View File

@ -0,0 +1,9 @@
{
"require": {
"php": "^7.4 || ^8.0",
"friendsofphp/php-cs-fixer": "3.16.0"
},
"config": {
"preferred-install": "dist"
}
}

View File

@ -0,0 +1,26 @@
<?php
$config = (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PHP71Migration:risky' => true,
'@PHPUnit75Migration:risky' => true,
'@Symfony' => true,
'declare_strict_types' => false,
'global_namespace_import' => false,
'phpdoc_annotation_without_dot' => false,
'phpdoc_summary' => false,
'phpdoc_to_comment' => false,
'single_line_throw' => false,
'void_return' => false,
'yoda_style' => false,
])
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->name('*.php')
)
;
return $config;

View File

@ -26,12 +26,13 @@
],
"require": {
"php": "^7.2.5 || ^8.0",
"guzzlehttp/guzzle": "^7.4.1",
"guzzlehttp/command": "^1.2.2",
"guzzlehttp/psr7": "^1.8.3 || ^2.1",
"guzzlehttp/guzzle": "^7.7",
"guzzlehttp/command": "^1.3",
"guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
"guzzlehttp/uri-template": "^1.0.1"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.1",
"phpunit/phpunit": "^8.5.19 || ^9.5.8"
},
"autoload": {
@ -48,12 +49,16 @@
"gimler/guzzle-description-loader": "^0.0.4"
},
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"config": {
"preferred-install": "dist",
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"bamarni/composer-bin-plugin": true
}
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
use GuzzleHttp\Psr7\Uri;
@ -35,7 +36,7 @@ class Description implements DescriptionInterface
/**
* @param array $config Service description data
* @param array $options Custom options to apply to the description
* - formatter: Can provide a custom SchemaFormatter class
* - formatter: Can provide a custom SchemaFormatter class
*
* @throws \InvalidArgumentException
*/
@ -132,6 +133,7 @@ class Description implements DescriptionInterface
* @param string $name Name of the command
*
* @return Operation
*
* @throws \InvalidArgumentException if the operation is not found
*/
public function getOperation($name)
@ -155,6 +157,7 @@ class Description implements DescriptionInterface
* @param string $id ID/name of the model to retrieve
*
* @return Parameter
*
* @throws \InvalidArgumentException if the model is not found
*/
public function getModel($id)
@ -250,7 +253,7 @@ class Description implements DescriptionInterface
*
* @param string $key Data key to retrieve or null to retrieve all extra
*
* @return null|mixed
* @return mixed|null
*/
public function getData($key = null)
{

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
use GuzzleHttp\Psr7\Uri;
@ -34,6 +35,7 @@ interface DescriptionInterface
* @param string $name Name of the command
*
* @return Operation
*
* @throws \InvalidArgumentException if the operation is not found
*/
public function getOperation($name);
@ -44,6 +46,7 @@ interface DescriptionInterface
* @param string $id ID/name of the model to retrieve
*
* @return Parameter
*
* @throws \InvalidArgumentException if the model is not found
*/
public function getModel($id);
@ -101,7 +104,7 @@ interface DescriptionInterface
*
* @param string $key Data key to retrieve or null to retrieve all extra
*
* @return null|mixed
* @return mixed|null
*/
public function getData($key = null);
}

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
use GuzzleHttp\Command\CommandInterface;
@ -29,18 +30,17 @@ use Psr\Http\Message\ResponseInterface;
*/
class Deserializer
{
/** @var ResponseLocationInterface[] $responseLocations */
/** @var ResponseLocationInterface[] */
private $responseLocations;
/** @var DescriptionInterface $description */
/** @var DescriptionInterface */
private $description;
/** @var boolean $process */
/** @var bool */
private $process;
/**
* @param DescriptionInterface $description
* @param bool $process
* @param bool $process
* @param ResponseLocationInterface[] $responseLocations Extra response locations
*/
public function __construct(
@ -51,12 +51,12 @@ class Deserializer
static $defaultResponseLocations;
if (!$defaultResponseLocations) {
$defaultResponseLocations = [
'body' => new BodyLocation(),
'header' => new HeaderLocation(),
'body' => new BodyLocation(),
'header' => new HeaderLocation(),
'reasonPhrase' => new ReasonPhraseLocation(),
'statusCode' => new StatusCodeLocation(),
'xml' => new XmlLocation(),
'json' => new JsonLocation(),
'statusCode' => new StatusCodeLocation(),
'xml' => new XmlLocation(),
'json' => new JsonLocation(),
];
}
@ -68,9 +68,8 @@ class Deserializer
/**
* Deserialize the response into the specified result representation
*
* @param ResponseInterface $response
* @param RequestInterface|null $request
* @param CommandInterface $command
*
* @return Result|ResultInterface|void|ResponseInterface
*/
public function __invoke(ResponseInterface $response, RequestInterface $request, CommandInterface $command)
@ -103,8 +102,6 @@ class Deserializer
/**
* Handles visit() and after() methods of the Response locations
*
* @param Parameter $model
* @param ResponseInterface $response
* @return Result|ResultInterface|void
*/
protected function visit(Parameter $model, ResponseInterface $response)
@ -117,7 +114,7 @@ class Deserializer
} elseif ($model->getType() === 'array') {
$result = $this->visitOuterArray($model, $result, $response, $context);
} else {
throw new \InvalidArgumentException('Invalid response model: ' . $model->getType());
throw new \InvalidArgumentException('Invalid response model: '.$model->getType());
}
// Call the after() method of each found visitor
@ -132,11 +129,8 @@ class Deserializer
/**
* Handles the before() method of Response locations
*
* @param string $location
* @param Parameter $model
* @param ResultInterface $result
* @param ResponseInterface $response
* @param array $context
* @param string $location
*
* @return ResultInterface
*/
private function triggerBeforeVisitor(
@ -164,10 +158,6 @@ class Deserializer
/**
* Visits the outer object
*
* @param Parameter $model
* @param ResultInterface $result
* @param ResponseInterface $response
* @param array $context
* @return ResultInterface
*/
private function visitOuterObject(
@ -212,10 +202,6 @@ class Deserializer
/**
* Visits the outer array
*
* @param Parameter $model
* @param ResultInterface $result
* @param ResponseInterface $response
* @param array $context
* @return ResultInterface|void
*/
private function visitOuterArray(
@ -246,11 +232,6 @@ class Deserializer
* In order for the exception to be properly triggered, all your exceptions must be instance
* of "GuzzleHttp\Command\Exception\CommandException". If that's not the case, your exceptions will be wrapped
* around a CommandException
*
* @param ResponseInterface $response
* @param RequestInterface $request
* @param CommandInterface $command
* @param Operation $operation
*/
protected function handleErrorResponses(
ResponseInterface $response,
@ -271,7 +252,7 @@ class Deserializer
continue;
}
if (isset($error['phrase']) && ! ($error['phrase'] === $response->getReasonPhrase())) {
if (isset($error['phrase']) && !($error['phrase'] === $response->getReasonPhrase())) {
continue;
}

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
use GuzzleHttp\ClientInterface;
@ -12,7 +13,7 @@ use GuzzleHttp\HandlerStack;
*/
class GuzzleClient extends ServiceClient
{
/** @var array $config */
/** @var array */
private $config;
/** @var DescriptionInterface Guzzle service description */
@ -33,12 +34,12 @@ class GuzzleClient extends ServiceClient
* - response_locations: Associative array of location types mapping to
* ResponseLocationInterface objects.
*
* @param ClientInterface $client HTTP client to use.
* @param DescriptionInterface $description Guzzle service description
* @param callable $commandToRequestTransformer
* @param callable $responseToResultTransformer
* @param HandlerStack $commandHandlerStack
* @param array $config Configuration options
* @param ClientInterface $client HTTP client to use.
* @param DescriptionInterface $description Guzzle service description
* @param callable $commandToRequestTransformer
* @param callable $responseToResultTransformer
* @param HandlerStack $commandHandlerStack
* @param array $config Configuration options
*/
public function __construct(
ClientInterface $client,
@ -59,9 +60,11 @@ class GuzzleClient extends ServiceClient
/**
* Returns the command if valid; otherwise an Exception
*
* @param string $name
* @param array $args
*
* @return CommandInterface
*
* @throws \InvalidArgumentException
*/
public function getCommand($name, array $args = [])
@ -95,6 +98,7 @@ class GuzzleClient extends ServiceClient
* Returns the passed Serializer when set, a new instance otherwise
*
* @param callable|null $commandToRequestTransformer
*
* @return \GuzzleHttp\Command\Guzzle\Serializer
*/
private function getSerializer($commandToRequestTransformer)
@ -108,11 +112,12 @@ class GuzzleClient extends ServiceClient
* Returns the passed Deserializer when set, a new instance otherwise
*
* @param callable|null $responseToResultTransformer
*
* @return \GuzzleHttp\Command\Guzzle\Deserializer
*/
private function getDeserializer($responseToResultTransformer)
{
$process = (! isset($this->config['process']) || $this->config['process'] === true);
$process = (!isset($this->config['process']) || $this->config['process'] === true);
return $responseToResultTransformer !== null
? $responseToResultTransformer
@ -123,6 +128,7 @@ class GuzzleClient extends ServiceClient
* Get the config of the client
*
* @param array|string $option
*
* @return mixed
*/
public function getConfig($option = null)
@ -132,10 +138,6 @@ class GuzzleClient extends ServiceClient
: (isset($this->config[$option]) ? $this->config[$option] : []);
}
/**
* @param $option
* @param $value
*/
public function setConfig($option, $value)
{
$this->config[$option] = $value;

View File

@ -1,4 +1,6 @@
<?php namespace GuzzleHttp\Command\Guzzle\Handler;
<?php
namespace GuzzleHttp\Command\Guzzle\Handler;
use GuzzleHttp\Command\CommandInterface;
use GuzzleHttp\Command\Exception\CommandException;
@ -12,17 +14,14 @@ use GuzzleHttp\Command\Guzzle\SchemaValidator;
*/
class ValidatedDescriptionHandler
{
/** @var SchemaValidator $validator */
/** @var SchemaValidator */
private $validator;
/** @var DescriptionInterface $description */
/** @var DescriptionInterface */
private $description;
/**
* ValidatedDescriptionHandler constructor.
*
* @param DescriptionInterface $description
* @param SchemaValidator|null $schemaValidator
*/
public function __construct(DescriptionInterface $description, SchemaValidator $schemaValidator = null)
{
@ -31,7 +30,6 @@ class ValidatedDescriptionHandler
}
/**
* @param callable $handler
* @return \Closure
*/
public function __invoke(callable $handler)
@ -47,7 +45,7 @@ class ValidatedDescriptionHandler
$value = $schema->filter($value);
}
if (! $this->validator->validate($schema, $value)) {
if (!$this->validator->validate($schema, $value)) {
$errors = array_merge($errors, $this->validator->getErrors());
} elseif ($value !== $command[$name]) {
// Update the config value if it changed and no validation errors were encountered.
@ -60,10 +58,10 @@ class ValidatedDescriptionHandler
if ($params = $operation->getAdditionalParameters()) {
foreach ($command->toArray() as $name => $value) {
// It's only additional if it isn't defined in the schema
if (! $operation->hasParam($name)) {
if (!$operation->hasParam($name)) {
// Always set the name so that error messages are useful
$params->setName($name);
if (! $this->validator->validate($params, $value)) {
if (!$this->validator->validate($params, $value)) {
$errors = array_merge($errors, $this->validator->getErrors());
} elseif ($value !== $command[$name]) {
$command[$name] = $value;
@ -73,7 +71,7 @@ class ValidatedDescriptionHandler
}
if ($errors) {
throw new CommandException('Validation errors: ' . implode("\n", $errors), $command);
throw new CommandException('Validation errors: '.implode("\n", $errors), $command);
}
return $handler($command);

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
use GuzzleHttp\Command\ToArrayInterface;
@ -45,8 +46,9 @@ class Operation implements ToArrayInterface
* - additionalParameters: (null|array) Parameter schema to use when an
* option is passed to the operation that is not in the schema
*
* @param array $config Array of configuration data
* @param DescriptionInterface $description Service description used to resolve models if $ref tags are found
* @param array $config Array of configuration data
* @param DescriptionInterface $description Service description used to resolve models if $ref tags are found
*
* @throws \InvalidArgumentException
*/
public function __construct(array $config = [], DescriptionInterface $description = null)
@ -63,7 +65,7 @@ class Operation implements ToArrayInterface
'data' => [],
'parameters' => [],
'additionalParameters' => null,
'errorResponses' => []
'errorResponses' => [],
];
$this->description = $description === null ? new Description([]) : $description;
@ -240,7 +242,7 @@ class Operation implements ToArrayInterface
* Get extra data from the operation
*
* @param string $name Name of the data point to retrieve or null to
* retrieve all of the extra data.
* retrieve all of the extra data.
*
* @return mixed|null
*/
@ -256,14 +258,12 @@ class Operation implements ToArrayInterface
}
/**
* @param $name
* @param array $config
* @return array
*/
private function resolveExtends($name, array $config)
{
if (!$this->description->hasOperation($name)) {
throw new \InvalidArgumentException('No operation named ' . $name);
throw new \InvalidArgumentException('No operation named '.$name);
}
// Merge parameters together one level deep

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
use GuzzleHttp\Command\ToArrayInterface;
@ -6,74 +7,75 @@ use GuzzleHttp\Command\ToArrayInterface;
/**
* API parameter object used with service descriptions
*/
#[\AllowDynamicProperties]
class Parameter implements ToArrayInterface
{
private $originalData;
/** @var string $name */
/** @var string */
private $name;
/** @var string $description */
/** @var string */
private $description;
/** @var string|array $type */
/** @var string|array */
private $type;
/** @var bool $required*/
/** @var bool */
private $required;
/** @var array|null $enum */
/** @var array|null */
private $enum;
/** @var string $pattern */
/** @var string */
private $pattern;
/** @var int $minimum*/
/** @var int */
private $minimum;
/** @var int $maximum */
/** @var int */
private $maximum;
/** @var int $minLength */
/** @var int */
private $minLength;
/** @var int $maxLength */
/** @var int */
private $maxLength;
/** @var int $minItems */
/** @var int */
private $minItems;
/** @var int $maxItems */
/** @var int */
private $maxItems;
/** @var mixed $default */
/** @var mixed */
private $default;
/** @var bool $static */
/** @var bool */
private $static;
/** @var array $filters */
/** @var array */
private $filters;
/** @var string $location */
/** @var string */
private $location;
/** @var string $sentAs */
/** @var string */
private $sentAs;
/** @var array $data */
/** @var array */
private $data;
/** @var array $properties */
/** @var array */
private $properties = [];
/** @var array|bool|Parameter $additionalProperties */
/** @var array|bool|Parameter */
private $additionalProperties;
/** @var array|Parameter $items */
/** @var array|Parameter */
private $items;
/** @var string $format */
/** @var string */
private $format;
private $propertiesCache = null;
@ -171,7 +173,7 @@ class Parameter implements ToArrayInterface
*
* @param array $data Array of data as seen in service descriptions
* @param array $options Options used when creating the parameter. You can
* specify a Guzzle service description in the 'description' key.
* specify a Guzzle service description in the 'description' key.
*
* @throws \InvalidArgumentException
*/
@ -252,8 +254,9 @@ class Parameter implements ToArrayInterface
* @param mixed $value Value to filter
*
* @return mixed Returns the filtered value
*
* @throws \RuntimeException when trying to format when no service
* description is available.
* description is available.
*/
public function filter($value)
{
@ -261,8 +264,9 @@ class Parameter implements ToArrayInterface
if ($this->format) {
if (!$this->serviceDescription) {
throw new \RuntimeException('No service description was set so '
. 'the value cannot be formatted.');
.'the value cannot be formatted.');
}
return $this->serviceDescription->format($this->format, $value);
}
@ -512,7 +516,7 @@ class Parameter implements ToArrayInterface
*
* @param string $name Name of the property to retrieve
*
* @return null|Parameter
* @return Parameter|null
*/
public function getProperty($name)
{
@ -618,6 +622,7 @@ class Parameter implements ToArrayInterface
* @param string|array $filter Method to filter the value through
*
* @return self
*
* @throws \InvalidArgumentException
*/
private function addFilter($filter)
@ -643,13 +648,15 @@ class Parameter implements ToArrayInterface
* Check if a parameter has a specific variable and if it set.
*
* @param string $var
*
* @return bool
*/
public function has($var)
{
if (!is_string($var)) {
throw new \InvalidArgumentException('Expected a string. Got: ' . (is_object($var) ? get_class($var) : gettype($var)));
throw new \InvalidArgumentException('Expected a string. Got: '.(is_object($var) ? get_class($var) : gettype($var)));
}
return isset($this->{$var}) && !empty($this->{$var});
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\QuerySerializer;
interface QuerySerializerInterface
@ -6,8 +7,7 @@ interface QuerySerializerInterface
/**
* Aggregate query params and transform them into a string
*
* @param array $queryParams
* @return string
*/
public function aggregate(array $queryParams);
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\RequestLocation;
use GuzzleHttp\Command\CommandInterface;
@ -13,8 +14,6 @@ abstract class AbstractLocation implements RequestLocationInterface
/**
* Set the name of the location
*
* @param $locationName
*/
public function __construct($locationName)
{
@ -22,9 +21,6 @@ abstract class AbstractLocation implements RequestLocationInterface
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Parameter $param
* @return RequestInterface
*/
public function visit(
@ -36,9 +32,6 @@ abstract class AbstractLocation implements RequestLocationInterface
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Operation $operation
* @return RequestInterface
*/
public function after(
@ -53,8 +46,7 @@ abstract class AbstractLocation implements RequestLocationInterface
* Prepare (filter and set desired name for request item) the value for
* request.
*
* @param mixed $value
* @param Parameter $param
* @param mixed $value
*
* @return array|mixed
*/

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\RequestLocation;
use GuzzleHttp\Command\CommandInterface;
@ -12,7 +13,6 @@ use Psr\Http\Message\RequestInterface;
*/
class BodyLocation extends AbstractLocation
{
/**
* Set the name of the location
*
@ -24,10 +24,6 @@ class BodyLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Parameter $param
*
* @return MessageInterface
*/
public function visit(
@ -38,10 +34,10 @@ class BodyLocation extends AbstractLocation
$oldValue = $request->getBody()->getContents();
$value = $command[$param->getName()];
$value = $param->getName() . '=' . $param->filter($value);
$value = $param->getName().'='.$param->filter($value);
if ($oldValue !== '') {
$value = $oldValue . '&' . $value;
$value = $oldValue.'&'.$value;
}
return $request->withBody(Psr7\Utils::streamFor($value));

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\RequestLocation;
use GuzzleHttp\Command\CommandInterface;
@ -12,10 +13,10 @@ use Psr\Http\Message\RequestInterface;
*/
class FormParamLocation extends AbstractLocation
{
/** @var string $contentType */
/** @var string */
protected $contentType = 'application/x-www-form-urlencoded; charset=utf-8';
/** @var array $formParamsData */
/** @var array */
protected $formParamsData = [];
/**
@ -29,10 +30,6 @@ class FormParamLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Parameter $param
*
* @return RequestInterface
*/
public function visit(
@ -49,10 +46,6 @@ class FormParamLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Operation $operation
*
* @return RequestInterface
*/
public function after(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\RequestLocation;
use GuzzleHttp\Command\CommandInterface;
@ -12,7 +13,6 @@ use Psr\Http\Message\RequestInterface;
*/
class HeaderLocation extends AbstractLocation
{
/**
* Set the name of the location
*
@ -24,10 +24,6 @@ class HeaderLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Parameter $param
*
* @return MessageInterface
*/
public function visit(
@ -41,10 +37,6 @@ class HeaderLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Operation $operation
*
* @return RequestInterface
*/
public function after(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\RequestLocation;
use GuzzleHttp\Command\CommandInterface;
@ -23,7 +24,7 @@ class JsonLocation extends AbstractLocation
/**
* @param string $locationName Name of the location
* @param string $contentType Content-Type header to add to the request if
* JSON is added to the body. Pass an empty string to omit.
* JSON is added to the body. Pass an empty string to omit.
*/
public function __construct($locationName = 'json', $contentType = 'application/json')
{
@ -32,10 +33,6 @@ class JsonLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Parameter $param
*
* @return RequestInterface
*/
public function visit(
@ -52,10 +49,6 @@ class JsonLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Operation $operation
*
* @return MessageInterface
*/
public function after(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\RequestLocation;
use GuzzleHttp\Command\CommandInterface;
@ -12,10 +13,10 @@ use Psr\Http\Message\RequestInterface;
*/
class MultiPartLocation extends AbstractLocation
{
/** @var string $contentType */
/** @var string */
protected $contentType = 'multipart/form-data; boundary=';
/** @var array $formParamsData */
/** @var array */
protected $multipartData = [];
/**
@ -29,9 +30,6 @@ class MultiPartLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Parameter $param
* @return RequestInterface
*/
public function visit(
@ -41,17 +39,13 @@ class MultiPartLocation extends AbstractLocation
) {
$this->multipartData[] = [
'name' => $param->getWireName(),
'contents' => $this->prepareValue($command[$param->getName()], $param)
'contents' => $this->prepareValue($command[$param->getName()], $param),
];
return $request;
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Operation $operation
* @return RequestInterface
*/
public function after(
@ -68,7 +62,7 @@ class MultiPartLocation extends AbstractLocation
$request = Psr7\Utils::modifyRequest($request, $modify);
if ($request->getBody() instanceof Psr7\MultipartStream) {
// Use a multipart/form-data POST if a Content-Type is not set.
$request->withHeader('Content-Type', $this->contentType . $request->getBody()->getBoundary());
$request->withHeader('Content-Type', $this->contentType.$request->getBody()->getBoundary());
}
return $request;

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\RequestLocation;
use GuzzleHttp\Command\CommandInterface;
@ -22,8 +23,7 @@ class QueryLocation extends AbstractLocation
/**
* Set the name of the location
*
* @param string $locationName
* @param QuerySerializerInterface|null $querySerializer
* @param string $locationName
*/
public function __construct($locationName = 'query', QuerySerializerInterface $querySerializer = null)
{
@ -33,10 +33,6 @@ class QueryLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Parameter $param
*
* @return RequestInterface
*/
public function visit(
@ -58,10 +54,6 @@ class QueryLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Operation $operation
*
* @return RequestInterface
*/
public function after(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\RequestLocation;
use GuzzleHttp\Command\CommandInterface;
@ -24,8 +25,8 @@ class XmlLocation extends AbstractLocation
/**
* @param string $locationName Name of the location
* @param string $contentType Set to a non-empty string to add a
* Content-Type header to a request if any XML content is added to the
* body. Pass an empty string to disable the addition of the header.
* Content-Type header to a request if any XML content is added to the
* body. Pass an empty string to disable the addition of the header.
*/
public function __construct($locationName = 'xml', $contentType = 'application/xml')
{
@ -34,10 +35,6 @@ class XmlLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Parameter $param
*
* @return RequestInterface
*/
public function visit(
@ -58,10 +55,6 @@ class XmlLocation extends AbstractLocation
}
/**
* @param CommandInterface $command
* @param RequestInterface $request
* @param Operation $operation
*
* @return RequestInterface
*/
public function after(
@ -149,8 +142,8 @@ class XmlLocation extends AbstractLocation
* Recursively build the XML body
*
* @param \XMLWriter $writer XML to modify
* @param Parameter $param API Parameter
* @param mixed $value Value to add
* @param Parameter $param API Parameter
* @param mixed $value Value to add
*/
protected function addXml(\XMLWriter $writer, Parameter $param, $value)
{
@ -179,6 +172,7 @@ class XmlLocation extends AbstractLocation
if (!$param->getData('xmlFlattened')) {
$writer->endElement();
}
return;
}
if ($param->getData('xmlAttribute')) {
@ -191,11 +185,11 @@ class XmlLocation extends AbstractLocation
/**
* Write an attribute with namespace if used
*
* @param \XMLWriter $writer XMLWriter instance
* @param string $prefix Namespace prefix if any
* @param string $name Attribute name
* @param string $namespace The uri of the namespace
* @param string $value The attribute content
* @param \XMLWriter $writer XMLWriter instance
* @param string $prefix Namespace prefix if any
* @param string $name Attribute name
* @param string $namespace The uri of the namespace
* @param string $value The attribute content
*/
protected function writeAttribute($writer, $prefix, $name, $namespace, $value)
{
@ -209,11 +203,11 @@ class XmlLocation extends AbstractLocation
/**
* Write an element with namespace if used
*
* @param \XMLWriter $writer XML writer resource
* @param string $prefix Namespace prefix if any
* @param string $name Element name
* @param string $namespace The uri of the namespace
* @param string $value The element content
* @param \XMLWriter $writer XML writer resource
* @param string $prefix Namespace prefix if any
* @param string $name Element name
* @param string $namespace The uri of the namespace
* @param string $value The element content
*/
protected function writeElement(\XMLWriter $writer, $prefix, $name, $namespace, $value)
{
@ -233,9 +227,10 @@ class XmlLocation extends AbstractLocation
/**
* Create a new xml writer and start a document
*
* @param string $encoding document encoding
* @param string $encoding document encoding
*
* @return \XMLWriter the writer resource
*
* @throws \RuntimeException if the document cannot be started
*/
protected function startDocument($encoding)
@ -267,10 +262,6 @@ class XmlLocation extends AbstractLocation
/**
* Add an array to the XML
*
* @param \XMLWriter $writer
* @param Parameter $param
* @param $value
*/
protected function addXmlArray(\XMLWriter $writer, Parameter $param, &$value)
{
@ -283,10 +274,6 @@ class XmlLocation extends AbstractLocation
/**
* Add an object to the XML
*
* @param \XMLWriter $writer
* @param Parameter $param
* @param $value
*/
protected function addXmlObject(\XMLWriter $writer, Parameter $param, &$value)
{
@ -309,11 +296,6 @@ class XmlLocation extends AbstractLocation
}
}
/**
* @param $value
* @param Parameter $param
* @param Operation $operation
*/
private function visitWithValue(
$value,
Parameter $param,

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;
@ -7,18 +8,14 @@ use Psr\Http\Message\ResponseInterface;
/**
* Class AbstractLocation
*
* @package GuzzleHttp\Command\Guzzle\ResponseLocation
*/
abstract class AbstractLocation implements ResponseLocationInterface
{
/** @var string $locationName */
/** @var string */
protected $locationName;
/**
* Set the name of the location
*
* @param $locationName
*/
public function __construct($locationName)
{
@ -26,9 +23,6 @@ abstract class AbstractLocation implements ResponseLocationInterface
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $model
* @return ResultInterface
*/
public function before(
@ -40,9 +34,6 @@ abstract class AbstractLocation implements ResponseLocationInterface
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $model
* @return ResultInterface
*/
public function after(
@ -54,9 +45,6 @@ abstract class AbstractLocation implements ResponseLocationInterface
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $param
* @return ResultInterface
*/
public function visit(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;
@ -10,7 +11,6 @@ use Psr\Http\Message\ResponseInterface;
*/
class BodyLocation extends AbstractLocation
{
/**
* Set the name of the location
*
@ -22,9 +22,6 @@ class BodyLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $param
* @return ResultInterface
*/
public function visit(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;
@ -10,7 +11,6 @@ use Psr\Http\Message\ResponseInterface;
*/
class HeaderLocation extends AbstractLocation
{
/**
* Set the name of the location
*
@ -22,10 +22,6 @@ class HeaderLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $param
*
* @return ResultInterface
*/
public function visit(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;
@ -25,10 +26,6 @@ class JsonLocation extends AbstractLocation
}
/**
* @param \GuzzleHttp\Command\ResultInterface $result
* @param \Psr\Http\Message\ResponseInterface $response
* @param \GuzzleHttp\Command\Guzzle\Parameter $model
*
* @return \GuzzleHttp\Command\ResultInterface
*/
public function before(
@ -37,7 +34,7 @@ class JsonLocation extends AbstractLocation
Parameter $model
) {
$body = (string) $response->getBody();
$body = $body ?: "{}";
$body = $body ?: '{}';
$this->json = \GuzzleHttp\json_decode($body, true);
// relocate named arrays, so that they have the same structure as
// arrays nested in objects and visit can work on them in the same way
@ -49,9 +46,6 @@ class JsonLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $model
* @return ResultInterface
*/
public function after(
@ -84,9 +78,6 @@ class JsonLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $param
* @return Result|ResultInterface
*/
public function visit(
@ -123,6 +114,7 @@ class JsonLocation extends AbstractLocation
*
* @param Parameter $param API parameter being validated
* @param mixed $value Value to process.
*
* @return mixed|null
*/
private function recurse(Parameter $param, $value)

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;
@ -10,7 +11,6 @@ use Psr\Http\Message\ResponseInterface;
*/
class ReasonPhraseLocation extends AbstractLocation
{
/**
* Set the name of the location
*
@ -22,9 +22,6 @@ class ReasonPhraseLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $param
* @return ResultInterface
*/
public function visit(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;
@ -10,7 +11,6 @@ use Psr\Http\Message\ResponseInterface;
*/
class StatusCodeLocation extends AbstractLocation
{
/**
* Set the name of the location
*
@ -22,9 +22,6 @@ class StatusCodeLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $param
* @return ResultInterface
*/
public function visit(

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle\ResponseLocation;
use GuzzleHttp\Command\Guzzle\Parameter;
@ -25,9 +26,6 @@ class XmlLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $model
* @return ResultInterface
*/
public function before(
@ -41,9 +39,6 @@ class XmlLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $model
* @return Result|ResultInterface
*/
public function after(
@ -68,9 +63,6 @@ class XmlLocation extends AbstractLocation
}
/**
* @param ResultInterface $result
* @param ResponseInterface $response
* @param Parameter $param
* @return ResultInterface
*/
public function visit(
@ -80,7 +72,7 @@ class XmlLocation extends AbstractLocation
) {
$sentAs = $param->getWireName();
$ns = null;
if (strstr($sentAs, ':')) {
if (null !== $sentAs && strstr($sentAs, ':')) {
list($ns, $sentAs) = explode(':', $sentAs);
}
@ -100,6 +92,7 @@ class XmlLocation extends AbstractLocation
*
* @param Parameter $param API parameter being processed
* @param \SimpleXMLElement $node Node being processed
*
* @return array
*/
private function recursiveProcess(
@ -132,8 +125,6 @@ class XmlLocation extends AbstractLocation
}
/**
* @param Parameter $param
* @param \SimpleXMLElement $node
* @return array
*/
private function processArray(Parameter $param, \SimpleXMLElement $node)
@ -144,7 +135,7 @@ class XmlLocation extends AbstractLocation
$result = [];
$ns = null;
if (strstr($sentAs, ':')) {
if (null !== $sentAs && strstr($sentAs, ':')) {
// Get namespace from the wire name
list($ns, $sentAs) = explode(':', $sentAs);
} else {
@ -174,6 +165,7 @@ class XmlLocation extends AbstractLocation
*
* @param Parameter $param API parameter being parsed
* @param \SimpleXMLElement $node Value to process
*
* @return array
*/
private function processObject(Parameter $param, \SimpleXMLElement $node)
@ -243,9 +235,8 @@ class XmlLocation extends AbstractLocation
/**
* Convert an XML document to an array.
*
* @param \SimpleXMLElement $xml
* @param int $nesting
* @param null $ns
* @param int $nesting
* @param null $ns
*
* @return array
*/

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
/**
@ -41,6 +42,7 @@ class SchemaFormatter
* @param string $format Format of the result
*
* @return string
*
* @throws \InvalidArgumentException
*/
protected function dateFormatter($dateTime, $format)
@ -58,18 +60,19 @@ class SchemaFormatter
if (!$utc) {
$utc = new \DateTimeZone('UTC');
}
return $dateTime->setTimezone($utc)->format($format);
}
throw new \InvalidArgumentException('Date/Time values must be either '
. 'be a string, integer, or DateTime object');
.'be a string, integer, or DateTime object');
}
/**
* Create a ISO 8601 (YYYY-MM-DDThh:mm:ssZ) formatted date time value in
* UTC time.
*
* @param string|integer|\DateTime $value Date time value
* @param string|int|\DateTime $value Date time value
*
* @return string
*/
@ -81,7 +84,7 @@ class SchemaFormatter
/**
* Create an HTTP date (RFC 1123 / RFC 822) formatted UTC date-time string
*
* @param string|integer|\DateTime $value Date time value
* @param string|int|\DateTime $value Date time value
*
* @return string
*/
@ -93,7 +96,7 @@ class SchemaFormatter
/**
* Create a YYYY-MM-DD formatted string
*
* @param string|integer|\DateTime $value Date time value
* @param string|int|\DateTime $value Date time value
*
* @return string
*/
@ -105,7 +108,7 @@ class SchemaFormatter
/**
* Create a hh:mm:ss formatted string
*
* @param string|integer|\DateTime $value Date time value
* @param string|int|\DateTime $value Date time value
*
* @return string
*/
@ -117,8 +120,8 @@ class SchemaFormatter
/**
* Formats a boolean value as a string
*
* @param string|integer|bool $value Value to convert to a boolean
* 'true' / 'false' value
* @param string|int|bool $value Value to convert to a boolean
* 'true' / 'false' value
*
* @return string
*/
@ -130,7 +133,7 @@ class SchemaFormatter
/**
* Return a UNIX timestamp in the UTC timezone
*
* @param string|integer|\DateTime $value Time value
* @param string|int|\DateTime $value Time value
*
* @return int
*/

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
use GuzzleHttp\Command\ToArrayInterface;
@ -21,8 +22,8 @@ class SchemaValidator
/**
* @param bool $castIntegerToStringType Set to true to convert integers
* into strings when a required type is a string and the input value is
* an integer. Defaults to true.
* into strings when a required type is a string and the input value is
* an integer. Defaults to true.
*/
public function __construct($castIntegerToStringType = true)
{
@ -30,8 +31,6 @@ class SchemaValidator
}
/**
* @param Parameter $param
* @param $value
* @return bool
*/
public function validate(Parameter $param, &$value)
@ -43,6 +42,7 @@ class SchemaValidator
return true;
} else {
sort($this->errors);
return false;
}
}
@ -60,8 +60,8 @@ class SchemaValidator
/**
* From the allowable types, determine the type that the variable matches
*
* @param string|array $type Parameter type
* @param mixed $value Value to determine the type
* @param string|array $type Parameter type
* @param mixed $value Value to determine the type
*
* @return string|false Returns the matching type on
*/
@ -97,11 +97,11 @@ class SchemaValidator
/**
* Recursively validate a parameter
*
* @param Parameter $param API parameter being validated
* @param mixed $value Value to validate and validate. The value may
* change during this validate.
* @param string $path Current validation path (used for error reporting)
* @param int $depth Current depth in the validation validate
* @param Parameter $param API parameter being validated
* @param mixed $value Value to validate and validate. The value may
* change during this validate.
* @param string $path Current validation path (used for error reporting)
* @param int $depth Current depth in the validation validate
*
* @return bool Returns true if valid, or false if invalid
*/
@ -146,6 +146,7 @@ class SchemaValidator
// indexed
if (isset($value[0])) {
$this->errors[] = "{$path} must be an array of properties. Got a numerically indexed array.";
return false;
}
$traverse = true;
@ -208,24 +209,24 @@ class SchemaValidator
$valueIsArray = false;
}
}
} elseif ($type == 'array' && $valueIsArray && $param->getItems()) {
foreach ($value as $i => &$item) {
// Validate each item in an array against the items attribute of the schema
$this->recursiveProcess($param->getItems(), $item, $path . "[{$i}]", $depth + 1);
$this->recursiveProcess($param->getItems(), $item, $path."[{$i}]", $depth + 1);
}
}
// If the value is required and the type is not null, then there is an
// error if the value is not set
if ($required && $value === null && $type != 'null') {
$message = "{$path} is " . ($param->getType()
? ('a required ' . implode(' or ', (array) $param->getType()))
$message = "{$path} is ".($param->getType()
? ('a required '.implode(' or ', (array) $param->getType()))
: 'required');
if ($param->has('description')) {
$message .= ': ' . $param->getDescription();
$message .= ': '.$param->getDescription();
}
$this->errors[] = $message;
return false;
}
@ -239,7 +240,7 @@ class SchemaValidator
) {
$value = (string) $value;
} else {
$this->errors[] = "{$path} must be of type " . implode(' or ', (array) $param->getType());
$this->errors[] = "{$path} must be of type ".implode(' or ', (array) $param->getType());
}
}
@ -247,12 +248,12 @@ class SchemaValidator
if ($type == 'string') {
// Strings can have enums which are a list of predefined values
if (($enum = $param->getEnum()) && !in_array($value, $enum)) {
$this->errors[] = "{$path} must be one of " . implode(' or ', array_map(function ($s) {
return '"' . addslashes($s) . '"';
$this->errors[] = "{$path} must be one of ".implode(' or ', array_map(function ($s) {
return '"'.addslashes($s).'"';
}, $enum));
}
// Strings can have a regex pattern that the value must match
if (($pattern = $param->getPattern()) && !preg_match($pattern, $value)) {
if (($pattern = $param->getPattern()) && !preg_match($pattern, $value)) {
$this->errors[] = "{$path} must match the following regular expression: {$pattern}";
}
@ -268,7 +269,6 @@ class SchemaValidator
$this->errors[] = "{$path} length must be less than or equal to {$max}";
}
}
} elseif ($type == 'array') {
$size = null;
if ($min = $param->getMinItems()) {
@ -282,7 +282,6 @@ class SchemaValidator
$this->errors[] = "{$path} must contain {$max} or fewer elements";
}
}
} elseif ($type == 'integer' || $type == 'number' || $type == 'numeric') {
if (($min = $param->getMinimum()) && $value < $min) {
$this->errors[] = "{$path} must be greater than or equal to {$min}";

View File

@ -1,4 +1,5 @@
<?php
namespace GuzzleHttp\Command\Guzzle;
use GuzzleHttp\Command\CommandInterface;
@ -28,7 +29,6 @@ class Serializer
private $description;
/**
* @param DescriptionInterface $description
* @param RequestLocationInterface[] $requestLocations Extra request locations
*/
public function __construct(
@ -38,11 +38,11 @@ class Serializer
static $defaultRequestLocations;
if (!$defaultRequestLocations) {
$defaultRequestLocations = [
'body' => new BodyLocation(),
'query' => new QueryLocation(),
'header' => new HeaderLocation(),
'json' => new JsonLocation(),
'xml' => new XmlLocation(),
'body' => new BodyLocation(),
'query' => new QueryLocation(),
'header' => new HeaderLocation(),
'json' => new JsonLocation(),
'xml' => new XmlLocation(),
'formParam' => new FormParamLocation(),
'multipart' => new MultiPartLocation(),
];
@ -53,21 +53,22 @@ class Serializer
}
/**
* @param CommandInterface $command
* @return RequestInterface
*/
public function __invoke(CommandInterface $command)
{
$request = $this->createRequest($command);
return $this->prepareRequest($command, $request);
}
/**
* Prepares a request for sending using location visitors
*
* @param CommandInterface $command
* @param RequestInterface $request Request being created
*
* @return RequestInterface
*
* @throws \RuntimeException If a location cannot be handled
*/
protected function prepareRequest(
@ -109,9 +110,8 @@ class Serializer
/**
* Create a request for the command and operation
*
* @param CommandInterface $command
*
* @return RequestInterface
*
* @throws \RuntimeException
*/
protected function createRequest(CommandInterface $command)
@ -133,7 +133,6 @@ class Serializer
* Create a request for an operation with a uri merged onto a base URI
*
* @param \GuzzleHttp\Command\Guzzle\Operation $operation
* @param \GuzzleHttp\Command\CommandInterface $command
*
* @return \GuzzleHttp\Psr7\Request
*/

View File

@ -0,0 +1,9 @@
{
"require": {
"php": "^7.4 || ^8.0",
"friendsofphp/php-cs-fixer": "3.16.0"
},
"config": {
"preferred-install": "dist"
}
}

View File

@ -2,6 +2,56 @@
Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version.
## 7.8.0 - 2023-08-27
### Added
- Support for PHP 8.3
- Added automatic closing of handles on `CurlFactory` object destruction
## 7.7.1 - 2023-08-27
### Changed
- Remove the need for `AllowDynamicProperties` in `CurlMultiHandler`
## 7.7.0 - 2023-05-21
### Added
- Support `guzzlehttp/promises` v2
## 7.6.1 - 2023-05-15
### Fixed
- Fix `SetCookie::fromString` MaxAge deprecation warning and skip invalid MaxAge values
## 7.6.0 - 2023-05-14
### Added
- Support for setting the minimum TLS version in a unified way
- Apply on request the version set in options parameters
## 7.5.2 - 2023-05-14
### Fixed
- Fixed set cookie constructor validation
- Fixed handling of files with `'0'` body
### Changed
- Corrected docs and default connect timeout value to 300 seconds
## 7.5.1 - 2023-04-17
### Fixed
@ -12,6 +62,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- Adjusted `guzzlehttp/psr7` version constraint to `^1.9.1 || ^2.4.5`
## 7.5.0 - 2022-08-28
### Added
@ -19,6 +70,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- Support PHP 8.2
- Add request to delay closure params
## 7.4.5 - 2022-06-20
### Fixed
@ -26,6 +78,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
* Fix change in port should be considered a change in origin
* Fix `CURLOPT_HTTPAUTH` option not cleared on change of origin
## 7.4.4 - 2022-06-09
### Fixed
@ -33,12 +86,14 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
* Fix failure to strip Authorization header on HTTP downgrade
* Fix failure to strip the Cookie header on change in host or HTTP downgrade
## 7.4.3 - 2022-05-25
### Fixed
* Fix cross-domain cookie leakage
## 7.4.2 - 2022-03-20
### Fixed
@ -47,6 +102,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- Reject non-HTTP schemes in StreamHandler
- Set a default ssl.peer_name context in StreamHandler to allow `force_ip_resolve`
## 7.4.1 - 2021-12-06
### Changed
@ -58,6 +114,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- Only close curl handle if it's done [#2950](https://github.com/guzzle/guzzle/pull/2950)
## 7.4.0 - 2021-10-18
### Added
@ -75,6 +132,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- Be more strict with types [#2914](https://github.com/guzzle/guzzle/pull/2914), [#2917](https://github.com/guzzle/guzzle/pull/2917), [#2919](https://github.com/guzzle/guzzle/pull/2919), [#2945](https://github.com/guzzle/guzzle/pull/2945)
## 7.3.0 - 2021-03-23
### Added
@ -87,6 +145,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- Handle exceptions on invalid header consistently between PHP versions and handlers [#2872](https://github.com/guzzle/guzzle/pull/2872)
## 7.2.0 - 2020-10-10
### Added
@ -109,6 +168,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- Using environment variable GUZZLE_CURL_SELECT_TIMEOUT [#2786](https://github.com/guzzle/guzzle/pull/2786)
## 7.1.1 - 2020-09-30
### Fixed
@ -120,6 +180,7 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- We dont connect curl `sink` on HEAD requests.
- Removed some PHP 5 workarounds
## 7.1.0 - 2020-09-22
### Added
@ -142,14 +203,17 @@ Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version
- `Utils::defaultCaBundle()`
- `CurlFactory::LOW_CURL_VERSION_NUMBER`
## 7.0.1 - 2020-06-27
* Fix multiply defined functions fatal error [#2699](https://github.com/guzzle/guzzle/pull/2699)
## 7.0.0 - 2020-06-27
No changes since 7.0.0-rc1.
## 7.0.0-rc1 - 2020-06-15
### Changed
@ -157,6 +221,7 @@ No changes since 7.0.0-rc1.
* Use error level for logging errors in Middleware [#2629](https://github.com/guzzle/guzzle/pull/2629)
* Disabled IDN support by default and require ext-intl to use it [#2675](https://github.com/guzzle/guzzle/pull/2675)
## 7.0.0-beta2 - 2020-05-25
### Added
@ -182,6 +247,7 @@ No changes since 7.0.0-rc1.
* Pool option `pool_size` [#2528](https://github.com/guzzle/guzzle/pull/2528)
## 7.0.0-beta1 - 2019-12-30
The diff might look very big but 95% of Guzzle users will be able to upgrade without modification.
@ -215,15 +281,18 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* `uri_template()` and `UriTemplate` [#2440](https://github.com/guzzle/guzzle/pull/2440)
* Request options `save_to` and `exceptions` [#2464](https://github.com/guzzle/guzzle/pull/2464)
## 6.5.2 - 2019-12-23
* idn_to_ascii() fix for old PHP versions [#2489](https://github.com/guzzle/guzzle/pull/2489)
## 6.5.1 - 2019-12-21
* Better defaults for PHP installations with old ICU lib [#2454](https://github.com/guzzle/guzzle/pull/2454)
* IDN support for redirects [#2424](https://github.com/guzzle/guzzle/pull/2424)
## 6.5.0 - 2019-12-07
* Improvement: Added support for reset internal queue in MockHandler. [#2143](https://github.com/guzzle/guzzle/pull/2143)
@ -233,11 +302,13 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Fix: Prevent undefined offset when using array for ssl_key options. [#2348](https://github.com/guzzle/guzzle/pull/2348)
* Deprecated `ClientInterface::VERSION`
## 6.4.1 - 2019-10-23
* No `guzzle.phar` was created in 6.4.0 due expired API token. This release will fix that
* Added `parent::__construct()` to `FileCookieJar` and `SessionCookieJar`
## 6.4.0 - 2019-10-23
* Improvement: Improved error messages when using curl < 7.21.2 [#2108](https://github.com/guzzle/guzzle/pull/2108)
@ -250,6 +321,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Fix: Prevent concurrent writes to file when saving `CookieJar` [#2335](https://github.com/guzzle/guzzle/pull/2335)
* Improvement: Update `MockHandler` so we can test transfer time [#2362](https://github.com/guzzle/guzzle/pull/2362)
## 6.3.3 - 2018-04-22
* Fix: Default headers when decode_content is specified
@ -291,13 +363,14 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Bug fix: Fill `CURLOPT_CAPATH` and `CURLOPT_CAINFO` properly [#1684](https://github.com/guzzle/guzzle/pull/1684)
* Improvement: Use `\GuzzleHttp\Promise\rejection_for` function instead of object init [#1827](https://github.com/guzzle/guzzle/pull/1827)
+ Minor code cleanups, documentation fixes and clarifications.
## 6.2.3 - 2017-02-28
* Fix deprecations with guzzle/psr7 version 1.4
## 6.2.2 - 2016-10-08
* Allow to pass nullable Response to delay callable
@ -305,6 +378,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Fix drain case where content-length is the literal string zero
* Obfuscate in-URL credentials in exceptions
## 6.2.1 - 2016-07-18
* Address HTTP_PROXY security vulnerability, CVE-2016-5385:
@ -315,6 +389,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
a server does not honor `Connection: close`.
* Ignore URI fragment when sending requests.
## 6.2.0 - 2016-03-21
* Feature: added `GuzzleHttp\json_encode` and `GuzzleHttp\json_decode`.
@ -334,6 +409,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Bug fix: provide an empty string to `http_build_query` for HHVM workaround.
https://github.com/guzzle/guzzle/pull/1367
## 6.1.1 - 2015-11-22
* Bug fix: Proxy::wrapSync() now correctly proxies to the appropriate handler
@ -349,6 +425,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Bug fix: fixed regression where MockHandler was not using `sink`.
https://github.com/guzzle/guzzle/pull/1292
## 6.1.0 - 2015-09-08
* Feature: Added the `on_stats` request option to provide access to transfer
@ -383,6 +460,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Bug fix: Adding a Content-Length to PHP stream wrapper requests if not set.
https://github.com/guzzle/guzzle/pull/1189
## 6.0.2 - 2015-07-04
* Fixed a memory leak in the curl handlers in which references to callbacks
@ -400,6 +478,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Functions are now conditionally required using an additional level of
indirection to help with global Composer installations.
## 6.0.1 - 2015-05-27
* Fixed a bug with serializing the `query` request option where the `&`
@ -408,6 +487,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
use `form_params` or `multipart` instead.
* Various doc fixes.
## 6.0.0 - 2015-05-26
* See the UPGRADING.md document for more information.
@ -432,6 +512,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* `$maxHandles` has been removed from CurlMultiHandler.
* `MultipartPostBody` is now part of the `guzzlehttp/psr7` package.
## 5.3.0 - 2015-05-19
* Mock now supports `save_to`
@ -442,6 +523,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Marked `GuzzleHttp\Client::getDefaultUserAgent` as deprecated.
* URL scheme is now always lowercased.
## 6.0.0-beta.1
* Requires PHP >= 5.5
@ -494,6 +576,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* `GuzzleHttp\QueryParser` has been replaced with the
`GuzzleHttp\Psr7\parse_query`.
## 5.2.0 - 2015-01-27
* Added `AppliesHeadersInterface` to make applying headers to a request based
@ -504,6 +587,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
RingBridge.
* Added a guard in the Pool class to not use recursion for request retries.
## 5.1.0 - 2014-12-19
* Pool class no longer uses recursion when a request is intercepted.
@ -524,6 +608,7 @@ Please see [the upgrade document](UPGRADING.md) that describes all BC breaking c
* Exceptions thrown in the `end` event are now correctly wrapped with Guzzle
specific exceptions if necessary.
## 5.0.3 - 2014-11-03
This change updates query strings so that they are treated as un-encoded values
@ -538,6 +623,7 @@ string that should not be parsed or encoded (unless a call to getQuery() is
subsequently made, forcing the query-string to be converted into a Query
object).
## 5.0.2 - 2014-10-30
* Added a trailing `\r\n` to multipart/form-data payloads. See
@ -559,6 +645,7 @@ object).
string on a URL: Now allowing many more characters to be present in the
query string without being percent encoded. See https://tools.ietf.org/html/rfc3986#appendix-A
## 5.0.1 - 2014-10-16
Bugfix release.
@ -570,6 +657,7 @@ Bugfix release.
* Fixed an issue where transfer statistics were not being populated in the
RingBridge. https://github.com/guzzle/guzzle/issues/866
## 5.0.0 - 2014-10-12
Adding support for non-blocking responses and some minor API cleanup.
@ -651,6 +739,7 @@ interfaces.
argument. They now accept an associative array of options, including the
"size" key and "metadata" key which can be used to provide custom metadata.
## 4.2.2 - 2014-09-08
* Fixed a memory leak in the CurlAdapter when reusing cURL handles.

View File

@ -60,13 +60,13 @@ composer require guzzlehttp/guzzle
## Version Guidance
| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
|---------|----------------|---------------------|--------------|---------------------|---------------------|-------|--------------|
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 |
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 |
| 5.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 |
| 6.x | Security fixes | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 |
| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.3 |
| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
|---------|---------------------|---------------------|--------------|---------------------|---------------------|-------|--------------|
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 |
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 |
| 5.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 |
| 6.x | Security fixes only | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 |
| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.3 |
[guzzle-3-repo]: https://github.com/guzzle/guzzle3
[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x

View File

@ -27,7 +27,7 @@ Please make sure:
- Function `GuzzleHttp\Exception\RequestException::getResponseBodySummary` is removed.
Use `\GuzzleHttp\Psr7\get_message_body_summary` as an alternative.
- Function `GuzzleHttp\Cookie\CookieJar::getCookieValue` is removed.
- Request option `exception` is removed. Please use `http_errors`.
- Request option `exceptions` is removed. Please use `http_errors`.
- Request option `save_to` is removed. Please use `sink`.
- Pool option `pool_size` is removed. Please use `concurrency`.
- We now look for environment variables in the `$_SERVER` super global, due to thread safety issues with `getenv`. We continue to fallback to `getenv` in CLI environments, for maximum compatibility.

View File

@ -53,8 +53,8 @@
"require": {
"php": "^7.2.5 || ^8.0",
"ext-json": "*",
"guzzlehttp/promises": "^1.5",
"guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
"guzzlehttp/promises": "^1.5.3 || ^2.0.1",
"guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
@ -64,7 +64,8 @@
"require-dev": {
"ext-curl": "*",
"bamarni/composer-bin-plugin": "^1.8.1",
"php-http/client-integration-tests": "^3.0",
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.29 || ^9.5.23",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
@ -84,9 +85,6 @@
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": {
"dev-master": "7.5-dev"
}
},
"autoload": {

View File

@ -120,13 +120,14 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
public function send(RequestInterface $request, array $options = []): ResponseInterface
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->sendAsync($request, $options)->wait();
}
/**
* The HttpClient PSR (PSR-18) specify this method.
*
* @inheritDoc
* {@inheritDoc}
*/
public function sendRequest(RequestInterface $request): ResponseInterface
{
@ -184,6 +185,7 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
public function request(string $method, $uri = '', array $options = []): ResponseInterface
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->requestAsync($method, $uri, $options)->wait();
}
@ -200,7 +202,7 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
*
* @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
*/
public function getConfig(?string $option = null)
public function getConfig(string $option = null)
{
return $option === null
? $this->config
@ -228,11 +230,11 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
{
$defaults = [
'allow_redirects' => RedirectMiddleware::$defaultSettings,
'http_errors' => true,
'decode_content' => true,
'verify' => true,
'cookies' => false,
'idn_conversion' => false,
'http_errors' => true,
'decode_content' => true,
'verify' => true,
'cookies' => false,
'idn_conversion' => false,
];
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
@ -354,10 +356,10 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
if (isset($options['form_params'])) {
if (isset($options['multipart'])) {
throw new InvalidArgumentException('You cannot use '
. 'form_params and multipart at the same time. Use the '
. 'form_params option if you want to send application/'
. 'x-www-form-urlencoded requests, and the multipart '
. 'option to send multipart/form-data requests.');
.'form_params and multipart at the same time. Use the '
.'form_params option if you want to send application/'
.'x-www-form-urlencoded requests, and the multipart '
.'option to send multipart/form-data requests.');
}
$options['body'] = \http_build_query($options['form_params'], '', '&');
unset($options['form_params']);
@ -403,7 +405,7 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
// Ensure that we don't have the header in different case and set the new value.
$modify['set_headers'] = Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']);
$modify['set_headers']['Authorization'] = 'Basic '
. \base64_encode("$value[0]:$value[1]");
.\base64_encode("$value[0]:$value[1]");
break;
case 'digest':
// @todo: Do not rely on curl
@ -437,13 +439,17 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
}
}
if (isset($options['version'])) {
$modify['version'] = $options['version'];
}
$request = Psr7\Utils::modifyRequest($request, $modify);
if ($request->getBody() instanceof Psr7\MultipartStream) {
// Use a multipart/form-data POST if a Content-Type is not set.
// Ensure that we don't have the header in different case and set the new value.
$options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
$options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
. $request->getBody()->getBoundary();
.$request->getBody()->getBoundary();
}
// Merge in conditional headers if they are not present.
@ -469,9 +475,9 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
private function invalidBody(): InvalidArgumentException
{
return new InvalidArgumentException('Passing in the "body" request '
. 'option as an array to send a request is not supported. '
. 'Please use the "form_params" request option to send a '
. 'application/x-www-form-urlencoded request, or the "multipart" '
. 'request option to send a multipart/form-data request.');
.'option as an array to send a request is not supported. '
.'Please use the "form_params" request option to send a '
.'application/x-www-form-urlencoded request, or the "multipart" '
.'request option to send a multipart/form-data request.');
}
}

View File

@ -80,5 +80,5 @@ interface ClientInterface
*
* @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
*/
public function getConfig(?string $option = null);
public function getConfig(string $option = null);
}

View File

@ -50,10 +50,10 @@ class CookieJar implements CookieJarInterface
$cookieJar = new self();
foreach ($cookies as $name => $value) {
$cookieJar->setCookie(new SetCookie([
'Domain' => $domain,
'Name' => $name,
'Value' => $value,
'Discard' => true
'Domain' => $domain,
'Name' => $name,
'Value' => $value,
'Discard' => true,
]));
}
@ -96,9 +96,6 @@ class CookieJar implements CookieJarInterface
return null;
}
/**
* @inheritDoc
*/
public function toArray(): array
{
return \array_map(static function (SetCookie $cookie): array {
@ -106,13 +103,11 @@ class CookieJar implements CookieJarInterface
}, $this->getIterator()->getArrayCopy());
}
/**
* @inheritDoc
*/
public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
public function clear(string $domain = null, string $path = null, string $name = null): void
{
if (!$domain) {
$this->cookies = [];
return;
} elseif (!$path) {
$this->cookies = \array_filter(
@ -125,25 +120,22 @@ class CookieJar implements CookieJarInterface
$this->cookies = \array_filter(
$this->cookies,
static function (SetCookie $cookie) use ($path, $domain): bool {
return !($cookie->matchesPath($path) &&
$cookie->matchesDomain($domain));
return !($cookie->matchesPath($path)
&& $cookie->matchesDomain($domain));
}
);
} else {
$this->cookies = \array_filter(
$this->cookies,
static function (SetCookie $cookie) use ($path, $domain, $name) {
return !($cookie->getName() == $name &&
$cookie->matchesPath($path) &&
$cookie->matchesDomain($domain));
return !($cookie->getName() == $name
&& $cookie->matchesPath($path)
&& $cookie->matchesDomain($domain));
}
);
}
}
/**
* @inheritDoc
*/
public function clearSessionCookies(): void
{
$this->cookies = \array_filter(
@ -154,9 +146,6 @@ class CookieJar implements CookieJarInterface
);
}
/**
* @inheritDoc
*/
public function setCookie(SetCookie $cookie): bool
{
// If the name string is empty (but not 0), ignore the set-cookie
@ -170,9 +159,10 @@ class CookieJar implements CookieJarInterface
$result = $cookie->validate();
if ($result !== true) {
if ($this->strictMode) {
throw new \RuntimeException('Invalid cookie: ' . $result);
throw new \RuntimeException('Invalid cookie: '.$result);
}
$this->removeCookieIfEmpty($cookie);
return false;
}
@ -180,9 +170,9 @@ class CookieJar implements CookieJarInterface
foreach ($this->cookies as $i => $c) {
// Two cookies are identical, when their path, and domain are
// identical.
if ($c->getPath() != $cookie->getPath() ||
$c->getDomain() != $cookie->getDomain() ||
$c->getName() != $cookie->getName()
if ($c->getPath() != $cookie->getPath()
|| $c->getDomain() != $cookie->getDomain()
|| $c->getName() != $cookie->getName()
) {
continue;
}
@ -253,7 +243,7 @@ class CookieJar implements CookieJarInterface
/**
* Computes cookie path following RFC 6265 section 5.1.4
*
* @link https://tools.ietf.org/html/rfc6265#section-5.1.4
* @see https://tools.ietf.org/html/rfc6265#section-5.1.4
*/
private function getCookiePathFromRequest(RequestInterface $request): string
{
@ -284,13 +274,13 @@ class CookieJar implements CookieJarInterface
$path = $uri->getPath() ?: '/';
foreach ($this->cookies as $cookie) {
if ($cookie->matchesPath($path) &&
$cookie->matchesDomain($host) &&
!$cookie->isExpired() &&
(!$cookie->getSecure() || $scheme === 'https')
if ($cookie->matchesPath($path)
&& $cookie->matchesDomain($host)
&& !$cookie->isExpired()
&& (!$cookie->getSecure() || $scheme === 'https')
) {
$values[] = $cookie->getName() . '='
. $cookie->getValue();
$values[] = $cookie->getName().'='
.$cookie->getValue();
}
}

View File

@ -13,7 +13,8 @@ use Psr\Http\Message\ResponseInterface;
* necessary. Subclasses are also responsible for storing and retrieving
* cookies from a file, database, etc.
*
* @link https://docs.python.org/2/library/cookielib.html Inspiration
* @see https://docs.python.org/2/library/cookielib.html Inspiration
*
* @extends \IteratorAggregate<SetCookie>
*/
interface CookieJarInterface extends \Countable, \IteratorAggregate
@ -61,7 +62,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
* @param string|null $path Clears cookies matching a domain and path
* @param string|null $name Clears cookies matching a domain, path, and name
*/
public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void;
public function clear(string $domain = null, string $path = null, string $name = null): void;
/**
* Discard all sessions cookies.

View File

@ -71,7 +71,7 @@ class SessionCookieJar extends CookieJar
$this->setCookie(new SetCookie($cookie));
}
} elseif (\strlen($data)) {
throw new \RuntimeException("Invalid cookie data");
throw new \RuntimeException('Invalid cookie data');
}
}
}

View File

@ -11,15 +11,15 @@ class SetCookie
* @var array
*/
private static $defaults = [
'Name' => null,
'Value' => null,
'Domain' => null,
'Path' => '/',
'Max-Age' => null,
'Expires' => null,
'Secure' => false,
'Discard' => false,
'HttpOnly' => false
'Name' => null,
'Value' => null,
'Domain' => null,
'Path' => '/',
'Max-Age' => null,
'Expires' => null,
'Secure' => false,
'Discard' => false,
'HttpOnly' => false,
];
/**
@ -58,7 +58,13 @@ class SetCookie
} else {
foreach (\array_keys(self::$defaults) as $search) {
if (!\strcasecmp($search, $key)) {
$data[$search] = $value;
if ($search === 'Max-Age') {
if (is_numeric($value)) {
$data[$search] = (int) $value;
}
} else {
$data[$search] = $value;
}
continue 2;
}
}
@ -74,13 +80,49 @@ class SetCookie
*/
public function __construct(array $data = [])
{
/** @var array|null $replaced will be null in case of replace error */
$replaced = \array_replace(self::$defaults, $data);
if ($replaced === null) {
throw new \InvalidArgumentException('Unable to replace the default values for the Cookie.');
$this->data = self::$defaults;
if (isset($data['Name'])) {
$this->setName($data['Name']);
}
if (isset($data['Value'])) {
$this->setValue($data['Value']);
}
if (isset($data['Domain'])) {
$this->setDomain($data['Domain']);
}
if (isset($data['Path'])) {
$this->setPath($data['Path']);
}
if (isset($data['Max-Age'])) {
$this->setMaxAge($data['Max-Age']);
}
if (isset($data['Expires'])) {
$this->setExpires($data['Expires']);
}
if (isset($data['Secure'])) {
$this->setSecure($data['Secure']);
}
if (isset($data['Discard'])) {
$this->setDiscard($data['Discard']);
}
if (isset($data['HttpOnly'])) {
$this->setHttpOnly($data['HttpOnly']);
}
// Set the remaining values that don't have extra validation logic
foreach (array_diff(array_keys($data), array_keys(self::$defaults)) as $key) {
$this->data[$key] = $data[$key];
}
$this->data = $replaced;
// Extract the Expires value and turn it into a UNIX timestamp if needed
if (!$this->getExpires() && $this->getMaxAge()) {
// Calculate the Expires date
@ -92,13 +134,13 @@ class SetCookie
public function __toString()
{
$str = $this->data['Name'] . '=' . ($this->data['Value'] ?? '') . '; ';
$str = $this->data['Name'].'='.($this->data['Value'] ?? '').'; ';
foreach ($this->data as $k => $v) {
if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
if ($k === 'Expires') {
$str .= 'Expires=' . \gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
$str .= 'Expires='.\gmdate('D, d M Y H:i:s \G\M\T', $v).'; ';
} else {
$str .= ($v === true ? $k : "{$k}={$v}") . '; ';
$str .= ($v === true ? $k : "{$k}={$v}").'; ';
}
}
}
@ -394,7 +436,7 @@ class SetCookie
return false;
}
return (bool) \preg_match('/\.' . \preg_quote($cookieDomain, '/') . '$/', $domain);
return (bool) \preg_match('/\.'.\preg_quote($cookieDomain, '/').'$/', $domain);
}
/**
@ -423,8 +465,8 @@ class SetCookie
$name
)) {
return 'Cookie name must not contain invalid characters: ASCII '
. 'Control characters (0-31;127), space, tab and the '
. 'following characters: ()<>@,;:\"/?={}';
.'Control characters (0-31;127), space, tab and the '
.'following characters: ()<>@,;:\"/?={}';
}
// Value must not be null. 0 and empty string are valid. Empty strings

View File

@ -51,7 +51,7 @@ class CurlFactory implements CurlFactoryInterface
unset($options['curl']['body_as_string']);
}
$easy = new EasyHandle;
$easy = new EasyHandle();
$easy->request = $request;
$easy->options = $options;
$conf = $this->getDefaultConf($easy);
@ -161,11 +161,11 @@ class CurlFactory implements CurlFactoryInterface
private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface
{
static $connectionErrors = [
\CURLE_OPERATION_TIMEOUTED => true,
\CURLE_OPERATION_TIMEOUTED => true,
\CURLE_COULDNT_RESOLVE_HOST => true,
\CURLE_COULDNT_CONNECT => true,
\CURLE_SSL_CONNECT_ERROR => true,
\CURLE_GOT_NOTHING => true,
\CURLE_COULDNT_CONNECT => true,
\CURLE_SSL_CONNECT_ERROR => true,
\CURLE_GOT_NOTHING => true,
];
if ($easy->createResponseException) {
@ -219,12 +219,12 @@ class CurlFactory implements CurlFactoryInterface
private function getDefaultConf(EasyHandle $easy): array
{
$conf = [
'_headers' => $easy->request->getHeaders(),
\CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
\CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
'_headers' => $easy->request->getHeaders(),
\CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
\CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
\CURLOPT_RETURNTRANSFER => false,
\CURLOPT_HEADER => false,
\CURLOPT_CONNECTTIMEOUT => 150,
\CURLOPT_HEADER => false,
\CURLOPT_CONNECTTIMEOUT => 300,
];
if (\defined('CURLOPT_PROTOCOLS')) {
@ -250,6 +250,7 @@ class CurlFactory implements CurlFactoryInterface
if ($size === null || $size > 0) {
$this->applyBody($easy->request, $easy->options, $conf);
return;
}
@ -341,6 +342,7 @@ class CurlFactory implements CurlFactoryInterface
foreach (\array_keys($options['_headers']) as $key) {
if (!\strcasecmp($key, $name)) {
unset($options['_headers'][$key]);
return;
}
}
@ -365,11 +367,11 @@ class CurlFactory implements CurlFactoryInterface
// If it's a directory or a link to a directory use CURLOPT_CAPATH.
// If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
if (
\is_dir($options['verify']) ||
(
\is_link($options['verify']) === true &&
($verifyLink = \readlink($options['verify'])) !== false &&
\is_dir($verifyLink)
\is_dir($options['verify'])
|| (
\is_link($options['verify']) === true
&& ($verifyLink = \readlink($options['verify'])) !== false
&& \is_dir($verifyLink)
)
) {
$conf[\CURLOPT_CAPATH] = $options['verify'];
@ -452,6 +454,32 @@ class CurlFactory implements CurlFactoryInterface
}
}
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');
}
$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')) {
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')) {
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');
}
}
if (isset($options['cert'])) {
$cert = $options['cert'];
if (\is_array($cert)) {
@ -461,8 +489,8 @@ class CurlFactory implements CurlFactoryInterface
if (!\file_exists($cert)) {
throw new \InvalidArgumentException("SSL certificate not found: {$cert}");
}
# OpenSSL (versions 0.9.3 and later) also support "P12" for PKCS#12-encoded files.
# see https://curl.se/libcurl/c/CURLOPT_SSLCERTTYPE.html
// OpenSSL (versions 0.9.3 and later) also support "P12" for PKCS#12-encoded files.
// see https://curl.se/libcurl/c/CURLOPT_SSLCERTTYPE.html
$ext = pathinfo($cert, \PATHINFO_EXTENSION);
if (preg_match('#^(der|p12)$#i', $ext)) {
$conf[\CURLOPT_SSLCERTTYPE] = strtoupper($ext);
@ -525,9 +553,10 @@ class CurlFactory implements CurlFactoryInterface
}
} catch (\RuntimeException $e) {
$ctx['error'] = 'The connection unexpectedly failed without '
. 'providing an error. The request would have been retried, '
. 'but attempting to rewind the request body failed. '
. 'Exception: ' . $e;
.'providing an error. The request would have been retried, '
.'but attempting to rewind the request body failed. '
.'Exception: '.$e;
return self::createRejection($easy, $ctx);
}
@ -536,14 +565,15 @@ class CurlFactory implements CurlFactoryInterface
$easy->options['_curl_retries'] = 1;
} elseif ($easy->options['_curl_retries'] == 2) {
$ctx['error'] = 'The cURL request was retried 3 times '
. 'and did not succeed. The most likely reason for the failure '
. 'is that cURL was unable to rewind the body of the request '
. 'and subsequent retries resulted in the same error. Turn on '
. 'the debug option to see what went wrong. See '
. 'https://bugs.php.net/bug.php?id=47204 for more information.';
.'and did not succeed. The most likely reason for the failure '
.'is that cURL was unable to rewind the body of the request '
.'and subsequent retries resulted in the same error. Turn on '
.'the debug option to see what went wrong. See '
.'https://bugs.php.net/bug.php?id=47204 for more information.';
return self::createRejection($easy, $ctx);
} else {
$easy->options['_curl_retries']++;
++$easy->options['_curl_retries'];
}
return $handler($easy->request, $easy->options);
@ -573,6 +603,7 @@ class CurlFactory implements CurlFactoryInterface
$easy->createResponse();
} catch (\Exception $e) {
$easy->createResponseException = $e;
return -1;
}
if ($onHeaders !== null) {
@ -582,6 +613,7 @@ class CurlFactory implements CurlFactoryInterface
// Associate the exception with the handle and trigger
// a curl header write error by returning 0.
$easy->onHeadersException = $e;
return -1;
}
}
@ -591,7 +623,16 @@ class CurlFactory implements CurlFactoryInterface
} else {
$easy->headers[] = $value;
}
return \strlen($h);
};
}
public function __destruct()
{
foreach ($this->handles as $id => $handle) {
\curl_close($handle);
unset($this->handles[$id]);
}
}
}

View File

@ -15,11 +15,8 @@ use Psr\Http\Message\RequestInterface;
* associative array of curl option constants mapping to values in the
* **curl** key of the provided request options.
*
* @property resource|\CurlMultiHandle $_mh Internal use only. Lazy loaded multi-handle.
*
* @final
*/
#[\AllowDynamicProperties]
class CurlMultiHandler
{
/**
@ -56,6 +53,9 @@ class CurlMultiHandler
*/
private $options = [];
/** @var resource|\CurlMultiHandle */
private $_mh;
/**
* This handler accepts the following options:
*
@ -79,6 +79,10 @@ class CurlMultiHandler
}
$this->options = $options['options'] ?? [];
// unsetting the property forces the first access to go through
// __get().
unset($this->_mh);
}
/**
@ -164,7 +168,8 @@ class CurlMultiHandler
\usleep(250);
}
while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM);
while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
}
$this->processMessages();
}

View File

@ -106,7 +106,7 @@ final class EasyHandle
*/
public function __get($name)
{
$msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: ' . $name;
$msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: '.$name;
throw new \BadMethodCallException($msg);
}
}

View File

@ -14,9 +14,9 @@ final class HeaderProcessor
*
* @param string[] $headers
*
* @throws \RuntimeException
*
* @return array{0:string, 1:int, 2:?string, 3:array}
*
* @throws \RuntimeException
*/
public static function parseHeaders(array $headers): array
{

View File

@ -138,6 +138,7 @@ class MockHandler implements \Countable
if ($this->onRejected) {
($this->onRejected)($reason);
}
return P\Create::rejectionFor($reason);
}
);
@ -159,7 +160,7 @@ class MockHandler implements \Countable
) {
$this->queue[] = $value;
} else {
throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found ' . Utils::describeType($value));
throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found '.Utils::describeType($value));
}
}
}

View File

@ -67,7 +67,7 @@ class StreamHandler
if (false !== \strpos($message, 'getaddrinfo') // DNS lookup failed
|| false !== \strpos($message, 'Connection refused')
|| false !== \strpos($message, "couldn't connect to host") // error on HHVM
|| false !== \strpos($message, "connection attempt failed")
|| false !== \strpos($message, 'connection attempt failed')
) {
$e = new ConnectException($e->getMessage(), $request, $e);
} else {
@ -231,9 +231,10 @@ class StreamHandler
\set_error_handler(static function ($_, $msg, $file, $line) use (&$errors): bool {
$errors[] = [
'message' => $msg,
'file' => $file,
'line' => $line
'file' => $file,
'line' => $line,
];
return true;
});
@ -247,7 +248,7 @@ class StreamHandler
$message = 'Error creating resource: ';
foreach ($errors as $err) {
foreach ($err as $key => $value) {
$message .= "[$key] $value" . \PHP_EOL;
$message .= "[$key] $value".\PHP_EOL;
}
}
throw new \RuntimeException(\trim($message));
@ -350,6 +351,7 @@ class StreamHandler
if (false === $records || !isset($records[0]['ip'])) {
throw new ConnectException(\sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
}
return $uri->withHost($records[0]['ip']);
}
if ('v6' === $options['force_ip_resolve']) {
@ -357,7 +359,8 @@ class StreamHandler
if (false === $records || !isset($records[0]['ipv6'])) {
throw new ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
}
return $uri->withHost('[' . $records[0]['ipv6'] . ']');
return $uri->withHost('['.$records[0]['ipv6'].']');
}
}
@ -375,11 +378,11 @@ class StreamHandler
$context = [
'http' => [
'method' => $request->getMethod(),
'header' => $headers,
'method' => $request->getMethod(),
'header' => $headers,
'protocol_version' => $request->getProtocolVersion(),
'ignore_errors' => true,
'follow_location' => 0,
'ignore_errors' => true,
'follow_location' => 0,
],
'ssl' => [
'peer_name' => $request->getUri()->getHost(),
@ -388,7 +391,7 @@ class StreamHandler
$body = (string) $request->getBody();
if (!empty($body)) {
if ('' !== $body) {
$context['http']['content'] = $body;
// Prevent the HTTP handler from adding a Content-Type header.
if (!$request->hasHeader('Content-Type')) {
@ -472,6 +475,25 @@ class StreamHandler
}
}
/**
* @param mixed $value as passed via Request transfer options.
*/
private function add_crypto_method(RequestInterface $request, array &$options, $value, array &$params): void
{
if (
$value === \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
|| $value === \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
|| $value === \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
|| (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && $value === \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT)
) {
$options['http']['crypto_method'] = $value;
return;
}
throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
}
/**
* @param mixed $value as passed via Request transfer options.
*/
@ -542,27 +564,27 @@ class StreamHandler
}
static $map = [
\STREAM_NOTIFY_CONNECT => 'CONNECT',
\STREAM_NOTIFY_CONNECT => 'CONNECT',
\STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
\STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
\STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
\STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
\STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
\STREAM_NOTIFY_PROGRESS => 'PROGRESS',
\STREAM_NOTIFY_FAILURE => 'FAILURE',
\STREAM_NOTIFY_COMPLETED => 'COMPLETED',
\STREAM_NOTIFY_RESOLVE => 'RESOLVE',
\STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
\STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
\STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
\STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
\STREAM_NOTIFY_PROGRESS => 'PROGRESS',
\STREAM_NOTIFY_FAILURE => 'FAILURE',
\STREAM_NOTIFY_COMPLETED => 'COMPLETED',
\STREAM_NOTIFY_RESOLVE => 'RESOLVE',
];
static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max'];
$value = Utils::debugResource($value);
$ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
$ident = $request->getMethod().' '.$request->getUri()->withFragment('');
self::addNotification(
$params,
static function (int $code, ...$passed) use ($ident, $value, $map, $args): void {
\fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
foreach (\array_filter($passed) as $i => $v) {
\fwrite($value, $args[$i] . ': "' . $v . '" ');
\fwrite($value, $args[$i].': "'.$v.'" ');
}
\fwrite($value, "\n");
}
@ -577,7 +599,7 @@ class StreamHandler
} else {
$params['notification'] = self::callArray([
$params['notification'],
$notify
$notify,
]);
}
}

View File

@ -44,7 +44,7 @@ class HandlerStack
* handler is provided, the best handler for your
* system will be utilized.
*/
public static function create(?callable $handler = null): self
public static function create(callable $handler = null): self
{
$stack = new self($handler ?: Utils::chooseHandler());
$stack->push(Middleware::httpErrors(), 'http_errors');
@ -86,14 +86,14 @@ class HandlerStack
$stack = [];
if ($this->handler !== null) {
$stack[] = "0) Handler: " . $this->debugCallable($this->handler);
$stack[] = '0) Handler: '.$this->debugCallable($this->handler);
}
$result = '';
foreach (\array_reverse($this->stack) as $tuple) {
$depth++;
++$depth;
$str = "{$depth}) Name: '{$tuple[1]}', ";
$str .= "Function: " . $this->debugCallable($tuple[0]);
$str .= 'Function: '.$this->debugCallable($tuple[0]);
$result = "> {$str}\n{$result}";
$stack[] = $str;
}
@ -122,7 +122,7 @@ class HandlerStack
*/
public function hasHandler(): bool
{
return $this->handler !== null ;
return $this->handler !== null;
}
/**
@ -131,7 +131,7 @@ class HandlerStack
* @param callable(callable): callable $middleware Middleware function
* @param string $name Name to register for this middleware.
*/
public function unshift(callable $middleware, ?string $name = null): void
public function unshift(callable $middleware, string $name = null): void
{
\array_unshift($this->stack, [$middleware, $name]);
$this->cached = null;
@ -266,10 +266,10 @@ class HandlerStack
if (\is_array($fn)) {
return \is_string($fn[0])
? "callable({$fn[0]}::{$fn[1]})"
: "callable(['" . \get_class($fn[0]) . "', '{$fn[1]}'])";
: "callable(['".\get_class($fn[0])."', '{$fn[1]}'])";
}
/** @var object $fn */
return 'callable(' . \spl_object_hash($fn) . ')';
return 'callable('.\spl_object_hash($fn).')';
}
}

View File

@ -40,11 +40,11 @@ class MessageFormatter implements MessageFormatterInterface
/**
* Apache Common Log Format.
*
* @link https://httpd.apache.org/docs/2.4/logs.html#common
* @see https://httpd.apache.org/docs/2.4/logs.html#common
*
* @var string
*/
public const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
public const CLF = '{hostname} {req_header_User-Agent} - [{date_common_log}] "{method} {target} HTTP/{version}" {code} {res_header_Content-Length}';
public const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
public const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
@ -68,7 +68,7 @@ class MessageFormatter implements MessageFormatterInterface
* @param ResponseInterface|null $response Response that was received
* @param \Throwable|null $error Exception that was received
*/
public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string
public function format(RequestInterface $request, ResponseInterface $response = null, \Throwable $error = null): string
{
$cache = [];
@ -90,9 +90,9 @@ class MessageFormatter implements MessageFormatterInterface
break;
case 'req_headers':
$result = \trim($request->getMethod()
. ' ' . $request->getRequestTarget())
. ' HTTP/' . $request->getProtocolVersion() . "\r\n"
. $this->headers($request);
.' '.$request->getRequestTarget())
.' HTTP/'.$request->getProtocolVersion()."\r\n"
.$this->headers($request);
break;
case 'res_headers':
$result = $response ?
@ -101,7 +101,7 @@ class MessageFormatter implements MessageFormatterInterface
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase()
) . "\r\n" . $this->headers($response)
)."\r\n".$this->headers($response)
: 'NULL';
break;
case 'req_body':
@ -177,6 +177,7 @@ class MessageFormatter implements MessageFormatterInterface
}
$cache[$matches[1]] = $result;
return $result;
},
$this->template
@ -190,7 +191,7 @@ class MessageFormatter implements MessageFormatterInterface
{
$result = '';
foreach ($message->getHeaders() as $name => $values) {
$result .= $name . ': ' . \implode(', ', $values) . "\r\n";
$result .= $name.': '.\implode(', ', $values)."\r\n";
}
return \trim($result);

View File

@ -14,5 +14,5 @@ interface MessageFormatterInterface
* @param ResponseInterface|null $response Response that was received
* @param \Throwable|null $error Exception that was received
*/
public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string;
public function format(RequestInterface $request, ResponseInterface $response = null, \Throwable $error = null): string;
}

View File

@ -34,10 +34,12 @@ final class Middleware
}
$cookieJar = $options['cookies'];
$request = $cookieJar->withCookieHeader($request);
return $handler($request, $options)
->then(
static function (ResponseInterface $response) use ($cookieJar, $request): ResponseInterface {
$cookieJar->extractCookies($request, $response);
return $response;
}
);
@ -60,6 +62,7 @@ final class Middleware
if (empty($options['http_errors'])) {
return $handler($request, $options);
}
return $handler($request, $options)->then(
static function (ResponseInterface $response) use ($request, $bodySummarizer) {
$code = $response->getStatusCode();
@ -93,20 +96,22 @@ final class Middleware
return $handler($request, $options)->then(
static function ($value) use ($request, &$container, $options) {
$container[] = [
'request' => $request,
'request' => $request,
'response' => $value,
'error' => null,
'options' => $options
'error' => null,
'options' => $options,
];
return $value;
},
static function ($reason) use ($request, &$container, $options) {
$container[] = [
'request' => $request,
'request' => $request,
'response' => null,
'error' => $reason,
'options' => $options
'error' => $reason,
'options' => $options,
];
return P\Create::rejectionFor($reason);
}
);
@ -138,6 +143,7 @@ final class Middleware
if ($after) {
$after($request, $options, $response);
}
return $response;
};
};
@ -202,12 +208,14 @@ final class Middleware
static function ($response) use ($logger, $request, $formatter, $logLevel): ResponseInterface {
$message = $formatter->format($request, $response);
$logger->log($logLevel, $message);
return $response;
},
static function ($reason) use ($logger, $request, $formatter): PromiseInterface {
$response = $reason instanceof RequestException ? $reason->getResponse() : null;
$message = $formatter->format($request, $response, P\Create::exceptionFor($reason));
$logger->error($message);
return P\Create::rejectionFor($reason);
}
);

View File

@ -84,6 +84,7 @@ class PrepareBodyMiddleware
// The expect header is unconditionally enabled
if ($expect === true) {
$modify['set_headers']['Expect'] = '100-Continue';
return;
}

View File

@ -27,10 +27,10 @@ class RedirectMiddleware
* @var array
*/
public static $defaultSettings = [
'max' => 5,
'protocols' => ['http', 'https'],
'strict' => false,
'referer' => false,
'max' => 5,
'protocols' => ['http', 'https'],
'strict' => false,
'referer' => false,
'track_redirects' => false,
];
@ -166,8 +166,8 @@ class RedirectMiddleware
// not forcing RFC compliance, but rather emulating what all browsers
// would do.
$statusCode = $response->getStatusCode();
if ($statusCode == 303 ||
($statusCode <= 302 && !$options['allow_redirects']['strict'])
if ($statusCode == 303
|| ($statusCode <= 302 && !$options['allow_redirects']['strict'])
) {
$safeMethods = ['GET', 'HEAD', 'OPTIONS'];
$requestMethod = $request->getMethod();

View File

@ -7,7 +7,7 @@ namespace GuzzleHttp;
*
* More documentation for each option can be found at http://guzzlephp.org/.
*
* @link http://docs.guzzlephp.org/en/v6/request-options.html
* @see http://docs.guzzlephp.org/en/v6/request-options.html
*/
final class RequestOptions
{
@ -70,10 +70,22 @@ final class RequestOptions
/**
* connect_timeout: (float, default=0) Float describing the number of
* seconds to wait while trying to connect to a server. Use 0 to wait
* indefinitely (the default behavior).
* 300 seconds (the default behavior).
*/
public const CONNECT_TIMEOUT = 'connect_timeout';
/**
* crypto_method: (int) A value describing the minimum TLS protocol
* version to use.
*
* This setting must be set to one of the
* ``STREAM_CRYPTO_METHOD_TLS*_CLIENT`` constants. PHP 7.4 or higher is
* required in order to use TLS 1.3, and cURL 7.34.0 or higher is required
* in order to specify a crypto method, with cURL 7.52.0 or higher being
* required to use TLS 1.3.
*/
public const CRYPTO_METHOD = 'crypto_method';
/**
* debug: (bool|resource) Set to true or set to a PHP stream returned by
* fopen() enable debug output with the HTTP handler used to send a

View File

@ -44,7 +44,7 @@ class RetryMiddleware
{
$this->decider = $decider;
$this->nextHandler = $nextHandler;
$this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
$this->delay = $delay ?: __CLASS__.'::exponentialDelay';
}
/**
@ -54,7 +54,7 @@ class RetryMiddleware
*/
public static function exponentialDelay(int $retries): int
{
return (int) \pow(2, $retries - 1) * 1000;
return (int) 2 ** ($retries - 1) * 1000;
}
public function __invoke(RequestInterface $request, array $options): PromiseInterface
@ -64,6 +64,7 @@ class RetryMiddleware
}
$fn = $this->nextHandler;
return $fn($request, $options)
->then(
$this->onFulfilled($request, $options),
@ -85,6 +86,7 @@ class RetryMiddleware
)) {
return $value;
}
return $this->doRetry($request, $options, $value);
};
}
@ -103,6 +105,7 @@ class RetryMiddleware
)) {
return P\Create::rejectionFor($reason);
}
return $this->doRetry($req, $options);
};
}

View File

@ -46,8 +46,8 @@ final class TransferStats
*/
public function __construct(
RequestInterface $request,
?ResponseInterface $response = null,
?float $transferTime = null,
ResponseInterface $response = null,
float $transferTime = null,
$handlerErrorData = null,
array $handlerStats = []
) {

View File

@ -23,9 +23,9 @@ final class Utils
{
switch (\gettype($input)) {
case 'object':
return 'object(' . \get_class($input) . ')';
return 'object('.\get_class($input).')';
case 'array':
return 'array(' . \count($input) . ')';
return 'array('.\count($input).')';
default:
\ob_start();
\var_dump($input);
@ -79,9 +79,9 @@ final class Utils
*
* The returned handler is not wrapped by any default middlewares.
*
* @throws \RuntimeException if no viable Handler is available.
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.
*
* @throws \RuntimeException if no viable Handler is available.
*/
public static function chooseHandler(): callable
{
@ -247,8 +247,8 @@ EOT
}
// Special match if the area when prefixed with ".". Remove any
// existing leading "." and add a new leading ".".
$area = '.' . \ltrim($area, '.');
if (\substr($host, -(\strlen($area))) === $area) {
$area = '.'.\ltrim($area, '.');
if (\substr($host, -\strlen($area)) === $area) {
return true;
}
}
@ -269,13 +269,13 @@ EOT
*
* @throws InvalidArgumentException if the JSON cannot be decoded.
*
* @link https://www.php.net/manual/en/function.json-decode.php
* @see https://www.php.net/manual/en/function.json-decode.php
*/
public static function jsonDecode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
{
$data = \json_decode($json, $assoc, $depth, $options);
if (\JSON_ERROR_NONE !== \json_last_error()) {
throw new InvalidArgumentException('json_decode error: ' . \json_last_error_msg());
throw new InvalidArgumentException('json_decode error: '.\json_last_error_msg());
}
return $data;
@ -290,13 +290,13 @@ EOT
*
* @throws InvalidArgumentException if the JSON cannot be encoded.
*
* @link https://www.php.net/manual/en/function.json-encode.php
* @see https://www.php.net/manual/en/function.json-encode.php
*/
public static function jsonEncode($value, int $options = 0, int $depth = 512): string
{
$json = \json_encode($value, $options, $depth);
if (\JSON_ERROR_NONE !== \json_last_error()) {
throw new InvalidArgumentException('json_encode error: ' . \json_last_error_msg());
throw new InvalidArgumentException('json_encode error: '.\json_last_error_msg());
}
/** @var string */
@ -341,7 +341,7 @@ EOT
$errorMessage = 'IDN conversion failed';
if ($errors) {
$errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
$errorMessage .= ' (errors: '.implode(', ', $errors).')';
}
throw new InvalidArgumentException($errorMessage);

View File

@ -50,10 +50,10 @@ function debug_resource($value = null)
*
* The returned handler is not wrapped by any default middlewares.
*
* @throws \RuntimeException if no viable Handler is available.
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.
*
* @throws \RuntimeException if no viable Handler is available.
*
* @deprecated choose_handler will be removed in guzzlehttp/guzzle:8.0. Use Utils::chooseHandler instead.
*/
function choose_handler(): callable
@ -141,7 +141,7 @@ function is_host_in_noproxy(string $host, array $noProxyArray): bool
*
* @throws Exception\InvalidArgumentException if the JSON cannot be decoded.
*
* @link https://www.php.net/manual/en/function.json-decode.php
* @see https://www.php.net/manual/en/function.json-decode.php
* @deprecated json_decode will be removed in guzzlehttp/guzzle:8.0. Use Utils::jsonDecode instead.
*/
function json_decode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
@ -158,7 +158,7 @@ function json_decode(string $json, bool $assoc = false, int $depth = 512, int $o
*
* @throws Exception\InvalidArgumentException if the JSON cannot be encoded.
*
* @link https://www.php.net/manual/en/function.json-encode.php
* @see https://www.php.net/manual/en/function.json-encode.php
* @deprecated json_encode will be removed in guzzlehttp/guzzle:8.0. Use Utils::jsonEncode instead.
*/
function json_encode($value, int $options = 0, int $depth = 512): string

View File

@ -2,5 +2,5 @@
// Don't redefine the functions if included multiple times.
if (!\function_exists('GuzzleHttp\describe_type')) {
require __DIR__ . '/functions.php';
require __DIR__.'/functions.php';
}

View File

@ -1,11 +1,43 @@
# CHANGELOG
## 2.0.1 - 2023-08-03
### Changed
- PHP 8.3 support
## 2.0.0 - 2023-05-21
### Added
- Added PHP 7 type hints
### Changed
- All previously non-final non-exception classes have been marked as soft-final
### Removed
- Dropped PHP < 7.2 support
- All functions in the `GuzzleHttp\Promise` namespace
## 1.5.3 - 2023-05-21
### Changed
- Removed remaining usage of deprecated functions
## 1.5.2 - 2022-08-07
### Changed
- Officially support PHP 8.2
## 1.5.1 - 2021-10-22
### Fixed
@ -13,6 +45,7 @@
- Revert "Call handler when waiting on fulfilled/rejected Promise"
- Fix pool memory leak when empty array of promises provided
## 1.5.0 - 2021-10-07
### Changed
@ -24,12 +57,14 @@
- Fix manually settle promises generated with `Utils::task`
## 1.4.1 - 2021-02-18
### Fixed
- Fixed `each_limit` skipping promises and failing
## 1.4.0 - 2020-09-30
### Added

View File

@ -29,6 +29,21 @@ for a general introduction to promises.
`GuzzleHttp\Promise\Coroutine::of()`.
## Installation
```shell
composer require guzzlehttp/promises
```
## Version Guidance
| Version | Status | PHP Version |
|---------|------------------------|--------------|
| 1.x | Bug and security fixes | >=5.5,<8.3 |
| 2.x | Latest | >=7.2.5,<8.4 |
## Quick Start
A *promise* represents the eventual result of an asynchronous operation. The
@ -430,8 +445,6 @@ $loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(0, [$queue, 'run']);
```
*TODO*: Perhaps adding a `futureTick()` on each tick would be faster?
## Implementation Notes
@ -501,8 +514,8 @@ $promise->resolve('foo');
A static API was first introduced in 1.4.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:
function API was removed in 2.0.0. A migration table has been provided here for
your convenience:
| Original Function | Replacement Method |
|----------------|----------------|

View File

@ -26,32 +26,32 @@
}
],
"require": {
"php": ">=5.5"
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^4.4 || ^5.1"
"bamarni/composer-bin-plugin": "^1.8.1",
"phpunit/phpunit": "^8.5.29 || ^9.5.23"
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": ["src/functions_include.php"]
}
},
"autoload-dev": {
"psr-4": {
"GuzzleHttp\\Promise\\Tests\\": "tests/"
}
},
"scripts": {
"test": "vendor/bin/simple-phpunit",
"test-ci": "vendor/bin/simple-phpunit --coverage-text"
},
"extra": {
"branch-alias": {
"dev-master": "1.5-dev"
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"config": {
"allow-plugins": {
"bamarni/composer-bin-plugin": true
},
"preferred-install": "dist",
"sort-packages": true
}

View File

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace GuzzleHttp\Promise;
/**
@ -7,7 +9,7 @@ namespace GuzzleHttp\Promise;
*/
class AggregateException extends RejectionException
{
public function __construct($msg, array $reasons)
public function __construct(string $msg, array $reasons)
{
parent::__construct(
$reasons,

View File

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace GuzzleHttp\Promise;
/**

View File

@ -1,8 +1,9 @@
<?php
declare(strict_types=1);
namespace GuzzleHttp\Promise;
use Exception;
use Generator;
use Throwable;
@ -27,7 +28,7 @@ use Throwable;
* $value = (yield createPromise('a'));
* try {
* $value = (yield createPromise($value . 'b'));
* } catch (\Exception $e) {
* } catch (\Throwable $e) {
* // The promise was rejected.
* }
* yield $value . 'c';
@ -40,7 +41,7 @@ use Throwable;
*
* @return Promise
*
* @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
* @see https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
*/
final class Coroutine implements PromiseInterface
{
@ -62,15 +63,13 @@ final class Coroutine implements PromiseInterface
public function __construct(callable $generatorFn)
{
$this->generator = $generatorFn();
$this->result = new Promise(function () {
$this->result = new Promise(function (): void {
while (isset($this->currentPromise)) {
$this->currentPromise->wait();
}
});
try {
$this->nextCoroutine($this->generator->current());
} catch (\Exception $exception) {
$this->result->reject($exception);
} catch (Throwable $throwable) {
$this->result->reject($throwable);
}
@ -78,10 +77,8 @@ final class Coroutine implements PromiseInterface
/**
* Create a new coroutine.
*
* @return self
*/
public static function of(callable $generatorFn)
public static function of(callable $generatorFn): self
{
return new self($generatorFn);
}
@ -89,42 +86,42 @@ final class Coroutine implements PromiseInterface
public function then(
callable $onFulfilled = null,
callable $onRejected = null
) {
): PromiseInterface {
return $this->result->then($onFulfilled, $onRejected);
}
public function otherwise(callable $onRejected)
public function otherwise(callable $onRejected): PromiseInterface
{
return $this->result->otherwise($onRejected);
}
public function wait($unwrap = true)
public function wait(bool $unwrap = true)
{
return $this->result->wait($unwrap);
}
public function getState()
public function getState(): string
{
return $this->result->getState();
}
public function resolve($value)
public function resolve($value): void
{
$this->result->resolve($value);
}
public function reject($reason)
public function reject($reason): void
{
$this->result->reject($reason);
}
public function cancel()
public function cancel(): void
{
$this->currentPromise->cancel();
$this->result->cancel();
}
private function nextCoroutine($yielded)
private function nextCoroutine($yielded): void
{
$this->currentPromise = Create::promiseFor($yielded)
->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
@ -133,7 +130,7 @@ final class Coroutine implements PromiseInterface
/**
* @internal
*/
public function _handleSuccess($value)
public function _handleSuccess($value): void
{
unset($this->currentPromise);
try {
@ -143,8 +140,6 @@ final class Coroutine implements PromiseInterface
} else {
$this->result->resolve($value);
}
} catch (Exception $exception) {
$this->result->reject($exception);
} catch (Throwable $throwable) {
$this->result->reject($throwable);
}
@ -153,15 +148,13 @@ final class Coroutine implements PromiseInterface
/**
* @internal
*/
public function _handleFailure($reason)
public function _handleFailure($reason): void
{
unset($this->currentPromise);
try {
$nextYield = $this->generator->throw(Create::exceptionFor($reason));
// The throw was caught, so keep iterating on the coroutine
$this->nextCoroutine($nextYield);
} catch (Exception $exception) {
$this->result->reject($exception);
} catch (Throwable $throwable) {
$this->result->reject($throwable);
}

View File

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace GuzzleHttp\Promise;
final class Create
@ -8,10 +10,8 @@ final class Create
* Creates a promise for a value if the value is not a promise.
*
* @param mixed $value Promise or value.
*
* @return PromiseInterface
*/
public static function promiseFor($value)
public static function promiseFor($value): PromiseInterface
{
if ($value instanceof PromiseInterface) {
return $value;
@ -23,6 +23,7 @@ final class Create
$cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
$promise = new Promise($wfn, $cfn);
$value->then([$promise, 'resolve'], [$promise, 'reject']);
return $promise;
}
@ -34,10 +35,8 @@ final class Create
* If the provided reason is a promise, then it is returned as-is.
*
* @param mixed $reason Promise or reason.
*
* @return PromiseInterface
*/
public static function rejectionFor($reason)
public static function rejectionFor($reason): PromiseInterface
{
if ($reason instanceof PromiseInterface) {
return $reason;
@ -50,12 +49,10 @@ final class Create
* Create an exception for a rejected promise value.
*
* @param mixed $reason
*
* @return \Exception|\Throwable
*/
public static function exceptionFor($reason)
public static function exceptionFor($reason): \Throwable
{
if ($reason instanceof \Exception || $reason instanceof \Throwable) {
if ($reason instanceof \Throwable) {
return $reason;
}
@ -66,10 +63,8 @@ final class Create
* Returns an iterator for the given value.
*
* @param mixed $value
*
* @return \Iterator
*/
public static function iterFor($value)
public static function iterFor($value): \Iterator
{
if ($value instanceof \Iterator) {
return $value;

View File

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace GuzzleHttp\Promise;
final class Each
@ -20,17 +22,15 @@ final class Each
* @param mixed $iterable Iterator or array to iterate over.
* @param callable $onFulfilled
* @param callable $onRejected
*
* @return PromiseInterface
*/
public static function of(
$iterable,
callable $onFulfilled = null,
callable $onRejected = null
) {
): PromiseInterface {
return (new EachPromise($iterable, [
'fulfilled' => $onFulfilled,
'rejected' => $onRejected
'rejected' => $onRejected,
]))->promise();
}
@ -46,19 +46,17 @@ final class Each
* @param int|callable $concurrency
* @param callable $onFulfilled
* @param callable $onRejected
*
* @return PromiseInterface
*/
public static function ofLimit(
$iterable,
$concurrency,
callable $onFulfilled = null,
callable $onRejected = null
) {
): PromiseInterface {
return (new EachPromise($iterable, [
'fulfilled' => $onFulfilled,
'rejected' => $onRejected,
'concurrency' => $concurrency
'fulfilled' => $onFulfilled,
'rejected' => $onRejected,
'concurrency' => $concurrency,
]))->promise();
}
@ -70,19 +68,17 @@ final class Each
* @param mixed $iterable
* @param int|callable $concurrency
* @param callable $onFulfilled
*
* @return PromiseInterface
*/
public static function ofLimitAll(
$iterable,
$concurrency,
callable $onFulfilled = null
) {
return each_limit(
): PromiseInterface {
return self::ofLimit(
$iterable,
$concurrency,
$onFulfilled,
function ($reason, $idx, PromiseInterface $aggregate) {
function ($reason, $idx, PromiseInterface $aggregate): void {
$aggregate->reject($reason);
}
);

View File

@ -1,10 +1,14 @@
<?php
declare(strict_types=1);
namespace GuzzleHttp\Promise;
/**
* Represents a promise that iterates over many promises and invokes
* side-effect functions in the process.
*
* @final
*/
class EachPromise implements PromisorInterface
{
@ -69,7 +73,7 @@ class EachPromise implements PromisorInterface
}
/** @psalm-suppress InvalidNullableReturnType */
public function promise()
public function promise(): PromiseInterface
{
if ($this->aggregate) {
return $this->aggregate;
@ -82,21 +86,18 @@ class EachPromise implements PromisorInterface
$this->refillPending();
} catch (\Throwable $e) {
$this->aggregate->reject($e);
} catch (\Exception $e) {
$this->aggregate->reject($e);
}
/**
* @psalm-suppress NullableReturnStatement
* @phpstan-ignore-next-line
*/
return $this->aggregate;
}
private function createPromise()
private function createPromise(): void
{
$this->mutex = false;
$this->aggregate = new Promise(function () {
$this->aggregate = new Promise(function (): void {
if ($this->checkIfFinished()) {
return;
}
@ -113,7 +114,7 @@ class EachPromise implements PromisorInterface
});
// Clear the references when the promise is resolved.
$clearFn = function () {
$clearFn = function (): void {
$this->iterable = $this->concurrency = $this->pending = null;
$this->onFulfilled = $this->onRejected = null;
$this->nextPendingIndex = 0;
@ -122,11 +123,13 @@ class EachPromise implements PromisorInterface
$this->aggregate->then($clearFn, $clearFn);
}
private function refillPending()
private function refillPending(): void
{
if (!$this->concurrency) {
// Add all pending promises.
while ($this->addPending() && $this->advanceIterator());
while ($this->addPending() && $this->advanceIterator()) {
}
return;
}
@ -147,10 +150,11 @@ class EachPromise implements PromisorInterface
// next value to yield until promise callbacks are called.
while (--$concurrency
&& $this->advanceIterator()
&& $this->addPending());
&& $this->addPending()) {
}
}
private function addPending()
private function addPending(): bool
{
if (!$this->iterable || !$this->iterable->valid()) {
return false;
@ -164,7 +168,7 @@ class EachPromise implements PromisorInterface
$idx = $this->nextPendingIndex++;
$this->pending[$idx] = $promise->then(
function ($value) use ($idx, $key) {
function ($value) use ($idx, $key): void {
if ($this->onFulfilled) {
call_user_func(
$this->onFulfilled,
@ -175,7 +179,7 @@ class EachPromise implements PromisorInterface
}
$this->step($idx);
},
function ($reason) use ($idx, $key) {
function ($reason) use ($idx, $key): void {
if ($this->onRejected) {
call_user_func(
$this->onRejected,
@ -191,7 +195,7 @@ class EachPromise implements PromisorInterface
return true;
}
private function advanceIterator()
private function advanceIterator(): bool
{
// Place a lock on the iterator so that we ensure to not recurse,
// preventing fatal generator errors.
@ -204,19 +208,17 @@ class EachPromise implements PromisorInterface
try {
$this->iterable->next();
$this->mutex = false;
return true;
} catch (\Throwable $e) {
$this->aggregate->reject($e);
$this->mutex = false;
return false;
} catch (\Exception $e) {
$this->aggregate->reject($e);
$this->mutex = false;
return false;
}
}
private function step($idx)
private function step(int $idx): void
{
// If the promise was already resolved, then ignore this step.
if (Is::settled($this->aggregate)) {
@ -234,11 +236,12 @@ class EachPromise implements PromisorInterface
}
}
private function checkIfFinished()
private function checkIfFinished(): bool
{
if (!$this->pending && !$this->iterable->valid()) {
// Resolve the promise if there's nothing left to do.
$this->aggregate->resolve(null);
return true;
}

View File

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace GuzzleHttp\Promise;
/**
@ -7,11 +9,16 @@ namespace GuzzleHttp\Promise;
*
* Thenning off of this promise will invoke the onFulfilled callback
* immediately and ignore other callbacks.
*
* @final
*/
class FulfilledPromise implements PromiseInterface
{
private $value;
/**
* @param mixed $value
*/
public function __construct($value)
{
if (is_object($value) && method_exists($value, 'then')) {
@ -26,7 +33,7 @@ class FulfilledPromise implements PromiseInterface
public function then(
callable $onFulfilled = null,
callable $onRejected = null
) {
): PromiseInterface {
// Return itself if there is no onFulfilled function.
if (!$onFulfilled) {
return $this;
@ -35,14 +42,12 @@ class FulfilledPromise implements PromiseInterface
$queue = Utils::queue();
$p = new Promise([$queue, 'run']);
$value = $this->value;
$queue->add(static function () use ($p, $value, $onFulfilled) {
$queue->add(static function () use ($p, $value, $onFulfilled): void {
if (Is::pending($p)) {
try {
$p->resolve($onFulfilled($value));
} catch (\Throwable $e) {
$p->reject($e);
} catch (\Exception $e) {
$p->reject($e);
}
}
});
@ -50,34 +55,34 @@ class FulfilledPromise implements PromiseInterface
return $p;
}
public function otherwise(callable $onRejected)
public function otherwise(callable $onRejected): PromiseInterface
{
return $this->then(null, $onRejected);
}
public function wait($unwrap = true, $defaultDelivery = null)
public function wait(bool $unwrap = true)
{
return $unwrap ? $this->value : null;
}
public function getState()
public function getState(): string
{
return self::FULFILLED;
}
public function resolve($value)
public function resolve($value): void
{
if ($value !== $this->value) {
throw new \LogicException("Cannot resolve a fulfilled promise");
throw new \LogicException('Cannot resolve a fulfilled promise');
}
}
public function reject($reason)
public function reject($reason): void
{
throw new \LogicException("Cannot reject a fulfilled promise");
throw new \LogicException('Cannot reject a fulfilled promise');
}
public function cancel()
public function cancel(): void
{
// pass
}

View File

@ -1,45 +1,39 @@
<?php
declare(strict_types=1);
namespace GuzzleHttp\Promise;
final class Is
{
/**
* Returns true if a promise is pending.
*
* @return bool
*/
public static function pending(PromiseInterface $promise)
public static function pending(PromiseInterface $promise): bool
{
return $promise->getState() === PromiseInterface::PENDING;
}
/**
* Returns true if a promise is fulfilled or rejected.
*
* @return bool
*/
public static function settled(PromiseInterface $promise)
public static function settled(PromiseInterface $promise): bool
{
return $promise->getState() !== PromiseInterface::PENDING;
}
/**
* Returns true if a promise is fulfilled.
*
* @return bool
*/
public static function fulfilled(PromiseInterface $promise)
public static function fulfilled(PromiseInterface $promise): bool
{
return $promise->getState() === PromiseInterface::FULFILLED;
}
/**
* Returns true if a promise is rejected.
*
* @return bool
*/
public static function rejected(PromiseInterface $promise)
public static function rejected(PromiseInterface $promise): bool
{
return $promise->getState() === PromiseInterface::REJECTED;
}

Some files were not shown because too many files have changed in this diff Show More