diff --git a/app/command/Zm.php b/app/command/Zm.php index 4a23231..a1ef8c1 100644 --- a/app/command/Zm.php +++ b/app/command/Zm.php @@ -11,6 +11,16 @@ use think\facade\Cache; use think\facade\Log; use GuzzleHttp\Client; +use GuzzleHttp\HandlerStack; +use Kevinrob\GuzzleCache\CacheMiddleware; +use Kevinrob\GuzzleCache\Strategy\Delegate\RequestMatcher; +use Kevinrob\GuzzleCache\Strategy\GreedyCacheStrategy; +use Kevinrob\GuzzleCache\Storage\Psr6CacheStorage; +use Symfony\Component\Cache\Adapter\RedisAdapter; + + + + class Zm extends Command { private $aria2 = null; @@ -35,10 +45,13 @@ class Zm extends Command $this->aria2->setOption('enable-http-pipelining', true); //设置http管道化 $this->aria2->setOption('enable-http-keep-alive', true); //设置http保持连接 - // Disable SSL verification for cURL requests + + + $cachePath = runtime_path() . 'guzzle_cache'; $this->client = new Client([ 'verify' => false, ]); + $this->completed = false; while($this->completed === false){ try { @@ -69,14 +82,19 @@ class Zm extends Command $curr_total++; $curr_item = $value; $curr_item_title = $curr_item['title']; - $c = $savepath . '/' . $lable_title . '/' . $curr_item_title; + $c = trim($savepath . '/' . $lable_title . '/' . $curr_item_title); // dump('存储路径',$c); - is_dir($c) || mkdir($c,0755,true); + try { + is_dir($c) || mkdir($c,0755,true); + } catch (\Exception $e) { + dump('创建目录失败:',$c,$e->getMessage()); + throw $e; + } - $author = $savepath . '/' . $lable_title . '/' . $curr_item_title . '/' . '作者.txt'; + $author = $c . '/' . '作者.txt'; $this->savetxt($author,$curr_item['author']); - $introduce = $savepath . '/' . $lable_title . '/' . $curr_item_title . '/' . '介绍.txt'; + $introduce = $c . '/' . '介绍.txt'; $this->savetxt($introduce,$curr_item['introduce']); $cover = $curr_item['cover']; @@ -87,8 +105,13 @@ class Zm extends Command $this->savetxt($cover_path,$cover); $curr_details = $this->getCurrDetails($curr_item['id']); foreach($curr_details['data']['curriculum']['allClassSectionTrue'] as $class){ - $class_path = $c . '/' . $class['title']; - is_dir($class_path) || mkdir($class_path,0755,true); + $class_path = trim($c . '/' . $class['title']); + try { + is_dir($class_path) || mkdir($class_path,0755,true); + } catch (\Exception $e) { + dump('创建目录失败:',$class_path,$e->getMessage()); + throw $e; + } $class_details = $this->getClassDetails($class['id']); if($class_details == false){ dump('课程未授权,跳过下载',$class['title']); @@ -265,11 +288,16 @@ class Zm extends Command if($result['code'] == -3){ return $this->getLable($result['sign']); }else{ + return $result; } } public function getCurr($label_id,$page,$sign = 'null') { + $cacheKey = 'zm_curr_' . $label_id . '_' . $page; + if(Cache::has($cacheKey)){ + return Cache::get($cacheKey); + } $options = [ 'headers'=>[ 'User-Agent'=>'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36 Core/1.116.489.400 QQBrowser/13.7.6351.400', @@ -289,6 +317,7 @@ class Zm extends Command if($result['code'] == -3){ return $this->getCurr($label_id,$page,$result['sign']); }else if($result['code'] == 0){ + Cache::set($cacheKey,$result,86400); return $result; }else{ dump($result['msg']); @@ -299,6 +328,10 @@ class Zm extends Command public function getCurrDetails($curr_id,$sign = 'null') { + $cacheKey = 'zm_curr_details_' . $curr_id; + if(Cache::has($cacheKey)){ + return Cache::get($cacheKey); + } $options = [ 'headers'=>[ 'User-Agent'=>'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36 Core/1.116.489.400 QQBrowser/13.7.6351.400', @@ -318,6 +351,7 @@ class Zm extends Command if($result['code'] == -3){ return $this->getCurrDetails($curr_id,$result['sign']); }else if($result['code'] == 0){ + Cache::set($cacheKey,$result,86400); return $result; }else{ dump($result['msg']); @@ -326,6 +360,10 @@ class Zm extends Command } public function getClassDetails($curr_id,$sign = 'null') { + $cacheKey = 'zm_class_details_' . $curr_id; + if(Cache::has($cacheKey)){ + return Cache::get($cacheKey); + } $options = [ 'headers'=>[ 'User-Agent'=>'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36 Core/1.116.489.400 QQBrowser/13.7.6351.400', @@ -346,6 +384,7 @@ class Zm extends Command if($result['code'] == -3){ return $this->getClassDetails($curr_id,$result['sign']); }else if($result['code'] == 0){ + Cache::set($cacheKey,$result,86400); return $result; }else if($result['code'] == -5){ return false; @@ -355,8 +394,6 @@ class Zm extends Command } } - - private function savetxt(string $file,string $content) { if(is_file($file)){ diff --git a/composer.json b/composer.json index a45e728..b55a68f 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,9 @@ "guzzlehttp/guzzle": "~6.0", "php-curl-class/php-curl-class": "^9.14", "topthink/think-helper": "^3.1", - "daijie/aria2": "^1.1" + "daijie/aria2": "^1.1", + "symfony/cache": "^5.4", + "kevinrob/guzzle-cache-middleware": "^5.1" }, "require-dev": { "symfony/var-dumper": "^4.2", diff --git a/composer.lock b/composer.lock index 3763516..bf494e5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d6bbbbddb2fa51632500960dcedcee8c", + "content-hash": "dae1d18c69bcda3f527544eda43b3049", "packages": [ { "name": "daijie/aria2", @@ -67,9 +67,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/guzzlehttp/guzzle/6.5.8/guzzlehttp-guzzle-6.5.8.zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-json": "*", @@ -100,6 +106,7 @@ "GuzzleHttp\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -151,21 +158,45 @@ "rest", "web service" ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], "time": "2022-06-20T22:16:07+00:00" }, { "name": "guzzlehttp/promises", - "version": "1.5.2", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "b94b2807d85443f9719887892882d0329d1e2598" + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/guzzlehttp/promises/1.5.2/guzzlehttp-promises-1.5.2.zip", - "reference": "b94b2807d85443f9719887892882d0329d1e2598", - "shasum": "" + "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.5" @@ -174,11 +205,6 @@ "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5-dev" - } - }, "autoload": { "files": [ "src/functions_include.php" @@ -187,6 +213,7 @@ "GuzzleHttp\\Promise\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -216,21 +243,45 @@ "keywords": [ "promise" ], - "time": "2022-08-28T14:55:35+00:00" + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-05-21T12:31:43+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/guzzlehttp/psr7/1.9.0/guzzlehttp-psr7-1.9.0.zip", - "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", - "shasum": "" + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.4.0", @@ -248,11 +299,6 @@ "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - }, "autoload": { "files": [ "src/functions_include.php" @@ -261,6 +307,7 @@ "GuzzleHttp\\Psr7\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -307,7 +354,116 @@ "uri", "url" ], - "time": "2022-06-20T21:43:03+00:00" + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-04-17T16:00:37+00:00" + }, + { + "name": "kevinrob/guzzle-cache-middleware", + "version": "v5.1.0", + "source": { + "type": "git", + "url": "https://github.com/Kevinrob/guzzle-cache-middleware.git", + "reference": "6bd64dbbe5155107d84a0f67140a8822a709c6d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Kevinrob/guzzle-cache-middleware/zipball/6bd64dbbe5155107d84a0f67140a8822a709c6d0", + "reference": "6bd64dbbe5155107d84a0f67140a8822a709c6d0", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "guzzlehttp/promises": "^1.4 || ^2.0", + "guzzlehttp/psr7": "^1.7.0 || ^2.0.0", + "php": ">=7.2.0" + }, + "require-dev": { + "cache/array-adapter": "^0.4 || ^0.5 || ^1.0", + "cache/simple-cache-bridge": "^0.1 || ^1.0", + "doctrine/cache": "^1.10", + "illuminate/cache": "^5.0", + "league/flysystem": "^2.5", + "phpunit/phpunit": "^8.5.15 || ^9.5", + "psr/cache": "^1.0", + "symfony/cache": "^4.4 || ^5.0", + "symfony/phpunit-bridge": "^4.4 || ^5.0" + }, + "suggest": { + "doctrine/cache": "This library has a lot of ready-to-use cache storage (to be used with Kevinrob\\GuzzleCache\\Storage\\DoctrineCacheStorage). Use only versions >=1.4.0 < 2.0.0", + "guzzlehttp/guzzle": "For using this library. It was created for Guzzle6 (but you can use it with any PSR-7 HTTP client).", + "laravel/framework": "To be used with Kevinrob\\GuzzleCache\\Storage\\LaravelCacheStorage", + "league/flysystem": "To be used with Kevinrob\\GuzzleCache\\Storage\\FlysystemStorage", + "psr/cache": "To be used with Kevinrob\\GuzzleCache\\Storage\\Psr6CacheStorage", + "psr/simple-cache": "To be used with Kevinrob\\GuzzleCache\\Storage\\Psr16CacheStorage" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kevinrob\\GuzzleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Robatel", + "email": "kevinrob2@gmail.com", + "homepage": "https://github.com/Kevinrob" + } + ], + "description": "A HTTP/1.1 Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack. (RFC 7234)", + "homepage": "https://github.com/Kevinrob/guzzle-cache-middleware", + "keywords": [ + "Etag", + "Flysystem", + "Guzzle", + "cache", + "cache-control", + "doctrine", + "expiration", + "guzzle6", + "handler", + "http", + "http 1.1", + "middleware", + "performance", + "php", + "promise", + "psr6", + "psr7", + "rfc7234", + "validation" + ], + "support": { + "issues": "https://github.com/Kevinrob/guzzle-cache-middleware/issues", + "source": "https://github.com/Kevinrob/guzzle-cache-middleware/tree/v5.1.0" + }, + "time": "2023-11-09T06:53:45+00:00" }, { "name": "league/flysystem", @@ -319,9 +475,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/league/flysystem/1.1.10/league-flysystem-1.1.10.zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-fileinfo": "*", @@ -361,6 +523,7 @@ "League\\Flysystem\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -390,6 +553,16 @@ "sftp", "storage" ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.1.10" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], "time": "2022-10-04T09:16:37+00:00" }, { @@ -402,9 +575,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/league/flysystem-cached-adapter/1.1.0/league-flysystem-cached-adapter-1.1.0.zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "league/flysystem": "~1.0", @@ -426,6 +605,7 @@ "League\\Flysystem\\Cached\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -436,21 +616,31 @@ } ], "description": "An adapter decorator to enable meta-data caching.", + "support": { + "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", + "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" + }, "time": "2020-07-25T15:56:04+00:00" }, { "name": "league/mime-type-detection", - "version": "1.11.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" + "reference": "c7f2872fb273bf493811473dafc88d60ae829f48" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/league/mime-type-detection/1.11.0/league-mime-type-detection-1.11.0.zip", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", - "shasum": "" + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/c7f2872fb273bf493811473dafc88d60ae829f48", + "reference": "c7f2872fb273bf493811473dafc88d60ae829f48", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-fileinfo": "*", @@ -467,6 +657,7 @@ "League\\MimeTypeDetection\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -477,21 +668,41 @@ } ], "description": "Mime-type detection for Flysystem", - "time": "2022-04-17T13:12:02+00:00" + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.12.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2023-08-03T07:14:11+00:00" }, { "name": "php-curl-class/php-curl-class", - "version": "9.14.3", + "version": "9.19.2", "source": { "type": "git", "url": "https://github.com/php-curl-class/php-curl-class.git", - "reference": "5d87676a3a7f83dd33d65f3c8d97f36679305193" + "reference": "c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/php-curl-class/php-curl-class/9.14.3/php-curl-class-php-curl-class-9.14.3.zip", - "reference": "5d87676a3a7f83dd33d65f3c8d97f36679305193", - "shasum": "" + "url": "https://api.github.com/repos/php-curl-class/php-curl-class/zipball/c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294", + "reference": "c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-curl": "*", @@ -500,11 +711,12 @@ "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "*", "ext-gd": "*", + "friendsofphp/php-cs-fixer": "*", "phpcompatibility/php-compatibility": "dev-develop", "phpcsstandards/phpcsutils": "@alpha", "phpunit/phpunit": "*", "squizlabs/php_codesniffer": "*", - "vimeo/psalm": "*" + "vimeo/psalm": ">=0.3.63" }, "suggest": { "ext-mbstring": "*" @@ -515,12 +727,17 @@ "Curl\\": "src/Curl/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "Unlicense" ], "authors": [ { "name": "Zach Borboa" + }, + { + "name": "Contributors", + "homepage": "https://github.com/php-curl-class/php-curl-class/graphs/contributors" } ], "description": "PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs.", @@ -547,7 +764,11 @@ "web-service", "xml" ], - "time": "2023-03-13T18:02:56+00:00" + "support": { + "issues": "https://github.com/php-curl-class/php-curl-class/issues", + "source": "https://github.com/php-curl-class/php-curl-class/tree/9.19.2" + }, + "time": "2024-04-09T18:03:13+00:00" }, { "name": "psr/cache", @@ -559,9 +780,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/psr/cache/1.0.1/psr-cache-1.0.1.zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.3.0" @@ -577,6 +804,7 @@ "Psr\\Cache\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -592,6 +820,9 @@ "psr", "psr-6" ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, "time": "2016-08-06T20:24:11+00:00" }, { @@ -604,9 +835,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/psr/container/1.1.1/psr-container-1.1.1.zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=7.2.0" @@ -617,6 +854,7 @@ "Psr\\Container\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -635,6 +873,10 @@ "container-interop", "psr" ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, "time": "2021-03-05T17:36:06+00:00" }, { @@ -647,9 +889,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/psr/http-message/1.1/psr-http-message-1.1.zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": "^7.2 || ^8.0" @@ -665,6 +913,7 @@ "Psr\\Http\\Message\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -684,6 +933,9 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, "time": "2023-04-04T09:50:52+00:00" }, { @@ -696,9 +948,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/psr/log/1.1.4/psr-log-1.1.4.zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", "reference": "d49695b909c3b7628b6289db5479a1c204601f11", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.3.0" @@ -714,6 +972,7 @@ "Psr\\Log\\": "Psr/Log/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -730,6 +989,9 @@ "psr", "psr-3" ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, "time": "2021-05-03T11:20:27+00:00" }, { @@ -742,9 +1004,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/psr/simple-cache/1.0.1/psr-simple-cache-1.0.1.zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.3.0" @@ -760,6 +1028,7 @@ "Psr\\SimpleCache\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -777,6 +1046,9 @@ "psr-16", "simple-cache" ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, "time": "2017-10-23T01:57:42+00:00" }, { @@ -789,9 +1061,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/ralouphie/getallheaders/3.0.3/ralouphie-getallheaders-3.0.3.zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.6" @@ -806,6 +1084,7 @@ "src/getallheaders.php" ] }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -816,35 +1095,302 @@ } ], "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, "time": "2019-03-08T08:55:37+00:00" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.27.0", + "name": "symfony/cache", + "version": "v5.4.46", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + "url": "https://github.com/symfony/cache.git", + "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-intl-idn/v1.27.0/symfony-polyfill-intl-idn-v1.27.0.zip", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da", - "shasum": "" + "url": "https://api.github.com/repos/symfony/cache/zipball/0fe08ee32cec2748fbfea10c52d3ee02049e0f6b", + "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/var-exporter": "^4.4|^5.0|^6.0" + }, + "conflict": { + "doctrine/dbal": "<2.13.1", + "symfony/dependency-injection": "<4.4", + "symfony/http-kernel": "<4.4", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v5.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-04T11:43:55+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/517c3a3619dadfa6952c4651767fcadffb4df65e", + "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "2.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -858,6 +1404,7 @@ "Symfony\\Polyfill\\Intl\\Idn\\": "" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -885,33 +1432,53 @@ "portable", "shim" ], - "time": "2022-11-03T14:55:06+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.27.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-intl-normalizer/v1.27.0/symfony-polyfill-intl-normalizer-v1.27.0.zip", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "shasum": "" + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -928,6 +1495,7 @@ "Resources/stubs" ] }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -951,33 +1519,53 @@ "portable", "shim" ], - "time": "2022-11-03T14:55:06+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/polyfill-php72", - "version": "v1.27.0", + "name": "symfony/polyfill-php73", + "version": "v1.31.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-php72/v1.27.0/symfony-polyfill-php72-v1.27.0.zip", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", - "shasum": "" + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -985,9 +1573,13 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - } + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -1001,7 +1593,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1009,7 +1601,278 @@ "portable", "shim" ], - "time": "2022-11-03T14:55:06+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v5.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "862700068db0ddfd8c5b850671e029a90246ec75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/862700068db0ddfd8c5b850671e029a90246ec75", + "reference": "862700068db0ddfd8c5b850671e029a90246ec75", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v5.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" }, { "name": "topthink/framework", @@ -1092,9 +1955,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/topthink/think-filesystem/v1.0.3/topthink-think-filesystem-v1.0.3.zip", + "url": "https://api.github.com/repos/top-think/think-filesystem/zipball/29f19f140a9267c717fecd7ccb22c84c2d72382e", "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "league/flysystem": "^1.1.4", @@ -1113,6 +1982,7 @@ "think\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "Apache-2.0" ], @@ -1123,21 +1993,31 @@ } ], "description": "The ThinkPHP6.1 Filesystem Package", + "support": { + "issues": "https://github.com/top-think/think-filesystem/issues", + "source": "https://github.com/top-think/think-filesystem/tree/v1.0.3" + }, "time": "2023-02-08T01:25:15+00:00" }, { "name": "topthink/think-helper", - "version": "v3.1.6", + "version": "v3.1.11", "source": { "type": "git", "url": "https://github.com/top-think/think-helper.git", - "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff" + "reference": "1d6ada9b9f3130046bf6922fe1bd159c8d88a33c" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/topthink/think-helper/v3.1.6/topthink-think-helper-v3.1.6.zip", - "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff", - "shasum": "" + "url": "https://api.github.com/repos/top-think/think-helper/zipball/1d6ada9b9f3130046bf6922fe1bd159c8d88a33c", + "reference": "1d6ada9b9f3130046bf6922fe1bd159c8d88a33c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=7.1.0" @@ -1154,6 +2034,7 @@ "think\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "Apache-2.0" ], @@ -1164,21 +2045,31 @@ } ], "description": "The ThinkPHP6 Helper Package", - "time": "2021-12-15T04:27:55+00:00" + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/v3.1.11" + }, + "time": "2025-04-07T06:55:59+00:00" }, { "name": "topthink/think-orm", - "version": "v2.0.60", + "version": "v2.0.62", "source": { "type": "git", "url": "https://github.com/top-think/think-orm.git", - "reference": "8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46" + "reference": "e53bfea572a133039ad687077120de5521af617f" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/topthink/think-orm/v2.0.60/topthink-think-orm-v2.0.60.zip", - "reference": "8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46", - "shasum": "" + "url": "https://api.github.com/repos/top-think/think-orm/zipball/e53bfea572a133039ad687077120de5521af617f", + "reference": "e53bfea572a133039ad687077120de5521af617f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-json": "*", @@ -1200,6 +2091,7 @@ "think\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "Apache-2.0" ], @@ -1214,26 +2106,36 @@ "database", "orm" ], - "time": "2023-03-19T04:51:56+00:00" + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.62" + }, + "time": "2024-09-22T06:17:47+00:00" } ], "packages-dev": [ { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-mbstring/v1.27.0/symfony-polyfill-mbstring-v1.27.0.zip", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "shasum": "" + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -1243,9 +2145,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1259,6 +2158,7 @@ "Symfony\\Polyfill\\Mbstring\\": "" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -1281,54 +2181,60 @@ "portable", "shim" ], - "time": "2022-11-03T14:55:06+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "name": "symfony/polyfill-php72", + "version": "v1.31.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-php80/v1.27.0/symfony-polyfill-php80-v1.27.0.zip", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "shasum": "" + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", + "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, - "type": "library", + "type": "metapackage", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -1338,7 +2244,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1346,7 +2252,24 @@ "portable", "shim" ], - "time": "2022-11-03T14:55:06+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/var-dumper", @@ -1358,9 +2281,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/var-dumper/v4.4.47/symfony-var-dumper-v4.4.47.zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=7.1.3", @@ -1398,6 +2327,7 @@ "/Tests/" ] }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -1417,6 +2347,23 @@ "debug", "dump" ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2022-10-03T15:15:11+00:00" }, { @@ -1429,9 +2376,15 @@ }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/topthink/think-trace/v1.6/topthink-think-trace-v1.6.zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/136cd5d97e8bdb780e4b5c1637c588ed7ca3e142", "reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=7.1.0", @@ -1440,12 +2393,12 @@ "type": "library", "extra": { "think": { - "services": [ - "think\\trace\\Service" - ], "config": { "trace": "src/config.php" - } + }, + "services": [ + "think\\trace\\Service" + ] } }, "autoload": { @@ -1453,6 +2406,7 @@ "think\\trace\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "Apache-2.0" ], @@ -1463,6 +2417,10 @@ } ], "description": "thinkphp debug trace", + "support": { + "issues": "https://github.com/top-think/think-trace/issues", + "source": "https://github.com/top-think/think-trace/tree/v1.6" + }, "time": "2023-02-07T08:36:32+00:00" } ], diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index cae0fc2..351cc2f 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -8,6 +8,7 @@ $baseDir = dirname($vendorDir); return array( 'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.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', 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index 8397394..56d0de9 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -7,15 +7,16 @@ $baseDir = dirname($vendorDir); return array( '9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php', - '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', - '35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php', '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', - 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', - '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', - 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 2ebe67f..80d94f7 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -7,14 +7,18 @@ $baseDir = dirname($vendorDir); return array( 'think\\trace\\' => array($vendorDir . '/topthink/think-trace/src'), - 'think\\' => array($vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/framework/src/think', $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'), 'app\\' => array($baseDir . '/app'), 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), - 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), + 'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), + 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), + 'Symfony\\Contracts\\Cache\\' => array($vendorDir . '/symfony/cache-contracts'), + 'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'), 'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'), + 'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'), 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), @@ -23,6 +27,7 @@ return array( 'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), 'League\\Flysystem\\Cached\\' => array($vendorDir . '/league/flysystem-cached-adapter/src'), 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), + 'Kevinrob\\GuzzleCache\\' => array($vendorDir . '/kevinrob/guzzle-cache-middleware/src'), 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 2b3c7f6..faefb95 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -8,16 +8,17 @@ class ComposerStaticInit39c91b02671a17b9a5c68011e075e1a2 { public static $files = array ( '9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php', - '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', - '35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php', '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', - 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php', 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', - '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', - 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', ); @@ -34,11 +35,15 @@ class ComposerStaticInit39c91b02671a17b9a5c68011e075e1a2 'S' => array ( 'Symfony\\Polyfill\\Php80\\' => 23, - 'Symfony\\Polyfill\\Php72\\' => 23, + 'Symfony\\Polyfill\\Php73\\' => 23, 'Symfony\\Polyfill\\Mbstring\\' => 26, 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, + 'Symfony\\Contracts\\Service\\' => 26, + 'Symfony\\Contracts\\Cache\\' => 24, + 'Symfony\\Component\\VarExporter\\' => 30, 'Symfony\\Component\\VarDumper\\' => 28, + 'Symfony\\Component\\Cache\\' => 24, ), 'P' => array ( @@ -54,6 +59,10 @@ class ComposerStaticInit39c91b02671a17b9a5c68011e075e1a2 'League\\Flysystem\\Cached\\' => 24, 'League\\Flysystem\\' => 17, ), + 'K' => + array ( + 'Kevinrob\\GuzzleCache\\' => 21, + ), 'G' => array ( 'GuzzleHttp\\Psr7\\' => 16, @@ -73,10 +82,10 @@ class ComposerStaticInit39c91b02671a17b9a5c68011e075e1a2 ), 'think\\' => array ( - 0 => __DIR__ . '/..' . '/topthink/think-helper/src', - 1 => __DIR__ . '/..' . '/topthink/think-orm/src', - 2 => __DIR__ . '/..' . '/topthink/framework/src/think', - 3 => __DIR__ . '/..' . '/topthink/think-filesystem/src', + 0 => __DIR__ . '/..' . '/topthink/framework/src/think', + 1 => __DIR__ . '/..' . '/topthink/think-filesystem/src', + 2 => __DIR__ . '/..' . '/topthink/think-helper/src', + 3 => __DIR__ . '/..' . '/topthink/think-orm/src', ), 'app\\' => array ( @@ -86,9 +95,9 @@ class ComposerStaticInit39c91b02671a17b9a5c68011e075e1a2 array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', ), - 'Symfony\\Polyfill\\Php72\\' => + 'Symfony\\Polyfill\\Php73\\' => array ( - 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', + 0 => __DIR__ . '/..' . '/symfony/polyfill-php73', ), 'Symfony\\Polyfill\\Mbstring\\' => array ( @@ -102,10 +111,26 @@ class ComposerStaticInit39c91b02671a17b9a5c68011e075e1a2 array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn', ), + 'Symfony\\Contracts\\Service\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/service-contracts', + ), + 'Symfony\\Contracts\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/cache-contracts', + ), + 'Symfony\\Component\\VarExporter\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/var-exporter', + ), 'Symfony\\Component\\VarDumper\\' => array ( 0 => __DIR__ . '/..' . '/symfony/var-dumper', ), + 'Symfony\\Component\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/cache', + ), 'Psr\\SimpleCache\\' => array ( 0 => __DIR__ . '/..' . '/psr/simple-cache/src', @@ -138,6 +163,10 @@ class ComposerStaticInit39c91b02671a17b9a5c68011e075e1a2 array ( 0 => __DIR__ . '/..' . '/league/flysystem/src', ), + 'Kevinrob\\GuzzleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/kevinrob/guzzle-cache-middleware/src', + ), 'GuzzleHttp\\Psr7\\' => array ( 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', @@ -167,6 +196,7 @@ class ComposerStaticInit39c91b02671a17b9a5c68011e075e1a2 public static $classMap = array ( 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.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', 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 5dc2968..769d1dc 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -155,18 +155,24 @@ }, { "name": "guzzlehttp/promises", - "version": "1.5.2", - "version_normalized": "1.5.2.0", + "version": "1.5.3", + "version_normalized": "1.5.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "b94b2807d85443f9719887892882d0329d1e2598" + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/guzzlehttp/promises/1.5.2/guzzlehttp-promises-1.5.2.zip", - "reference": "b94b2807d85443f9719887892882d0329d1e2598", - "shasum": "" + "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.5" @@ -174,13 +180,8 @@ "require-dev": { "symfony/phpunit-bridge": "^4.4 || ^5.1" }, - "time": "2022-08-28T14:55:35+00:00", + "time": "2023-05-21T12:31:43+00:00", "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5-dev" - } - }, "installation-source": "dist", "autoload": { "files": [ @@ -190,6 +191,7 @@ "GuzzleHttp\\Promise\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -219,22 +221,46 @@ "keywords": [ "promise" ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], "install-path": "../guzzlehttp/promises" }, { "name": "guzzlehttp/psr7", - "version": "1.9.0", - "version_normalized": "1.9.0.0", + "version": "1.9.1", + "version_normalized": "1.9.1.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/guzzlehttp/psr7/1.9.0/guzzlehttp-psr7-1.9.0.zip", - "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", - "shasum": "" + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.4.0", @@ -251,13 +277,8 @@ "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, - "time": "2022-06-20T21:43:03+00:00", + "time": "2023-04-17T16:00:37+00:00", "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - }, "installation-source": "dist", "autoload": { "files": [ @@ -267,6 +288,7 @@ "GuzzleHttp\\Psr7\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -313,8 +335,120 @@ "uri", "url" ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], "install-path": "../guzzlehttp/psr7" }, + { + "name": "kevinrob/guzzle-cache-middleware", + "version": "v5.1.0", + "version_normalized": "5.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/Kevinrob/guzzle-cache-middleware.git", + "reference": "6bd64dbbe5155107d84a0f67140a8822a709c6d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Kevinrob/guzzle-cache-middleware/zipball/6bd64dbbe5155107d84a0f67140a8822a709c6d0", + "reference": "6bd64dbbe5155107d84a0f67140a8822a709c6d0", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "guzzlehttp/promises": "^1.4 || ^2.0", + "guzzlehttp/psr7": "^1.7.0 || ^2.0.0", + "php": ">=7.2.0" + }, + "require-dev": { + "cache/array-adapter": "^0.4 || ^0.5 || ^1.0", + "cache/simple-cache-bridge": "^0.1 || ^1.0", + "doctrine/cache": "^1.10", + "illuminate/cache": "^5.0", + "league/flysystem": "^2.5", + "phpunit/phpunit": "^8.5.15 || ^9.5", + "psr/cache": "^1.0", + "symfony/cache": "^4.4 || ^5.0", + "symfony/phpunit-bridge": "^4.4 || ^5.0" + }, + "suggest": { + "doctrine/cache": "This library has a lot of ready-to-use cache storage (to be used with Kevinrob\\GuzzleCache\\Storage\\DoctrineCacheStorage). Use only versions >=1.4.0 < 2.0.0", + "guzzlehttp/guzzle": "For using this library. It was created for Guzzle6 (but you can use it with any PSR-7 HTTP client).", + "laravel/framework": "To be used with Kevinrob\\GuzzleCache\\Storage\\LaravelCacheStorage", + "league/flysystem": "To be used with Kevinrob\\GuzzleCache\\Storage\\FlysystemStorage", + "psr/cache": "To be used with Kevinrob\\GuzzleCache\\Storage\\Psr6CacheStorage", + "psr/simple-cache": "To be used with Kevinrob\\GuzzleCache\\Storage\\Psr16CacheStorage" + }, + "time": "2023-11-09T06:53:45+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Kevinrob\\GuzzleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Robatel", + "email": "kevinrob2@gmail.com", + "homepage": "https://github.com/Kevinrob" + } + ], + "description": "A HTTP/1.1 Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack. (RFC 7234)", + "homepage": "https://github.com/Kevinrob/guzzle-cache-middleware", + "keywords": [ + "Etag", + "Flysystem", + "Guzzle", + "cache", + "cache-control", + "doctrine", + "expiration", + "guzzle6", + "handler", + "http", + "http 1.1", + "middleware", + "performance", + "php", + "promise", + "psr6", + "psr7", + "rfc7234", + "validation" + ], + "support": { + "issues": "https://github.com/Kevinrob/guzzle-cache-middleware/issues", + "source": "https://github.com/Kevinrob/guzzle-cache-middleware/tree/v5.1.0" + }, + "install-path": "../kevinrob/guzzle-cache-middleware" + }, { "name": "league/flysystem", "version": "1.1.10", @@ -452,18 +586,24 @@ }, { "name": "league/mime-type-detection", - "version": "1.11.0", - "version_normalized": "1.11.0.0", + "version": "1.12.0", + "version_normalized": "1.12.0.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" + "reference": "c7f2872fb273bf493811473dafc88d60ae829f48" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/league/mime-type-detection/1.11.0/league-mime-type-detection-1.11.0.zip", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", - "shasum": "" + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/c7f2872fb273bf493811473dafc88d60ae829f48", + "reference": "c7f2872fb273bf493811473dafc88d60ae829f48", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-fileinfo": "*", @@ -474,7 +614,7 @@ "phpstan/phpstan": "^0.12.68", "phpunit/phpunit": "^8.5.8 || ^9.3" }, - "time": "2022-04-17T13:12:02+00:00", + "time": "2023-08-03T07:14:11+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -482,6 +622,7 @@ "League\\MimeTypeDetection\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -492,22 +633,42 @@ } ], "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.12.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], "install-path": "../league/mime-type-detection" }, { "name": "php-curl-class/php-curl-class", - "version": "9.14.3", - "version_normalized": "9.14.3.0", + "version": "9.19.2", + "version_normalized": "9.19.2.0", "source": { "type": "git", "url": "https://github.com/php-curl-class/php-curl-class.git", - "reference": "5d87676a3a7f83dd33d65f3c8d97f36679305193" + "reference": "c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/php-curl-class/php-curl-class/9.14.3/php-curl-class-php-curl-class-9.14.3.zip", - "reference": "5d87676a3a7f83dd33d65f3c8d97f36679305193", - "shasum": "" + "url": "https://api.github.com/repos/php-curl-class/php-curl-class/zipball/c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294", + "reference": "c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-curl": "*", @@ -516,16 +677,17 @@ "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "*", "ext-gd": "*", + "friendsofphp/php-cs-fixer": "*", "phpcompatibility/php-compatibility": "dev-develop", "phpcsstandards/phpcsutils": "@alpha", "phpunit/phpunit": "*", "squizlabs/php_codesniffer": "*", - "vimeo/psalm": "*" + "vimeo/psalm": ">=0.3.63" }, "suggest": { "ext-mbstring": "*" }, - "time": "2023-03-13T18:02:56+00:00", + "time": "2024-04-09T18:03:13+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -533,12 +695,17 @@ "Curl\\": "src/Curl/" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "Unlicense" ], "authors": [ { "name": "Zach Borboa" + }, + { + "name": "Contributors", + "homepage": "https://github.com/php-curl-class/php-curl-class/graphs/contributors" } ], "description": "PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs.", @@ -565,6 +732,10 @@ "web-service", "xml" ], + "support": { + "issues": "https://github.com/php-curl-class/php-curl-class/issues", + "source": "https://github.com/php-curl-class/php-curl-class/tree/9.19.2" + }, "install-path": "../php-curl-class/php-curl-class" }, { @@ -855,34 +1026,306 @@ "install-path": "../ralouphie/getallheaders" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.27.0", - "version_normalized": "1.27.0.0", + "name": "symfony/cache", + "version": "v5.4.46", + "version_normalized": "5.4.46.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + "url": "https://github.com/symfony/cache.git", + "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-intl-idn/v1.27.0/symfony-polyfill-intl-idn-v1.27.0.zip", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da", - "shasum": "" + "url": "https://api.github.com/repos/symfony/cache/zipball/0fe08ee32cec2748fbfea10c52d3ee02049e0f6b", + "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/var-exporter": "^4.4|^5.0|^6.0" + }, + "conflict": { + "doctrine/dbal": "<2.13.1", + "symfony/dependency-injection": "<4.4", + "symfony/http-kernel": "<4.4", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "time": "2024-11-04T11:43:55+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v5.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/cache" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.4", + "version_normalized": "2.5.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/517c3a3619dadfa6952c4651767fcadffb4df65e", + "reference": "517c3a3619dadfa6952c4651767fcadffb4df65e", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "time": "2024-09-25T14:11:13+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "2.5-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/cache-contracts" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.4", + "version_normalized": "2.5.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.1" + }, + "time": "2024-09-25T14:11:13+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/deprecation-contracts" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, "suggest": { "ext-intl": "For best performance" }, - "time": "2022-11-03T14:55:06+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -897,6 +1340,7 @@ "Symfony\\Polyfill\\Intl\\Idn\\": "" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -924,35 +1368,55 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "install-path": "../symfony/polyfill-intl-idn" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.27.0", - "version_normalized": "1.27.0.0", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-intl-normalizer/v1.27.0/symfony-polyfill-intl-normalizer-v1.27.0.zip", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "shasum": "" + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, - "time": "2022-11-03T14:55:06+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -970,6 +1434,7 @@ "Resources/stubs" ] }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -993,25 +1458,48 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "install-path": "../symfony/polyfill-intl-normalizer" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", - "version_normalized": "1.27.0.0", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-mbstring/v1.27.0/symfony-polyfill-mbstring-v1.27.0.zip", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "shasum": "" + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -1019,12 +1507,9 @@ "suggest": { "ext-mbstring": "For best performance" }, - "time": "2022-11-03T14:55:06+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1039,6 +1524,7 @@ "Symfony\\Polyfill\\Mbstring\\": "" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -1061,46 +1547,58 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "install-path": "../symfony/polyfill-mbstring" }, { "name": "symfony/polyfill-php72", - "version": "v1.27.0", - "version_normalized": "1.27.0.0", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-php72/v1.27.0/symfony-polyfill-php72-v1.27.0.zip", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", - "shasum": "" + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", + "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, - "time": "2022-11-03T14:55:06+00:00", - "type": "library", + "time": "2024-09-09T11:45:10+00:00", + "type": "metapackage", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, - "installation-source": "dist", - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - } - }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -1122,35 +1620,140 @@ "portable", "shim" ], - "install-path": "../symfony/polyfill-php72" + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": null }, { - "name": "symfony/polyfill-php80", - "version": "v1.27.0", - "version_normalized": "1.27.0.0", + "name": "symfony/polyfill-php73", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/symfony/polyfill-php80/v1.27.0/symfony-polyfill-php80-v1.27.0.zip", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "shasum": "" + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, - "time": "2022-11-03T14:55:06+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php73" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2" + }, + "time": "2024-09-09T11:45:10+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -1165,6 +1768,7 @@ "Resources/stubs" ] }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -1190,8 +1794,117 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "install-path": "../symfony/polyfill-php80" }, + { + "name": "symfony/service-contracts", + "version": "v2.5.4", + "version_normalized": "2.5.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "time": "2024-09-25T14:11:13+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/service-contracts" + }, { "name": "symfony/var-dumper", "version": "v4.4.47", @@ -1266,6 +1979,88 @@ ], "install-path": "../symfony/var-dumper" }, + { + "name": "symfony/var-exporter", + "version": "v5.4.45", + "version_normalized": "5.4.45.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "862700068db0ddfd8c5b850671e029a90246ec75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/862700068db0ddfd8c5b850671e029a90246ec75", + "reference": "862700068db0ddfd8c5b850671e029a90246ec75", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + }, + "time": "2024-09-25T14:11:13+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v5.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/var-exporter" + }, { "name": "topthink/framework", "version": "v6.1.5", @@ -1388,18 +2183,24 @@ }, { "name": "topthink/think-helper", - "version": "v3.1.6", - "version_normalized": "3.1.6.0", + "version": "v3.1.11", + "version_normalized": "3.1.11.0", "source": { "type": "git", "url": "https://github.com/top-think/think-helper.git", - "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff" + "reference": "1d6ada9b9f3130046bf6922fe1bd159c8d88a33c" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/topthink/think-helper/v3.1.6/topthink-think-helper-v3.1.6.zip", - "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff", - "shasum": "" + "url": "https://api.github.com/repos/top-think/think-helper/zipball/1d6ada9b9f3130046bf6922fe1bd159c8d88a33c", + "reference": "1d6ada9b9f3130046bf6922fe1bd159c8d88a33c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=7.1.0" @@ -1407,7 +2208,7 @@ "require-dev": { "phpunit/phpunit": "^9.5" }, - "time": "2021-12-15T04:27:55+00:00", + "time": "2025-04-07T06:55:59+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1418,6 +2219,7 @@ "think\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "Apache-2.0" ], @@ -1428,22 +2230,32 @@ } ], "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/v3.1.11" + }, "install-path": "../topthink/think-helper" }, { "name": "topthink/think-orm", - "version": "v2.0.60", - "version_normalized": "2.0.60.0", + "version": "v2.0.62", + "version_normalized": "2.0.62.0", "source": { "type": "git", "url": "https://github.com/top-think/think-orm.git", - "reference": "8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46" + "reference": "e53bfea572a133039ad687077120de5521af617f" }, "dist": { "type": "zip", - "url": "https://repo.huaweicloud.com/repository/php/topthink/think-orm/v2.0.60/topthink-think-orm-v2.0.60.zip", - "reference": "8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46", - "shasum": "" + "url": "https://api.github.com/repos/top-think/think-orm/zipball/e53bfea572a133039ad687077120de5521af617f", + "reference": "e53bfea572a133039ad687077120de5521af617f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-json": "*", @@ -1456,7 +2268,7 @@ "require-dev": { "phpunit/phpunit": "^7|^8|^9.5" }, - "time": "2023-03-19T04:51:56+00:00", + "time": "2024-09-22T06:17:47+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1467,6 +2279,7 @@ "think\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", "license": [ "Apache-2.0" ], @@ -1481,6 +2294,10 @@ "database", "orm" ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.62" + }, "install-path": "../topthink/think-orm" }, { @@ -1536,7 +2353,7 @@ "dev": true, "dev-package-names": [ "symfony/polyfill-mbstring", - "symfony/polyfill-php80", + "symfony/polyfill-php72", "symfony/var-dumper", "topthink/think-trace" ] diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 378b914..bd80b52 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -29,23 +29,32 @@ 'dev_requirement' => false, ), 'guzzlehttp/promises' => array( - 'pretty_version' => '1.5.2', - 'version' => '1.5.2.0', - 'reference' => 'b94b2807d85443f9719887892882d0329d1e2598', + 'pretty_version' => '1.5.3', + 'version' => '1.5.3.0', + 'reference' => '67ab6e18aaa14d753cc148911d273f6e6cb6721e', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/promises', 'aliases' => array(), 'dev_requirement' => false, ), 'guzzlehttp/psr7' => array( - 'pretty_version' => '1.9.0', - 'version' => '1.9.0.0', - 'reference' => 'e98e3e6d4f86621a9b75f623996e6bbdeb4b9318', + 'pretty_version' => '1.9.1', + 'version' => '1.9.1.0', + 'reference' => 'e4490cabc77465aaee90b20cfc9a770f8c04be6b', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'aliases' => array(), 'dev_requirement' => false, ), + 'kevinrob/guzzle-cache-middleware' => array( + 'pretty_version' => 'v5.1.0', + 'version' => '5.1.0.0', + 'reference' => '6bd64dbbe5155107d84a0f67140a8822a709c6d0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../kevinrob/guzzle-cache-middleware', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'league/flysystem' => array( 'pretty_version' => '1.1.10', 'version' => '1.1.10.0', @@ -65,18 +74,18 @@ 'dev_requirement' => false, ), 'league/mime-type-detection' => array( - 'pretty_version' => '1.11.0', - 'version' => '1.11.0.0', - 'reference' => 'ff6248ea87a9f116e78edd6002e39e5128a0d4dd', + 'pretty_version' => '1.12.0', + 'version' => '1.12.0.0', + 'reference' => 'c7f2872fb273bf493811473dafc88d60ae829f48', 'type' => 'library', 'install_path' => __DIR__ . '/../league/mime-type-detection', 'aliases' => array(), 'dev_requirement' => false, ), 'php-curl-class/php-curl-class' => array( - 'pretty_version' => '9.14.3', - 'version' => '9.14.3.0', - 'reference' => '5d87676a3a7f83dd33d65f3c8d97f36679305193', + 'pretty_version' => '9.19.2', + 'version' => '9.19.2.0', + 'reference' => 'c41efeb4ea2dc3cf8f90f8f967b0fcf45a41e294', 'type' => 'library', 'install_path' => __DIR__ . '/../php-curl-class/php-curl-class', 'aliases' => array(), @@ -91,6 +100,12 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'psr/cache-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0|2.0', + ), + ), 'psr/container' => array( 'pretty_version' => '1.1.1', 'version' => '1.1.1.0', @@ -133,6 +148,12 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'psr/simple-cache-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0|2.0', + ), + ), 'ralouphie/getallheaders' => array( 'pretty_version' => '3.0.3', 'version' => '3.0.3.0', @@ -142,50 +163,101 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/cache' => array( + 'pretty_version' => 'v5.4.46', + 'version' => '5.4.46.0', + 'reference' => '0fe08ee32cec2748fbfea10c52d3ee02049e0f6b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/cache', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/cache-contracts' => array( + 'pretty_version' => 'v2.5.4', + 'version' => '2.5.4.0', + 'reference' => '517c3a3619dadfa6952c4651767fcadffb4df65e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/cache-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/cache-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0|2.0', + ), + ), + 'symfony/deprecation-contracts' => array( + 'pretty_version' => 'v2.5.4', + 'version' => '2.5.4.0', + 'reference' => '605389f2a7e5625f273b53960dc46aeaf9c62918', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', + '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.31.0', + 'version' => '1.31.0.0', + 'reference' => 'c36586dcf89a12315939e00ec9b4474adcb1d773', '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.31.0', + 'version' => '1.31.0.0', + 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', '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.31.0', + 'version' => '1.31.0.0', + 'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/polyfill-php72' => array( - 'pretty_version' => 'v1.27.0', - 'version' => '1.27.0.0', - 'reference' => '869329b1e9894268a8a61dabb69153029b7a8c97', + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'reference' => 'fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce', + 'type' => 'metapackage', + 'install_path' => NULL, + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'symfony/polyfill-php73' => array( + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'reference' => '0f68c03565dcaaf25a890667542e8bd75fe7e5bb', 'type' => 'library', - 'install_path' => __DIR__ . '/../symfony/polyfill-php72', + '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.31.0', + 'version' => '1.31.0.0', + 'reference' => '60328e362d4c2c802a54fcbf04f9d3fb892b4cf8', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), - 'dev_requirement' => true, + 'dev_requirement' => false, + ), + 'symfony/service-contracts' => array( + 'pretty_version' => 'v2.5.4', + 'version' => '2.5.4.0', + 'reference' => 'f37b419f7aea2e9abf10abd261832cace12e3300', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/service-contracts', + 'aliases' => array(), + 'dev_requirement' => false, ), 'symfony/var-dumper' => array( 'pretty_version' => 'v4.4.47', @@ -196,6 +268,15 @@ 'aliases' => array(), 'dev_requirement' => true, ), + 'symfony/var-exporter' => array( + 'pretty_version' => 'v5.4.45', + 'version' => '5.4.45.0', + 'reference' => '862700068db0ddfd8c5b850671e029a90246ec75', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/var-exporter', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'topthink/framework' => array( 'pretty_version' => 'v6.1.5', 'version' => '6.1.5.0', @@ -224,18 +305,18 @@ 'dev_requirement' => false, ), 'topthink/think-helper' => array( - 'pretty_version' => 'v3.1.6', - 'version' => '3.1.6.0', - 'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff', + 'pretty_version' => 'v3.1.11', + 'version' => '3.1.11.0', + 'reference' => '1d6ada9b9f3130046bf6922fe1bd159c8d88a33c', 'type' => 'library', 'install_path' => __DIR__ . '/../topthink/think-helper', 'aliases' => array(), 'dev_requirement' => false, ), 'topthink/think-orm' => array( - 'pretty_version' => 'v2.0.60', - 'version' => '2.0.60.0', - 'reference' => '8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46', + 'pretty_version' => 'v2.0.62', + 'version' => '2.0.62.0', + 'reference' => 'e53bfea572a133039ad687077120de5521af617f', 'type' => 'library', 'install_path' => __DIR__ . '/../topthink/think-orm', 'aliases' => array(), diff --git a/vendor/guzzlehttp/promises/CHANGELOG.md b/vendor/guzzlehttp/promises/CHANGELOG.md index 253282e..2e1a2f3 100644 --- a/vendor/guzzlehttp/promises/CHANGELOG.md +++ b/vendor/guzzlehttp/promises/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 1.5.3 - 2023-05-21 + +### Changed + +- Removed remaining usage of deprecated functions + ## 1.5.2 - 2022-08-07 ### Changed diff --git a/vendor/guzzlehttp/promises/composer.json b/vendor/guzzlehttp/promises/composer.json index c959fb3..966e3e3 100644 --- a/vendor/guzzlehttp/promises/composer.json +++ b/vendor/guzzlehttp/promises/composer.json @@ -46,11 +46,6 @@ "test": "vendor/bin/simple-phpunit", "test-ci": "vendor/bin/simple-phpunit --coverage-text" }, - "extra": { - "branch-alias": { - "dev-master": "1.5-dev" - } - }, "config": { "preferred-install": "dist", "sort-packages": true diff --git a/vendor/guzzlehttp/promises/src/Each.php b/vendor/guzzlehttp/promises/src/Each.php index 1dda354..ff8efd7 100644 --- a/vendor/guzzlehttp/promises/src/Each.php +++ b/vendor/guzzlehttp/promises/src/Each.php @@ -78,7 +78,7 @@ final class Each $concurrency, callable $onFulfilled = null ) { - return each_limit( + return self::ofLimit( $iterable, $concurrency, $onFulfilled, diff --git a/vendor/guzzlehttp/promises/src/Utils.php b/vendor/guzzlehttp/promises/src/Utils.php index 8647126..e376188 100644 --- a/vendor/guzzlehttp/promises/src/Utils.php +++ b/vendor/guzzlehttp/promises/src/Utils.php @@ -107,7 +107,7 @@ final class Utils { $results = []; foreach ($promises as $key => $promise) { - $results[$key] = inspect($promise); + $results[$key] = self::inspect($promise); } return $results; diff --git a/vendor/guzzlehttp/psr7/.github/workflows/ci.yml b/vendor/guzzlehttp/psr7/.github/workflows/ci.yml index eda7dce..0850470 100644 --- a/vendor/guzzlehttp/psr7/.github/workflows/ci.yml +++ b/vendor/guzzlehttp/psr7/.github/workflows/ci.yml @@ -6,7 +6,7 @@ on: jobs: build: name: Build - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: max-parallel: 10 matrix: @@ -21,11 +21,7 @@ jobs: extensions: mbstring - name: Checkout code - uses: actions/checkout@v2 - - - name: Mimic PHP 8.0 - run: composer config platform.php 8.0.999 - if: matrix.php > 8 + uses: actions/checkout@v3 - name: Install dependencies run: composer update --no-interaction --no-progress diff --git a/vendor/guzzlehttp/psr7/.github/workflows/integration.yml b/vendor/guzzlehttp/psr7/.github/workflows/integration.yml index 3c31f9e..a55a256 100644 --- a/vendor/guzzlehttp/psr7/.github/workflows/integration.yml +++ b/vendor/guzzlehttp/psr7/.github/workflows/integration.yml @@ -4,14 +4,13 @@ on: pull_request: jobs: - build: name: Test - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: max-parallel: 10 matrix: - php: ['7.2', '7.3', '7.4', '8.0'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1'] steps: - name: Set up PHP @@ -21,7 +20,7 @@ jobs: coverage: none - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Download dependencies uses: ramsey/composer-install@v1 diff --git a/vendor/guzzlehttp/psr7/.github/workflows/static.yml b/vendor/guzzlehttp/psr7/.github/workflows/static.yml index ab4d68b..f00351b 100644 --- a/vendor/guzzlehttp/psr7/.github/workflows/static.yml +++ b/vendor/guzzlehttp/psr7/.github/workflows/static.yml @@ -6,11 +6,11 @@ on: jobs: php-cs-fixer: name: PHP-CS-Fixer - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/vendor/guzzlehttp/psr7/CHANGELOG.md b/vendor/guzzlehttp/psr7/CHANGELOG.md index b4fdf3c..9b2b65c 100644 --- a/vendor/guzzlehttp/psr7/CHANGELOG.md +++ b/vendor/guzzlehttp/psr7/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 1.9.1 - 2023-04-17 + +### Fixed + +- Fixed header validation issue + ## 1.9.0 - 2022-06-20 ### Added diff --git a/vendor/guzzlehttp/psr7/composer.json b/vendor/guzzlehttp/psr7/composer.json index 0e36920..2607f22 100644 --- a/vendor/guzzlehttp/psr7/composer.json +++ b/vendor/guzzlehttp/psr7/composer.json @@ -61,11 +61,6 @@ "GuzzleHttp\\Tests\\Psr7\\": "tests/" } }, - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - }, "config": { "preferred-install": "dist", "sort-packages": true, diff --git a/vendor/guzzlehttp/psr7/src/MessageTrait.php b/vendor/guzzlehttp/psr7/src/MessageTrait.php index 0ac8663..0bbd63e 100644 --- a/vendor/guzzlehttp/psr7/src/MessageTrait.php +++ b/vendor/guzzlehttp/psr7/src/MessageTrait.php @@ -226,12 +226,9 @@ trait MessageTrait throw new \InvalidArgumentException('Header name can not be empty.'); } - if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $header)) { + if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) { throw new \InvalidArgumentException( - sprintf( - '"%s" is not valid header name', - $header - ) + sprintf('"%s" is not valid header name.', $header) ); } } @@ -263,8 +260,10 @@ trait MessageTrait // Clients must not send a request with line folding and a server sending folded headers is // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting // folding is not likely to break any legitimate use case. - if (! preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/', $value)) { - throw new \InvalidArgumentException(sprintf('"%s" is not valid header value', $value)); + if (! preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D', $value)) { + throw new \InvalidArgumentException( + sprintf('"%s" is not valid header value.', $value) + ); } } } diff --git a/vendor/kevinrob/guzzle-cache-middleware/LICENSE b/vendor/kevinrob/guzzle-cache-middleware/LICENSE new file mode 100644 index 0000000..f564577 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Kevin Robatel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/kevinrob/guzzle-cache-middleware/README.md b/vendor/kevinrob/guzzle-cache-middleware/README.md new file mode 100644 index 0000000..5b205e4 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/README.md @@ -0,0 +1,309 @@ +# guzzle-cache-middleware + +[](https://packagist.org/packages/kevinrob/guzzle-cache-middleware) [](https://packagist.org/packages/kevinrob/guzzle-cache-middleware) [](https://packagist.org/packages/kevinrob/guzzle-cache-middleware) + [](https://scrutinizer-ci.com/g/Kevinrob/guzzle-cache-middleware/?branch=master) [](https://scrutinizer-ci.com/g/Kevinrob/guzzle-cache-middleware/?branch=master) + + +A HTTP Cache for [Guzzle](https://github.com/guzzle/guzzle) 6+. It's a simple Middleware to be added in the HandlerStack. + +## Goals +- RFC 7234 compliance +- Performance and transparency +- Assured compatibility with PSR-7 + +## Built-in storage interfaces +- [Doctrine cache](https://github.com/doctrine/cache) +- [Laravel cache](https://laravel.com/docs/5.2/cache) +- [Flysystem](https://github.com/thephpleague/flysystem) +- [PSR6](https://github.com/php-fig/cache) +- [WordPress Object Cache](https://codex.wordpress.org/Class_Reference/WP_Object_Cache) + +## Installation + +`composer require kevinrob/guzzle-cache-middleware` + +or add it the your `composer.json` and run `composer update kevinrob/guzzle-cache-middleware`. + +# Why? +Performance. It's very common to do some HTTP calls to an API for rendering a page and it takes times to do it. + +# How? +With a simple Middleware added at the top of the `HandlerStack` of Guzzle. + +```php +use GuzzleHttp\Client; +use GuzzleHttp\HandlerStack; +use Kevinrob\GuzzleCache\CacheMiddleware; + +// Create default HandlerStack +$stack = HandlerStack::create(); + +// Add this middleware to the top with `push` +$stack->push(new CacheMiddleware(), 'cache'); + +// Initialize the client with the handler option +$client = new Client(['handler' => $stack]); +``` + +# Examples + +## Doctrine/Cache +You can use a cache from `Doctrine/Cache`: +```php +[...] +use Doctrine\Common\Cache\FilesystemCache; +use Kevinrob\GuzzleCache\Strategy\PrivateCacheStrategy; +use Kevinrob\GuzzleCache\Storage\DoctrineCacheStorage; + +[...] +$stack->push( + new CacheMiddleware( + new PrivateCacheStrategy( + new DoctrineCacheStorage( + new FilesystemCache('/tmp/') + ) + ) + ), + 'cache' +); +``` + +You can use `ChainCache` for using multiple `CacheProvider` instances. With that provider, you have to sort the different caches from the faster to the slower. Like that, you can have a very fast cache. +```php +[...] +use Doctrine\Common\Cache\ChainCache; +use Doctrine\Common\Cache\ArrayCache; +use Doctrine\Common\Cache\FilesystemCache; +use Kevinrob\GuzzleCache\Strategy\PrivateCacheStrategy; +use Kevinrob\GuzzleCache\Storage\DoctrineCacheStorage; + +[...] +$stack->push(new CacheMiddleware( + new PrivateCacheStrategy( + new DoctrineCacheStorage( + new ChainCache([ + new ArrayCache(), + new FilesystemCache('/tmp/'), + ]) + ) + ) +), 'cache'); +``` + +## Laravel cache +You can use a cache with Laravel, e.g. Redis, Memcache etc.: +```php +[...] +use Illuminate\Support\Facades\Cache; +use Kevinrob\GuzzleCache\Strategy\PrivateCacheStrategy; +use Kevinrob\GuzzleCache\Storage\LaravelCacheStorage; + +[...] + +$stack->push( + new CacheMiddleware( + new PrivateCacheStrategy( + new LaravelCacheStorage( + Cache::store('redis') + ) + ) + ), + 'cache' +); +``` + +## Flysystem +```php +[...] +use League\Flysystem\Adapter\Local; +use Kevinrob\GuzzleCache\Strategy\PrivateCacheStrategy; +use Kevinrob\GuzzleCache\Storage\FlysystemStorage; + +[...] + +$stack->push( + new CacheMiddleware( + new PrivateCacheStrategy( + new FlysystemStorage( + new Local('/path/to/cache') + ) + ) + ), + 'cache' +); +``` + +## WordPress Object Cache +```php +[...] +use Kevinrob\GuzzleCache\Strategy\PrivateCacheStrategy; +use Kevinrob\GuzzleCache\Storage\WordPressObjectCacheStorage; + +[...] + +$stack->push( + new CacheMiddleware( + new PrivateCacheStrategy( + new WordPressObjectCacheStorage() + ) + ), + 'cache' +); +``` + +## Public and shared +It's possible to add a public shared cache to the stack: +```php +[...] +use Doctrine\Common\Cache\FilesystemCache; +use Doctrine\Common\Cache\PredisCache; +use Kevinrob\GuzzleCache\Strategy\PrivateCacheStrategy; +use Kevinrob\GuzzleCache\Strategy\PublicCacheStrategy; +use Kevinrob\GuzzleCache\Storage\DoctrineCacheStorage; + +[...] +// Private caching +$stack->push( + new CacheMiddleware( + new PrivateCacheStrategy( + new DoctrineCacheStorage( + new FilesystemCache('/tmp/') + ) + ) + ), + 'private-cache' +); + +// Public caching +$stack->push( + new CacheMiddleware( + new PublicCacheStrategy( + new DoctrineCacheStorage( + new PredisCache( + new Predis\Client('tcp://10.0.0.1:6379') + ) + ) + ) + ), + 'shared-cache' +); +``` + +## Greedy caching +In some cases servers might send insufficient or no caching headers at all. +Using the greedy caching strategy allows defining an expiry TTL on your own while +disregarding any possibly present caching headers: +```php +[...] +use Kevinrob\GuzzleCache\KeyValueHttpHeader; +use Kevinrob\GuzzleCache\Strategy\GreedyCacheStrategy; +use Kevinrob\GuzzleCache\Storage\DoctrineCacheStorage; +use Doctrine\Common\Cache\FilesystemCache; + +[...] +// Greedy caching +$stack->push( + new CacheMiddleware( + new GreedyCacheStrategy( + new DoctrineCacheStorage( + new FilesystemCache('/tmp/') + ), + 1800, // the TTL in seconds + new KeyValueHttpHeader(['Authorization']) // Optional - specify the headers that can change the cache key + ) + ), + 'greedy-cache' +); +``` + +## Delegate caching +Because your client may call different apps, on different domains, you may need to define which strategy is suitable to your requests. + +To solve this, all you have to do is to define a default cache strategy, and override it by implementing your own Request Matchers. + +Here's an example: +```php +namespace App\RequestMatcher; + +use Kevinrob\GuzzleCache\Strategy\Delegate\RequestMatcherInterface; +use Psr\Http\Message\RequestInterface; + +class ExampleOrgRequestMatcher implements RequestMatcherInterface +{ + + /** + * @inheritDoc + */ + public function matches(RequestInterface $request) + { + return false !== strpos($request->getUri()->getHost(), 'example.org'); + } +} +``` + +```php +namespace App\RequestMatcher; + +use Kevinrob\GuzzleCache\Strategy\Delegate\RequestMatcherInterface; +use Psr\Http\Message\RequestInterface; + +class TwitterRequestMatcher implements RequestMatcherInterface +{ + + /** + * @inheritDoc + */ + public function matches(RequestInterface $request) + { + return false !== strpos($request->getUri()->getHost(), 'twitter.com'); + } +} +``` + +```php +require_once __DIR__ . '/vendor/autoload.php'; + +use App\RequestMatcher\ExampleOrgRequestMatcher; +use App\RequestMatcher\TwitterRequestMatcher; +use GuzzleHttp\Client; +use GuzzleHttp\HandlerStack; +use Kevinrob\GuzzleCache\CacheMiddleware; +use Kevinrob\GuzzleCache\Strategy; + +$strategy = new Strategy\Delegate\DelegatingCacheStrategy($defaultStrategy = new Strategy\NullCacheStrategy()); +$strategy->registerRequestMatcher(new ExampleOrgRequestMatcher(), new Strategy\PublicCacheStrategy()); +$strategy->registerRequestMatcher(new TwitterRequestMatcher(), new Strategy\PrivateCacheStrategy()); + +$stack = HandlerStack::create(); +$stack->push(new CacheMiddleware($strategy)); +$guzzle = new Client(['handler' => $stack]); +``` + +With this example: +* All requests to `example.org` will be handled by `PublicCacheStrategy` +* All requests to `twitter.com` will be handled by `PrivateCacheStrategy` +* All other requests won't be cached. + +## Drupal +See [Guzzle Cache](https://www.drupal.org/project/guzzle_cache) module. + +# Links that talk about the project +- [Speeding Up APIs/Apps/Smart Toasters with HTTP Response Caching](https://apisyouwonthate.com/blog/speeding-up-apis-apps-smart-toasters-with-http-response-caching) +- [Caching HTTP-Requests with Guzzle 6 and PSR-6](http://a.kabachnik.info/caching-http-requests-with-guzzle-6-and-psr-6.html) + +# Development + +## Docker quick start + +### Initialization +```bash +make init +``` +### Running test +```bash +make test +``` +### Entering container shell +```bash +make shell +``` diff --git a/vendor/kevinrob/guzzle-cache-middleware/composer.json b/vendor/kevinrob/guzzle-cache-middleware/composer.json new file mode 100644 index 0000000..9b787e4 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/composer.json @@ -0,0 +1,58 @@ +{ + "name": "kevinrob/guzzle-cache-middleware", + "type": "library", + "description": "A HTTP/1.1 Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack. (RFC 7234)", + "keywords": ["guzzle", "guzzle6", "cache", "http", "http 1.1", "psr6", "psr7", "handler", "middleware", "cache-control", "rfc7234", "performance", "php", "promise", "expiration", "validation", "Etag", "flysystem", "doctrine"], + "homepage": "https://github.com/Kevinrob/guzzle-cache-middleware", + "license": "MIT", + "authors": [ + { + "name": "Kevin Robatel", + "email": "kevinrob2@gmail.com", + "homepage": "https://github.com/Kevinrob" + } + ], + "require": { + "php": ">=7.2.0", + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "guzzlehttp/promises": "^1.4 || ^2.0", + "guzzlehttp/psr7": "^1.7.0 || ^2.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.15 || ^9.5", + "doctrine/cache": "^1.10", + "league/flysystem": "^2.5", + "psr/cache": "^1.0", + "cache/array-adapter": "^0.4 || ^0.5 || ^1.0", + "illuminate/cache": "^5.0", + "cache/simple-cache-bridge": "^0.1 || ^1.0", + "symfony/phpunit-bridge": "^4.4 || ^5.0", + "symfony/cache": "^4.4 || ^5.0" + }, + "autoload": { + "psr-4": { + "Kevinrob\\GuzzleCache\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Kevinrob\\GuzzleCache\\Tests\\": "tests/" + } + }, + "suggest": { + "guzzlehttp/guzzle": "For using this library. It was created for Guzzle6 (but you can use it with any PSR-7 HTTP client).", + "doctrine/cache": "This library has a lot of ready-to-use cache storage (to be used with Kevinrob\\GuzzleCache\\Storage\\DoctrineCacheStorage). Use only versions >=1.4.0 < 2.0.0", + "league/flysystem": "To be used with Kevinrob\\GuzzleCache\\Storage\\FlysystemStorage", + "psr/cache": "To be used with Kevinrob\\GuzzleCache\\Storage\\Psr6CacheStorage", + "psr/simple-cache": "To be used with Kevinrob\\GuzzleCache\\Storage\\Psr16CacheStorage", + "laravel/framework": "To be used with Kevinrob\\GuzzleCache\\Storage\\LaravelCacheStorage" + }, + "scripts": { + "test": "vendor/bin/phpunit" + }, + "config": { + "allow-plugins": { + "kylekatarnls/update-helper": true + } + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/BodyStore.php b/vendor/kevinrob/guzzle-cache-middleware/src/BodyStore.php new file mode 100644 index 0000000..0ff38a1 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/BodyStore.php @@ -0,0 +1,46 @@ +body = $body; + $this->toRead = mb_strlen($this->body); + } + + /** + * @param int $length + * @return false|string + */ + public function __invoke(int $length) + { + if ($this->toRead <= 0) { + return false; + } + + $length = min($length, $this->toRead); + + $body = mb_substr( + $this->body, + $this->read, + $length + ); + $this->toRead -= $length; + $this->read += $length; + return $body; + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/CacheEntry.php b/vendor/kevinrob/guzzle-cache-middleware/src/CacheEntry.php new file mode 100644 index 0000000..4d2a965 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/CacheEntry.php @@ -0,0 +1,333 @@ +dateCreated = new \DateTime(); + + $this->request = $request; + $this->response = $response; + $this->staleAt = $staleAt; + + $values = new KeyValueHttpHeader($response->getHeader('Cache-Control')); + + if ($staleIfErrorTo === null && $values->has('stale-if-error')) { + $this->staleIfErrorTo = (new \DateTime( + '@'.($this->staleAt->getTimestamp() + (int) $values->get('stale-if-error')) + )); + } else { + $this->staleIfErrorTo = $staleIfErrorTo; + } + + if ($staleWhileRevalidateTo === null && $values->has('stale-while-revalidate')) { + $this->staleWhileRevalidateTo = new \DateTime( + '@'.($this->staleAt->getTimestamp() + (int) $values->get('stale-while-revalidate')) + ); + } else { + $this->staleWhileRevalidateTo = $staleWhileRevalidateTo; + } + } + + /** + * @return ResponseInterface + */ + public function getResponse() + { + return $this->response + ->withHeader('Age', $this->getAge()); + } + + /** + * @return ResponseInterface + */ + public function getOriginalResponse() + { + return $this->response; + } + + /** + * @return RequestInterface + */ + public function getOriginalRequest() + { + return $this->request; + } + + /** + * @param RequestInterface $request + * @return bool + */ + public function isVaryEquals(RequestInterface $request) + { + if ($this->response->hasHeader('Vary')) { + if ($this->request === null) { + return false; + } + + foreach ($this->getVaryHeaders() as $key => $value) { + if (!$this->request->hasHeader($key) + && !$request->hasHeader($key) + ) { + // Absent from both + continue; + } elseif ($this->request->getHeaderLine($key) + == $request->getHeaderLine($key) + ) { + // Same content + continue; + } + + return false; + } + } + + return true; + } + + /** + * Get the vary headers that should be honoured by the cache. + * + * @return KeyValueHttpHeader + */ + public function getVaryHeaders() + { + return new KeyValueHttpHeader($this->response->getHeader('Vary')); + } + + /** + * @return \DateTime + */ + public function getStaleAt() + { + return $this->staleAt; + } + + /** + * @return bool + */ + public function isFresh() + { + return !$this->isStale(); + } + + /** + * @return bool + */ + public function isStale() + { + return $this->getStaleAge() > 0; + } + + /** + * @return int positive value equal staled + */ + public function getStaleAge() + { + // This object is immutable + if ($this->timestampStale === null) { + $this->timestampStale = $this->staleAt->getTimestamp(); + } + + return time() - $this->timestampStale; + } + + /** + * @return bool + */ + public function serveStaleIfError() + { + return $this->staleIfErrorTo !== null + && $this->staleIfErrorTo->getTimestamp() >= (new \DateTime())->getTimestamp(); + } + + /** + * @return bool + */ + public function staleWhileValidate() + { + return $this->staleWhileRevalidateTo !== null + && $this->staleWhileRevalidateTo->getTimestamp() >= (new \DateTime())->getTimestamp(); + } + + /** + * @return bool + */ + public function hasValidationInformation() + { + return $this->response->hasHeader('Etag') || $this->response->hasHeader('Last-Modified'); + } + + /** + * Time in seconds how long the entry should be kept in the cache + * + * This will not give the time (in seconds) that the response will still be fresh for + * from the HTTP point of view, but an upper bound on how long it is necessary and + * reasonable to keep the response in a cache (to re-use it or re-validate it later on). + * + * @return int TTL in seconds (0 = infinite) + */ + public function getTTL() + { + if ($this->hasValidationInformation()) { + // No TTL if we have a way to re-validate the cache + return 0; + } + + $ttl = 0; + + // Keep it when stale if error + if ($this->staleIfErrorTo !== null) { + $ttl = max($ttl, $this->staleIfErrorTo->getTimestamp() - time()); + } + + // Keep it when stale-while-revalidate + if ($this->staleWhileRevalidateTo !== null) { + $ttl = max($ttl, $this->staleWhileRevalidateTo->getTimestamp() - time()); + } + + // Keep it until it become stale + $ttl = max($ttl, $this->staleAt->getTimestamp() - time()); + + // Don't return 0, it's reserved for infinite TTL + return $ttl !== 0 ? (int) $ttl : -1; + } + + /** + * @return int Age in seconds + */ + public function getAge() + { + return time() - $this->dateCreated->getTimestamp(); + } + + public function __serialize(): array + { + return [ + 'request' => self::toSerializeableMessage($this->request), + 'response' => $this->response !== null ? self::toSerializeableMessage($this->response) : null, + 'staleAt' => $this->staleAt, + 'staleIfErrorTo' => $this->staleIfErrorTo, + 'staleWhileRevalidateTo' => $this->staleWhileRevalidateTo, + 'dateCreated' => $this->dateCreated, + 'timestampStale' => $this->timestampStale, + ]; + } + + public function __unserialize(array $data): void + { + $prefix = ''; + if (isset($data["\0*\0request"])) { + // We are unserializing a cache entry which was serialized with a version < 4.1.1 + $prefix = "\0*\0"; + } + $this->request = self::restoreStreamBody($data[$prefix.'request']); + $this->response = $data[$prefix.'response'] !== null ? self::restoreStreamBody($data[$prefix.'response']) : null; + $this->staleAt = $data[$prefix.'staleAt']; + $this->staleIfErrorTo = $data[$prefix.'staleIfErrorTo']; + $this->staleWhileRevalidateTo = $data[$prefix.'staleWhileRevalidateTo']; + $this->dateCreated = $data[$prefix.'dateCreated']; + $this->timestampStale = $data[$prefix.'timestampStale']; + } + + /** + * Stream/Resource can't be serialized... So we copy the content into an implementation of `Psr\Http\Message\StreamInterface` + * + * @template T of MessageInterface + * + * @param T $message + * @return T + */ + private static function toSerializeableMessage(MessageInterface $message): MessageInterface + { + $bodyString = (string)$message->getBody(); + + return $message->withBody( + new PumpStream( + new BodyStore($bodyString), + [ + 'size' => mb_strlen($bodyString), + ] + ) + ); + } + + /** + * @template T of MessageInterface + * + * @param T $message + * @return T + */ + private static function restoreStreamBody(MessageInterface $message): MessageInterface + { + return $message->withBody( + \GuzzleHttp\Psr7\Utils::streamFor((string) $message->getBody()) + ); + } + + public function serialize() + { + return serialize($this->__serialize()); + } + + public function unserialize($data) + { + $this->__unserialize(unserialize($data)); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/CacheMiddleware.php b/vendor/kevinrob/guzzle-cache-middleware/src/CacheMiddleware.php new file mode 100644 index 0000000..ee11520 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/CacheMiddleware.php @@ -0,0 +1,400 @@ + true]; + + /** + * List of safe methods + * + * https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1 + * + * @var array + */ + protected $safeMethods = ['GET' => true, 'HEAD' => true, 'OPTIONS' => true, 'TRACE' => true]; + + /** + * @param CacheStrategyInterface|null $cacheStrategy + */ + public function __construct(CacheStrategyInterface $cacheStrategy = null) + { + $this->cacheStorage = $cacheStrategy !== null ? $cacheStrategy : new PrivateCacheStrategy(); + + register_shutdown_function([$this, 'purgeReValidation']); + } + + /** + * @param Client $client + */ + public function setClient(Client $client) + { + $this->client = $client; + } + + /** + * @param CacheStrategyInterface $cacheStorage + */ + public function setCacheStorage(CacheStrategyInterface $cacheStorage) + { + $this->cacheStorage = $cacheStorage; + } + + /** + * @return CacheStrategyInterface + */ + public function getCacheStorage() + { + return $this->cacheStorage; + } + + /** + * @param array $methods + */ + public function setHttpMethods(array $methods) + { + $this->httpMethods = $methods; + } + + public function getHttpMethods() + { + return $this->httpMethods; + } + + /** + * Will be called at the end of the script. + */ + public function purgeReValidation() + { + \GuzzleHttp\Promise\Utils::inspectAll($this->waitingRevalidate); + } + + /** + * @param callable $handler + * + * @return callable + */ + public function __invoke(callable $handler) + { + return function (RequestInterface $request, array $options) use (&$handler) { + if (!isset($this->httpMethods[strtoupper($request->getMethod())])) { + // No caching for this method allowed + + return $handler($request, $options)->then( + function (ResponseInterface $response) use ($request) { + if (!isset($this->safeMethods[$request->getMethod()])) { + // Invalidate cache after a call of non-safe method on the same URI + $response = $this->invalidateCache($request, $response); + } + + return $response->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_MISS); + } + ); + } + + if ($request->hasHeader(self::HEADER_RE_VALIDATION)) { + // It's a re-validation request, so bypass the cache! + return $handler($request->withoutHeader(self::HEADER_RE_VALIDATION), $options); + } + + // Retrieve information from request (Cache-Control) + $reqCacheControl = new KeyValueHttpHeader($request->getHeader('Cache-Control')); + $onlyFromCache = $reqCacheControl->has('only-if-cached'); + $staleResponse = $reqCacheControl->has('max-stale') + && $reqCacheControl->get('max-stale') === ''; + $maxStaleCache = $reqCacheControl->get('max-stale', null); + $minFreshCache = $reqCacheControl->get('min-fresh', null); + + // If cache => return new FulfilledPromise(...) with response + $cacheEntry = $this->cacheStorage->fetch($request); + if ($cacheEntry instanceof CacheEntry) { + $body = $cacheEntry->getResponse()->getBody(); + if ($body->tell() > 0) { + $body->rewind(); + } + + if ($cacheEntry->isFresh() + && ($minFreshCache === null || $cacheEntry->getStaleAge() + (int)$minFreshCache <= 0) + ) { + // Cache HIT! + return new FulfilledPromise( + $cacheEntry->getResponse()->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_HIT) + ); + } elseif ($staleResponse + || ($maxStaleCache !== null && $cacheEntry->getStaleAge() <= $maxStaleCache) + ) { + // Staled cache! + return new FulfilledPromise( + $cacheEntry->getResponse()->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_HIT) + ); + } elseif ($cacheEntry->hasValidationInformation() && !$onlyFromCache) { + // Re-validation header + $request = static::getRequestWithReValidationHeader($request, $cacheEntry); + + if ($cacheEntry->staleWhileValidate()) { + static::addReValidationRequest($request, $this->cacheStorage, $cacheEntry); + + return new FulfilledPromise( + $cacheEntry->getResponse() + ->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_STALE) + ); + } + } + } else { + $cacheEntry = null; + } + + if ($cacheEntry === null && $onlyFromCache) { + // Explicit asking of a cached response => 504 + return new FulfilledPromise( + new Response(504) + ); + } + + /** @var Promise $promise */ + $promise = $handler($request, $options); + + return $promise->then( + function (ResponseInterface $response) use ($request, $cacheEntry) { + // Check if error and looking for a staled content + if ($response->getStatusCode() >= 500) { + $responseStale = static::getStaleResponse($cacheEntry); + if ($responseStale instanceof ResponseInterface) { + return $responseStale; + } + } + + $update = false; + + if ($response->getStatusCode() == 304 && $cacheEntry instanceof CacheEntry) { + // Not modified => cache entry is re-validate + /** @var ResponseInterface $response */ + $response = $response + ->withStatus($cacheEntry->getResponse()->getStatusCode()) + ->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_HIT); + $response = $response->withBody($cacheEntry->getResponse()->getBody()); + + // Merge headers of the "304 Not Modified" and the cache entry + /** + * @var string $headerName + * @var string[] $headerValue + */ + foreach ($cacheEntry->getOriginalResponse()->getHeaders() as $headerName => $headerValue) { + if (!$response->hasHeader($headerName) && $headerName !== self::HEADER_CACHE_INFO) { + $response = $response->withHeader($headerName, $headerValue); + } + } + + $update = true; + } else { + $response = $response->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_MISS); + } + + return static::addToCache($this->cacheStorage, $request, $response, $update); + }, + function ($reason) use ($cacheEntry) { + $response = static::getStaleResponse($cacheEntry); + if ($response instanceof ResponseInterface) { + return $response; + } + + return new RejectedPromise($reason); + } + ); + }; + } + + /** + * @param CacheStrategyInterface $cache + * @param RequestInterface $request + * @param ResponseInterface $response + * @param bool $update cache + * @return ResponseInterface + */ + protected static function addToCache( + CacheStrategyInterface $cache, + RequestInterface $request, + ResponseInterface $response, + $update = false + ) { + $body = $response->getBody(); + + // If the body is not seekable, we have to replace it by a seekable one + if (!$body->isSeekable()) { + $response = $response->withBody( + \GuzzleHttp\Psr7\Utils::streamFor($body->getContents()) + ); + } + + if ($update) { + $cache->update($request, $response); + } else { + $cache->cache($request, $response); + } + + // always rewind back to the start otherwise other middlewares may get empty "content" + if ($body->isSeekable()) { + $response->getBody()->rewind(); + } + + return $response; + } + + /** + * @param RequestInterface $request + * @param CacheStrategyInterface $cacheStorage + * @param CacheEntry $cacheEntry + * + * @return bool if added + */ + protected function addReValidationRequest( + RequestInterface $request, + CacheStrategyInterface &$cacheStorage, + CacheEntry $cacheEntry + ) { + // Add the promise for revalidate + if ($this->client !== null) { + /** @var RequestInterface $request */ + $request = $request->withHeader(self::HEADER_RE_VALIDATION, '1'); + $this->waitingRevalidate[] = $this->client + ->sendAsync($request) + ->then(function (ResponseInterface $response) use ($request, &$cacheStorage, $cacheEntry) { + $update = false; + + if ($response->getStatusCode() == 304) { + // Not modified => cache entry is re-validate + /** @var ResponseInterface $response */ + $response = $response->withStatus($cacheEntry->getResponse()->getStatusCode()); + $response = $response->withBody($cacheEntry->getResponse()->getBody()); + + // Merge headers of the "304 Not Modified" and the cache entry + foreach ($cacheEntry->getResponse()->getHeaders() as $headerName => $headerValue) { + if (!$response->hasHeader($headerName)) { + $response = $response->withHeader($headerName, $headerValue); + } + } + + $update = true; + } + + static::addToCache($cacheStorage, $request, $response, $update); + }); + + return true; + } + + return false; + } + + /** + * @param CacheEntry|null $cacheEntry + * + * @return null|ResponseInterface + */ + protected static function getStaleResponse(CacheEntry $cacheEntry = null) + { + // Return staled cache entry if we can + if ($cacheEntry instanceof CacheEntry && $cacheEntry->serveStaleIfError()) { + return $cacheEntry->getResponse() + ->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_STALE); + } + + return; + } + + /** + * @param RequestInterface $request + * @param CacheEntry $cacheEntry + * + * @return RequestInterface + */ + protected static function getRequestWithReValidationHeader(RequestInterface $request, CacheEntry $cacheEntry) + { + if ($cacheEntry->getResponse()->hasHeader('Last-Modified')) { + $request = $request->withHeader( + 'If-Modified-Since', + $cacheEntry->getResponse()->getHeader('Last-Modified') + ); + } + if ($cacheEntry->getResponse()->hasHeader('Etag')) { + $request = $request->withHeader( + 'If-None-Match', + $cacheEntry->getResponse()->getHeader('Etag') + ); + } + + return $request; + } + + /** + * @param CacheStrategyInterface|null $cacheStorage + * + * @return CacheMiddleware the Middleware for Guzzle HandlerStack + * + * @deprecated Use constructor => `new CacheMiddleware()` + */ + public static function getMiddleware(CacheStrategyInterface $cacheStorage = null) + { + return new self($cacheStorage); + } + + /** + * @param RequestInterface $request + * + * @param ResponseInterface $response + * + * @return ResponseInterface + */ + private function invalidateCache(RequestInterface $request, ResponseInterface $response) + { + foreach (array_keys($this->httpMethods) as $method) { + $this->cacheStorage->delete($request->withMethod($method)); + } + + return $response->withHeader(self::HEADER_INVALIDATION, true); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/KeyValueHttpHeader.php b/vendor/kevinrob/guzzle-cache-middleware/src/KeyValueHttpHeader.php new file mode 100644 index 0000000..d931d1a --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/KeyValueHttpHeader.php @@ -0,0 +1,131 @@ +@\,;\:\\\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\\\]|\\\\.)*)\")))?/'; + + /** + * @var string[] + */ + protected $values = []; + + /** + * @param array $values + */ + public function __construct(array $values) + { + foreach ($values as $value) { + $matches = []; + if (preg_match_all(self::REGEX_SPLIT, $value, $matches, PREG_SET_ORDER)) { + foreach ($matches as $match) { + $val = ''; + if (count($match) == 3) { + $val = $match[2]; + } elseif (count($match) > 3) { + $val = $match[3]; + } + + $this->values[$match[1]] = $val; + } + } + } + } + + /** + * @param string $key + * + * @return bool + */ + public function has($key) + { + // For performance, we can use isset, + // but it will not match if value == 0 + return isset($this->values[$key]) || array_key_exists($key, $this->values); + } + + /** + * @param string $key + * @param string $default the value to return if don't exist + * @return string + */ + public function get($key, $default = '') + { + if ($this->has($key)) { + return $this->values[$key]; + } + + return $default; + } + + /** + * @return bool + */ + public function isEmpty() + { + return count($this->values) === 0; + } + + /** + * Return the current element + * @link http://php.net/manual/en/iterator.current.php + * @return mixed Can return any type. + * @since 5.0.0 + */ + #[\ReturnTypeWillChange] + public function current() + { + return current($this->values); + } + + /** + * Move forward to next element + * @link http://php.net/manual/en/iterator.next.php + * @return void Any returned value is ignored. + * @since 5.0.0 + */ + public function next(): void + { + next($this->values); + } + + /** + * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * @return mixed scalar on success, or null on failure. + * @since 5.0.0 + * + */ + #[\ReturnTypeWillChange] + public function key() + { + return key($this->values); + } + + /** + * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * @return boolean The return value will be casted to boolean and then evaluated. + * Returns true on success or false on failure. + * @since 5.0.0 + */ + public function valid(): bool + { + return key($this->values) !== null; + } + + /** + * Rewind the Iterator to the first element + * @link http://php.net/manual/en/iterator.rewind.php + * @return void Any returned value is ignored. + * @since 5.0.0 + */ + public function rewind(): void + { + reset($this->values); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Storage/CacheStorageInterface.php b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/CacheStorageInterface.php new file mode 100644 index 0000000..0ec9e1a --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/CacheStorageInterface.php @@ -0,0 +1,30 @@ +cache = $cache; + } + + /** + * {@inheritdoc} + */ + public function fetch($key) + { + try { + $cache = unserialize(gzuncompress($this->cache->fetch($key))); + if ($cache instanceof CacheEntry) { + return $cache; + } + } catch (\Exception $ignored) { + return; + } + + return; + } + + /** + * {@inheritdoc} + */ + public function save($key, CacheEntry $data) + { + try { + $lifeTime = $data->getTTL(); + if ($lifeTime >= 0) { + return $this->cache->save( + $key, + gzcompress(serialize($data)), + $lifeTime + ); + } + } catch (\Exception $ignored) { + // No fail if we can't save it the storage + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function delete($key) + { + try { + return $this->cache->delete($key); + } catch (\Exception $ignored) { + // Don't fail if we can't delete it + } + + return false; + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Storage/DoctrineCacheStorage.php b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/DoctrineCacheStorage.php new file mode 100644 index 0000000..9f5f160 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/DoctrineCacheStorage.php @@ -0,0 +1,74 @@ +cache = $cache; + } + + /** + * {@inheritdoc} + */ + public function fetch($key) + { + try { + $cache = unserialize($this->cache->fetch($key)); + if ($cache instanceof CacheEntry) { + return $cache; + } + } catch (\Exception $ignored) { + return; + } + + return; + } + + /** + * {@inheritdoc} + */ + public function save($key, CacheEntry $data) + { + try { + $lifeTime = $data->getTTL(); + if ($lifeTime >= 0) { + return $this->cache->save( + $key, + serialize($data), + $lifeTime + ); + } + } catch (\Exception $ignored) { + // No fail if we can't save it the storage + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function delete($key) + { + try { + return $this->cache->delete($key); + } catch (\Exception $ignored) { + // Don't fail if we can't delete it + } + + return false; + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Storage/FlysystemStorage.php b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/FlysystemStorage.php new file mode 100644 index 0000000..eecd6a9 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/FlysystemStorage.php @@ -0,0 +1,61 @@ +filesystem = new Filesystem($adapter); + } + + /** + * @inheritdoc + */ + public function fetch($key) + { + if ($this->filesystem->fileExists($key)) { + // The file exist, read it! + $data = @unserialize( + $this->filesystem->read($key) + ); + + if ($data instanceof CacheEntry) { + return $data; + } + } + + return; + } + + /** + * @inheritdoc + */ + public function save($key, CacheEntry $data) + { + $this->filesystem->write($key, serialize($data)); + } + + /** + * {@inheritdoc} + */ + public function delete($key) + { + try { + $this->filesystem->delete($key); + } catch (FilesystemException $ex) { + return true; + } + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Storage/LaravelCacheStorage.php b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/LaravelCacheStorage.php new file mode 100644 index 0000000..3e3416d --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/LaravelCacheStorage.php @@ -0,0 +1,84 @@ +cache = $cache; + } + + /** + * {@inheritdoc} + */ + public function fetch($key) + { + try { + $cache = unserialize($this->cache->get($key, '')); + if ($cache instanceof CacheEntry) { + return $cache; + } + } catch (\Exception $ignored) { + return; + } + + return; + } + + /** + * {@inheritdoc} + */ + public function save($key, CacheEntry $data) + { + try { + $lifeTime = $this->getLifeTime($data); + if ($lifeTime === 0) { + return $this->cache->forever( + $key, + serialize($data) + ); + } else if ($lifeTime > 0) { + return $this->cache->add( + $key, + serialize($data), + $lifeTime + ); + } + } catch (\Exception $ignored) { + // No fail if we can't save it the storage + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function delete($key) + { + return $this->cache->forget($key); + } + + protected function getLifeTime(CacheEntry $data) + { + $version = app()->version(); + if (preg_match('/^\d+(\.\d+)?(\.\d+)?/', $version) && version_compare($version, '5.8.0') < 0) { + // getTTL returns seconds, Laravel needs minutes before v5.8 + return $data->getTTL() / 60; + } + + return $data->getTTL(); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Storage/Psr16CacheStorage.php b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/Psr16CacheStorage.php new file mode 100644 index 0000000..fe97a25 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/Psr16CacheStorage.php @@ -0,0 +1,52 @@ +cache = $cache; + } + + /** + * {@inheritdoc} + */ + public function fetch($key) + { + $data = $this->cache->get($key); + if ($data instanceof CacheEntry) { + return $data; + } + + return null; + } + + /** + * {@inheritdoc} + */ + public function save($key, CacheEntry $data) + { + $ttl = $data->getTTL(); + if ($ttl === 0) { + return $this->cache->set($key, $data); + } + return $this->cache->set($key, $data, $data->getTTL()); + } + + /** + * {@inheritdoc} + */ + public function delete($key) + { + return $this->cache->delete($key); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Storage/Psr6CacheStorage.php b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/Psr6CacheStorage.php new file mode 100644 index 0000000..b1344ef --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/Psr6CacheStorage.php @@ -0,0 +1,92 @@ +cachePool = $cachePool; + } + + /** + * {@inheritdoc} + */ + public function fetch($key) + { + $item = $this->cachePool->getItem($key); + $this->lastItem = $item; + + $cache = $item->get(); + + if ($cache instanceof CacheEntry) { + return $cache; + } + + return null; + } + + /** + * {@inheritdoc} + */ + public function save($key, CacheEntry $data) + { + if ($this->lastItem && $this->lastItem->getKey() == $key) { + $item = $this->lastItem; + } else { + $item = $this->cachePool->getItem($key); + } + + $this->lastItem = null; + + $item->set($data); + + $ttl = $data->getTTL(); + if ($ttl === 0) { + // No expiration + $item->expiresAfter(null); + } else { + $item->expiresAfter($ttl); + } + + return $this->cachePool->save($item); + } + + /** + * @param string $key + * + * @return bool + */ + public function delete($key) + { + if (null !== $this->lastItem && $this->lastItem->getKey() === $key) { + $this->lastItem = null; + } + + return $this->cachePool->deleteItem($key); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Storage/VolatileRuntimeStorage.php b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/VolatileRuntimeStorage.php new file mode 100644 index 0000000..ec77d30 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/VolatileRuntimeStorage.php @@ -0,0 +1,60 @@ +cache[$key])) { + return $this->cache[$key]; + } + + return; + } + + /** + * @param string $key + * @param CacheEntry $data + * + * @return bool + */ + public function save($key, CacheEntry $data) + { + $this->cache[$key] = $data; + + return true; + } + + /** + * @param string $key + * + * @return bool + */ + public function delete($key) + { + if (true === array_key_exists($key, $this->cache)) { + unset($this->cache[$key]); + + return true; + } + + return false; + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Storage/WordPressObjectCacheStorage.php b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/WordPressObjectCacheStorage.php new file mode 100644 index 0000000..c81e739 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Storage/WordPressObjectCacheStorage.php @@ -0,0 +1,73 @@ +group = $group; + } + + /** + * @param string $key + * + * @return CacheEntry|null the data or false + */ + public function fetch($key) + { + try { + $cache = unserialize(wp_cache_get($key, $this->group)); + if ($cache instanceof CacheEntry) { + return $cache; + } + } catch (\Exception $ignored) { + // Don't fail if we can't load it + } + + return null; + } + + /** + * @param string $key + * @param CacheEntry $data + * + * @return bool + */ + public function save($key, CacheEntry $data) + { + try { + return wp_cache_set($key, serialize($data), $this->group, $data->getTTL()); + } catch (\Exception $ignored) { + // Don't fail if we can't save it + } + + return false; + } + + /** + * @param string $key + * + * @return bool + */ + public function delete($key) + { + try { + return wp_cache_delete($key, $this->group); + } catch (\Exception $ignored) { + // Don't fail if we can't delete it + } + + return false; + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/CacheStrategyInterface.php b/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/CacheStrategyInterface.php new file mode 100644 index 0000000..a88df2d --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/CacheStrategyInterface.php @@ -0,0 +1,42 @@ +defaultCacheStrategy = $defaultCacheStrategy ?: new NullCacheStrategy(); + } + + /** + * @param CacheStrategyInterface $defaultCacheStrategy + */ + public function setDefaultCacheStrategy(CacheStrategyInterface $defaultCacheStrategy) + { + $this->defaultCacheStrategy = $defaultCacheStrategy; + } + + /** + * @param RequestMatcherInterface $requestMatcher + * @param CacheStrategyInterface $cacheStrategy + */ + final public function registerRequestMatcher(RequestMatcherInterface $requestMatcher, CacheStrategyInterface $cacheStrategy) + { + $this->requestMatchers[] = [ + $requestMatcher, + $cacheStrategy, + ]; + } + + /** + * @param RequestInterface $request + * @return CacheStrategyInterface + */ + private function getStrategyFor(RequestInterface $request) + { + /** + * @var RequestMatcherInterface $requestMatcher + * @var CacheStrategyInterface $cacheStrategy + */ + foreach ($this->requestMatchers as $requestMatcher) { + list($requestMatcher, $cacheStrategy) = $requestMatcher; + if ($requestMatcher->matches($request)) { + return $cacheStrategy; + } + } + + return $this->defaultCacheStrategy; + } + + /** + * @inheritDoc + */ + public function fetch(RequestInterface $request) + { + return $this->getStrategyFor($request)->fetch($request); + } + + /** + * @inheritDoc + */ + public function cache(RequestInterface $request, ResponseInterface $response) + { + return $this->getStrategyFor($request)->cache($request, $response); + } + + /** + * @inheritDoc + */ + public function update(RequestInterface $request, ResponseInterface $response) + { + return $this->getStrategyFor($request)->update($request, $response); + } + + /** + * {@inheritdoc} + */ + public function delete(RequestInterface $request) + { + return $this->getStrategyFor($request)->delete($request); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/Delegate/RequestMatcherInterface.php b/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/Delegate/RequestMatcherInterface.php new file mode 100644 index 0000000..5890bc2 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/Delegate/RequestMatcherInterface.php @@ -0,0 +1,15 @@ +defaultTtl = $defaultTtl; + $this->varyHeaders = $varyHeaders; + parent::__construct($cache); + } + + protected function getCacheKey(RequestInterface $request, KeyValueHttpHeader $varyHeaders = null) + { + if (null === $varyHeaders || $varyHeaders->isEmpty()) { + return hash( + 'sha256', + 'greedy'.$request->getMethod().$request->getUri() + ); + } + + $cacheHeaders = []; + foreach ($varyHeaders as $key => $value) { + if ($request->hasHeader($key)) { + $cacheHeaders[$key] = $request->getHeader($key); + } + } + + return hash( + 'sha256', + 'greedy'.$request->getMethod().$request->getUri().json_encode($cacheHeaders) + ); + } + + public function cache(RequestInterface $request, ResponseInterface $response) + { + $warningMessage = sprintf('%d - "%s" "%s"', + 299, + 'Cached although the response headers indicate not to do it!', + (new \DateTime())->format(\DateTime::RFC1123) + ); + + $response = $response->withAddedHeader('Warning', $warningMessage); + + if ($cacheObject = $this->getCacheObject($request, $response)) { + return $this->storage->save( + $this->getCacheKey($request, $this->varyHeaders), + $cacheObject + ); + } + + return false; + } + + protected function getCacheObject(RequestInterface $request, ResponseInterface $response) + { + if (!array_key_exists($response->getStatusCode(), $this->statusAccepted)) { + // Don't cache it + return null; + } + + if (null !== $this->varyHeaders && $this->varyHeaders->has('*')) { + // This will never match with a request + return; + } + + $response = $response->withoutHeader('Etag')->withoutHeader('Last-Modified'); + + $ttl = $this->defaultTtl; + if ($request->hasHeader(self::HEADER_TTL)) { + $ttlHeaderValues = $request->getHeader(self::HEADER_TTL); + $ttl = (int)reset($ttlHeaderValues); + } + + return new CacheEntry($request->withoutHeader(self::HEADER_TTL), $response, new \DateTime(sprintf('+%d seconds', $ttl))); + } + + public function fetch(RequestInterface $request) + { + $cache = $this->storage->fetch($this->getCacheKey($request, $this->varyHeaders)); + return $cache; + } + + /** + * {@inheritdoc} + */ + public function delete(RequestInterface $request) + { + return $this->storage->delete($this->getCacheKey($request)); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/NullCacheStrategy.php b/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/NullCacheStrategy.php new file mode 100644 index 0000000..22e3929 --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/NullCacheStrategy.php @@ -0,0 +1,43 @@ + 200, + 203 => 203, + 204 => 204, + 300 => 300, + 301 => 301, + 404 => 404, + 405 => 405, + 410 => 410, + 414 => 414, + 418 => 418, + 501 => 501, + ]; + + /** + * @var string[] + */ + protected $ageKey = [ + 'max-age', + ]; + + public function __construct(CacheStorageInterface $cache = null) + { + $this->storage = $cache !== null ? $cache : new VolatileRuntimeStorage(); + } + + /** + * @param RequestInterface $request + * @param ResponseInterface $response + * @return CacheEntry|null entry to save, null if can't cache it + */ + protected function getCacheObject(RequestInterface $request, ResponseInterface $response) + { + if (!isset($this->statusAccepted[$response->getStatusCode()])) { + // Don't cache it + return; + } + + $cacheControl = new KeyValueHttpHeader($response->getHeader('Cache-Control')); + $varyHeader = new KeyValueHttpHeader($response->getHeader('Vary')); + + if ($varyHeader->has('*')) { + // This will never match with a request + return; + } + + if ($cacheControl->has('no-store')) { + // No store allowed (maybe some sensitives data...) + return; + } + + if ($cacheControl->has('no-cache')) { + // Stale response see RFC7234 section 5.2.1.4 + $entry = new CacheEntry($request, $response, new \DateTime('-1 seconds')); + + return $entry->hasValidationInformation() ? $entry : null; + } + + foreach ($this->ageKey as $key) { + if ($cacheControl->has($key)) { + return new CacheEntry( + $request, + $response, + new \DateTime('+'.(int) $cacheControl->get($key).'seconds') + ); + } + } + + if ($response->hasHeader('Expires')) { + $expireAt = \DateTime::createFromFormat(\DateTime::RFC1123, $response->getHeaderLine('Expires')); + if ($expireAt !== false) { + return new CacheEntry( + $request, + $response, + $expireAt + ); + } + } + + return new CacheEntry($request, $response, new \DateTime('-1 seconds')); + } + + /** + * Generate a key for the response cache. + * + * @param RequestInterface $request + * @param null|KeyValueHttpHeader $varyHeaders The vary headers which should be honoured by the cache (optional) + * + * @return string + */ + protected function getCacheKey(RequestInterface $request, KeyValueHttpHeader $varyHeaders = null) + { + if (!$varyHeaders) { + return hash('sha256', $request->getMethod().$request->getUri()); + } + + $cacheHeaders = []; + + foreach ($varyHeaders as $key => $value) { + if ($request->hasHeader($key)) { + $cacheHeaders[$key] = $request->getHeader($key); + } + } + + return hash('sha256', $request->getMethod().$request->getUri().json_encode($cacheHeaders)); + } + + /** + * Return a CacheEntry or null if no cache. + * + * @param RequestInterface $request + * + * @return CacheEntry|null + */ + public function fetch(RequestInterface $request) + { + /** @var int|null $maxAge */ + $maxAge = null; + + if ($request->hasHeader('Cache-Control')) { + $reqCacheControl = new KeyValueHttpHeader($request->getHeader('Cache-Control')); + if ($reqCacheControl->has('no-cache')) { + // Can't return cache + return null; + } + + $maxAge = $reqCacheControl->get('max-age', null); + } elseif ($request->hasHeader('Pragma')) { + $pragma = new KeyValueHttpHeader($request->getHeader('Pragma')); + if ($pragma->has('no-cache')) { + // Can't return cache + return null; + } + } + + $cache = $this->storage->fetch($this->getCacheKey($request)); + if ($cache !== null) { + $varyHeaders = $cache->getVaryHeaders(); + + // vary headers exist from a previous response, check if we have a cache that matches those headers + if (!$varyHeaders->isEmpty()) { + $cache = $this->storage->fetch($this->getCacheKey($request, $varyHeaders)); + + if (!$cache) { + return null; + } + } + + if ((string)$cache->getOriginalRequest()->getUri() !== (string)$request->getUri()) { + return null; + } + + if ($maxAge !== null) { + if ($cache->getAge() > $maxAge) { + // Cache entry is too old for the request requirements! + return null; + } + } + + if (!$cache->isVaryEquals($request)) { + return null; + } + } + + return $cache; + } + + /** + * @param RequestInterface $request + * @param ResponseInterface $response + * + * @return bool true if success + */ + public function cache(RequestInterface $request, ResponseInterface $response) + { + $reqCacheControl = new KeyValueHttpHeader($request->getHeader('Cache-Control')); + if ($reqCacheControl->has('no-store')) { + // No caching allowed + return false; + } + + $cacheObject = $this->getCacheObject($request, $response); + if ($cacheObject !== null) { + // store the cache against the URI-only key + $success = $this->storage->save( + $this->getCacheKey($request), + $cacheObject + ); + + $varyHeaders = $cacheObject->getVaryHeaders(); + + if (!$varyHeaders->isEmpty()) { + // also store the cache against the vary headers based key + $success = $this->storage->save( + $this->getCacheKey($request, $varyHeaders), + $cacheObject + ); + } + + return $success; + } + + return false; + } + + /** + * @param RequestInterface $request + * @param ResponseInterface $response + * + * @return bool true if success + */ + public function update(RequestInterface $request, ResponseInterface $response) + { + return $this->cache($request, $response); + } + + /** + * {@inheritdoc} + */ + public function delete(RequestInterface $request) + { + return $this->storage->delete($this->getCacheKey($request)); + } +} diff --git a/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/PublicCacheStrategy.php b/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/PublicCacheStrategy.php new file mode 100644 index 0000000..873ac2c --- /dev/null +++ b/vendor/kevinrob/guzzle-cache-middleware/src/Strategy/PublicCacheStrategy.php @@ -0,0 +1,42 @@ +ageKey, 's-maxage'); + } + + /** + * {@inheritdoc} + */ + protected function getCacheObject(RequestInterface $request, ResponseInterface $response) + { + $cacheControl = new KeyValueHttpHeader($response->getHeader('Cache-Control')); + if ($cacheControl->has('private')) { + return; + } + + return parent::getCacheObject($request, $response); + } +} diff --git a/vendor/league/mime-type-detection/CHANGELOG.md b/vendor/league/mime-type-detection/CHANGELOG.md index 2264f7a..cd80156 100644 --- a/vendor/league/mime-type-detection/CHANGELOG.md +++ b/vendor/league/mime-type-detection/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 1.12.0 - 2022-08-03 + +### Updated + +- Updated lookup + +## 1.11.0 - 2022-04-17 + +### Updated + +- Updated lookup + ## 1.10.0 - 2022-04-11 ### Fixed diff --git a/vendor/league/mime-type-detection/LICENSE b/vendor/league/mime-type-detection/LICENSE index 1f01652..39d50b5 100644 --- a/vendor/league/mime-type-detection/LICENSE +++ b/vendor/league/mime-type-detection/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2022 Frank de Jonge +Copyright (c) 2013-2023 Frank de Jonge Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php b/vendor/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php index f092388..6a7de98 100644 --- a/vendor/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php +++ b/vendor/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php @@ -34,6 +34,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'acu' => 'application/vnd.acucobol', 'acutc' => 'application/vnd.acucorp', 'adp' => 'audio/adpcm', + 'adts' => 'audio/aac', 'aep' => 'application/vnd.audiograph', 'afm' => 'application/x-font-type1', 'afp' => 'application/vnd.ibm.modcap', @@ -46,11 +47,16 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'air' => 'application/vnd.adobe.air-application-installer-package+zip', 'ait' => 'application/vnd.dvb.ait', 'ami' => 'application/vnd.amiga.ami', + 'aml' => 'application/automationml-aml+xml', + 'amlx' => 'application/automationml-amlx+zip', 'amr' => 'audio/amr', 'apk' => 'application/vnd.android.package-archive', 'apng' => 'image/apng', 'appcache' => 'text/cache-manifest', + 'appinstaller' => 'application/appinstaller', 'application' => 'application/x-ms-application', + 'appx' => 'application/appx', + 'appxbundle' => 'application/appxbundle', 'apr' => 'application/vnd.lotus-approach', 'arc' => 'application/x-freearc', 'arj' => 'application/x-arj', @@ -95,6 +101,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'bpk' => 'application/octet-stream', 'bpmn' => 'application/octet-stream', 'bsp' => 'model/vnd.valve.source.compiled-map', + 'btf' => 'image/prs.btif', 'btif' => 'image/prs.btif', 'buffer' => 'application/octet-stream', 'bz' => 'application/x-bzip', @@ -146,6 +153,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'cjs' => 'application/node', 'cla' => 'application/vnd.claymore', 'class' => 'application/octet-stream', + 'cld' => 'model/vnd.cld', 'clkk' => 'application/vnd.crick.clicker.keyboard', 'clkp' => 'application/vnd.crick.clicker.palette', 'clkt' => 'application/vnd.crick.clicker.template', @@ -180,6 +188,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'csv' => 'text/csv', 'cu' => 'application/cu-seeme', 'curl' => 'text/vnd.curl', + 'cwl' => 'application/cwl', 'cww' => 'application/prs.cww', 'cxt' => 'application/x-director', 'cxx' => 'text/x-c', @@ -202,6 +211,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'der' => 'application/x-x509-ca-cert', 'dfac' => 'application/vnd.dreamfactory', 'dgc' => 'application/x-dgc-compressed', + 'dib' => 'image/bmp', 'dic' => 'text/x-c', 'dir' => 'application/x-director', 'dis' => 'application/vnd.mobius.dis', @@ -224,6 +234,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'dp' => 'application/vnd.osgi.dp', 'dpg' => 'application/vnd.dpgraph', + 'dpx' => 'image/dpx', 'dra' => 'audio/vnd.dra', 'drle' => 'image/dicom-rle', 'dsc' => 'text/prs.lines.tag', @@ -260,7 +271,6 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'eot' => 'application/vnd.ms-fontobject', 'eps' => 'application/postscript', 'epub' => 'application/epub+zip', - 'es' => 'application/ecmascript', 'es3' => 'application/vnd.eszigno3+xml', 'esa' => 'application/vnd.osgi.subsystem', 'esf' => 'application/vnd.epson.esf', @@ -453,6 +463,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'jsonld' => 'application/ld+json', 'jsonml' => 'application/jsonml+json', 'jsx' => 'text/jsx', + 'jt' => 'model/jt', 'jxr' => 'image/jxr', 'jxra' => 'image/jxra', 'jxrs' => 'image/jxrs', @@ -557,7 +568,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'mime' => 'message/rfc822', 'mj2' => 'video/mj2', 'mjp2' => 'video/mj2', - 'mjs' => 'application/javascript', + 'mjs' => 'text/javascript', 'mk3d' => 'video/x-matroska', 'mka' => 'audio/x-matroska', 'mkd' => 'text/x-markdown', @@ -607,6 +618,8 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'msg' => 'application/vnd.ms-outlook', 'msh' => 'model/mesh', 'msi' => 'application/x-msdownload', + 'msix' => 'application/msix', + 'msixbundle' => 'application/msixbundle', 'msl' => 'application/vnd.mobius.msl', 'msm' => 'application/octet-stream', 'msp' => 'application/octet-stream', @@ -780,6 +793,8 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'pvb' => 'application/vnd.3gpp.pic-bw-var', 'pwn' => 'application/vnd.3m.post-it-notes', 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyo' => 'model/vnd.pytha.pyox', + 'pyox' => 'model/vnd.pytha.pyox', 'pyv' => 'video/vnd.ms-playready.media.pyv', 'qam' => 'application/vnd.epson.quickanime', 'qbo' => 'application/vnd.intu.qbo', @@ -928,10 +943,12 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'st' => 'application/vnd.sailingtracker.track', 'stc' => 'application/vnd.sun.xml.calc.template', 'std' => 'application/vnd.sun.xml.draw.template', + 'step' => 'application/STEP', 'stf' => 'application/vnd.wt.stf', 'sti' => 'application/vnd.sun.xml.impress.template', 'stk' => 'application/hyperstudio', 'stl' => 'model/stl', + 'stp' => 'application/STEP', 'stpx' => 'model/step+xml', 'stpxz' => 'model/step-xml+zip', 'stpz' => 'model/step+zip', @@ -1018,10 +1035,12 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'ulx' => 'application/x-glulx', 'umj' => 'application/vnd.umajin', 'unityweb' => 'application/vnd.unity', + 'uo' => 'application/vnd.uoml+xml', 'uoml' => 'application/vnd.uoml+xml', 'uri' => 'text/uri-list', 'uris' => 'text/uri-list', 'urls' => 'text/uri-list', + 'usda' => 'model/vnd.usda', 'usdz' => 'model/vnd.usdz+zip', 'ustar' => 'application/x-ustar', 'utz' => 'application/vnd.uiq.theme', @@ -1101,6 +1120,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'webmanifest' => 'application/manifest+json', 'webp' => 'image/webp', 'wg' => 'application/vnd.pmi.widget', + 'wgsl' => 'text/wgsl', 'wgt' => 'application/widget', 'wif' => 'application/watcherinfo+xml', 'wks' => 'application/vnd.ms-works', @@ -1155,9 +1175,10 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'xel' => 'application/xcap-el+xml', 'xenc' => 'application/xenc+xml', 'xer' => 'application/patch-ops-error+xml', - 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdf' => 'application/xfdf', 'xfdl' => 'application/vnd.xfdl', 'xht' => 'application/xhtml+xml', + 'xhtm' => 'application/vnd.pwg-xhtml-print+xml', 'xhtml' => 'application/xhtml+xml', 'xhvml' => 'application/xv+xml', 'xif' => 'image/vnd.xiff', @@ -1188,6 +1209,7 @@ class GeneratedExtensionToMimeTypeMap implements ExtensionToMimeTypeMap 'xpw' => 'application/vnd.intercon.formnet', 'xpx' => 'application/vnd.intercon.formnet', 'xsd' => 'application/xml', + 'xsf' => 'application/prs.xsf+xml', 'xsl' => 'application/xml', 'xslt' => 'application/xslt+xml', 'xsm' => 'application/vnd.syncml+xml', diff --git a/vendor/php-curl-class/php-curl-class/.editorconfig b/vendor/php-curl-class/php-curl-class/.editorconfig deleted file mode 100644 index 8b2e1a8..0000000 --- a/vendor/php-curl-class/php-curl-class/.editorconfig +++ /dev/null @@ -1,8 +0,0 @@ -root = true - -[*.php] -charset = utf-8 -end_of_line = lf -indent_size = 4 -indent_style = space -trim_trailing_whitespace = true diff --git a/vendor/php-curl-class/php-curl-class/CHANGELOG.md b/vendor/php-curl-class/php-curl-class/CHANGELOG.md index 8a432e7..5e2e43f 100644 --- a/vendor/php-curl-class/php-curl-class/CHANGELOG.md +++ b/vendor/php-curl-class/php-curl-class/CHANGELOG.md @@ -6,6 +6,82 @@ backwards-incompatible changes that will affect existing usage. +## 9.19.2 - 2024-04-09 + +- Fix CI: Use nullable type declaration ([#859](https://github.com/php-curl-class/php-curl-class/pull/859)) + +## 9.19.1 - 2024-02-27 + +- Fix afterSend not being called ([#848](https://github.com/php-curl-class/php-curl-class/pull/848)) + +## 9.19.0 - 2024-01-18 + +- Allow displaying curl option value without specifying value ([#837](https://github.com/php-curl-class/php-curl-class/pull/837)) + +## 9.18.2 - 2023-09-11 + +- Fix use of mb_strpos() causing error when polyfill is used ([#813](https://github.com/php-curl-class/php-curl-class/pull/813)) + +## 9.18.1 - 2023-08-29 + +- Add additional check for decoding gzip-encoded responses ([#808](https://github.com/php-curl-class/php-curl-class/pull/808)) + +## 9.18.0 - 2023-08-28 + +- Implement Curl::setError() and MultiCurl::setError() ([#805](https://github.com/php-curl-class/php-curl-class/pull/805)) +- Rename ::setError() to ::afterSend() ([#807](https://github.com/php-curl-class/php-curl-class/pull/807)) + +## 9.17.4 - 2023-07-10 + +- Add coding standards rule to use the null coalescing operator ?? where possible ([#801](https://github.com/php-curl-class/php-curl-class/pull/801)) +- Replace isset with null coalescing operator ([#800](https://github.com/php-curl-class/php-curl-class/pull/800)) + +## 9.17.3 - 2023-07-04 + +- Update PHP_CodeSniffer ruleset: PSR2 → PSR12 ([#797](https://github.com/php-curl-class/php-curl-class/pull/797)) +- Add additional coding standard checks ([#796](https://github.com/php-curl-class/php-curl-class/pull/796)) + +## 9.17.2 - 2023-06-27 + +- Use short array syntax ([#793](https://github.com/php-curl-class/php-curl-class/pull/793)) +- Add PHP-CS-Fixer to check for unused imports ([#794](https://github.com/php-curl-class/php-curl-class/pull/794)) +- Replace `uniqid` by `random_bytes` ([#792](https://github.com/php-curl-class/php-curl-class/pull/792)) + +## 9.17.1 - 2023-06-14 + +- Improve and add tests for Curl::fastDownload() ([#791](https://github.com/php-curl-class/php-curl-class/pull/791)) + +## 9.17.0 - 2023-06-13 + +- Make method to display curl option value public ([#790](https://github.com/php-curl-class/php-curl-class/pull/790)) + +## 9.16.1 - 2023-06-12 + +- Differentiate between internal options and user-set options ([#788](https://github.com/php-curl-class/php-curl-class/pull/788)) +- Create method to display a curl option value ([#785](https://github.com/php-curl-class/php-curl-class/pull/785)) +- Fix existing header overwritten after using MultiCurl::addCurl() ([#787](https://github.com/php-curl-class/php-curl-class/pull/787)) + +## 9.16.0 - 2023-05-25 + +- Graduate Curl::fastDownload() ([#783](https://github.com/php-curl-class/php-curl-class/pull/783)) + +## 9.15.1 - 2023-05-24 + +- Fix PHP CodeSniffer errors ([#782](https://github.com/php-curl-class/php-curl-class/pull/782)) + +## 9.15.0 - 2023-05-22 + +- Update Curl::diagnose() to detect bit flags with negative values ([#781](https://github.com/php-curl-class/php-curl-class/pull/781)) +- Display bit flags in use when calling Curl::diagnose() ([#779](https://github.com/php-curl-class/php-curl-class/pull/779)) + +## 9.14.5 - 2023-05-16 + +- Handle missing content-type response header in Curl::diagnose() ([#778](https://github.com/php-curl-class/php-curl-class/pull/778)) + +## 9.14.4 - 2023-05-08 + +- Update article in Curl::diagnose() Allow header warning ([#776](https://github.com/php-curl-class/php-curl-class/pull/776)) + ## 9.14.3 - 2023-03-13 - Remove use of array_merge() inside loop ([#774](https://github.com/php-curl-class/php-curl-class/pull/774)) diff --git a/vendor/php-curl-class/php-curl-class/README.md b/vendor/php-curl-class/php-curl-class/README.md index bdf7277..d825f7a 100644 --- a/vendor/php-curl-class/php-curl-class/README.md +++ b/vendor/php-curl-class/php-curl-class/README.md @@ -37,7 +37,7 @@ Installation instructions to use the `composer` command can be found on https:// ### Requirements -PHP Curl Class works with PHP 7.0, 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, and 8.2. +PHP Curl Class works with PHP 8.3, 8.2, 8.1, 8.0, 7.4, 7.3, 7.2, 7.1, and 7.0. ### Quick Start and Examples @@ -199,7 +199,7 @@ More examples are available under [/examples](https://github.com/php-curl-class/ Curl::__construct($base_url = null, $options = []) Curl::__destruct() Curl::__get($name) -Curl::_fastDownload($url, $filename, $connections = 4) +Curl::afterSend($callback) Curl::attemptRetry() Curl::beforeSend($callback) Curl::buildPostData($data) @@ -209,10 +209,12 @@ Curl::complete($callback) Curl::delete($url, $query_parameters = [], $data = []) Curl::diagnose($return = false) Curl::disableTimeout() +Curl::displayCurlOptionValue($option, $value = null) Curl::download($url, $mixed_filename) Curl::error($callback) Curl::exec($ch = null) Curl::execDone() +Curl::fastDownload($url, $filename, $connections = 4) Curl::get($url, $data = []) Curl::getAttempts() Curl::getBeforeSendCallback() @@ -233,6 +235,7 @@ Curl::getId() Curl::getInfo($opt = null) Curl::getJsonDecoder() Curl::getOpt($option) +Curl::getOptions() Curl::getRawResponse() Curl::getRawResponseHeaders() Curl::getRemainingRetries() @@ -245,6 +248,7 @@ Curl::getRetries() Curl::getRetryDecider() Curl::getSuccessCallback() Curl::getUrl() +Curl::getUserSetOptions() Curl::getXmlDecoder() Curl::head($url, $data = []) Curl::isChildOfMultiCurl() @@ -319,6 +323,7 @@ MultiCurl::addPatch($url, $data = []) MultiCurl::addPost($url, $data = '', $follow_303_with_post = false) MultiCurl::addPut($url, $data = []) MultiCurl::addSearch($url, $data = []) +MultiCurl::afterSend($callback) MultiCurl::beforeSend($callback) MultiCurl::close() MultiCurl::complete($callback) diff --git a/vendor/php-curl-class/php-curl-class/composer.json b/vendor/php-curl-class/php-curl-class/composer.json index 389876e..6641a2d 100644 --- a/vendor/php-curl-class/php-curl-class/composer.json +++ b/vendor/php-curl-class/php-curl-class/composer.json @@ -11,6 +11,10 @@ "authors": [ { "name": "Zach Borboa" + }, + { + "name": "Contributors", + "homepage": "https://github.com/php-curl-class/php-curl-class/graphs/contributors" } ], "require": { @@ -20,11 +24,12 @@ "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "*", "ext-gd": "*", + "friendsofphp/php-cs-fixer": "*", "phpcompatibility/php-compatibility": "dev-develop", "phpcsstandards/phpcsutils": "@alpha", "phpunit/phpunit": "*", "squizlabs/php_codesniffer": "*", - "vimeo/psalm": "*" + "vimeo/psalm": ">=0.3.63" }, "suggest": { "ext-mbstring": "*" diff --git a/vendor/php-curl-class/php-curl-class/setup.cfg b/vendor/php-curl-class/php-curl-class/setup.cfg new file mode 100644 index 0000000..7da1f96 --- /dev/null +++ b/vendor/php-curl-class/php-curl-class/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 100 diff --git a/vendor/php-curl-class/php-curl-class/src/Curl/ArrayUtil.php b/vendor/php-curl-class/php-curl-class/src/Curl/ArrayUtil.php index e618657..20a83c8 100644 --- a/vendor/php-curl-class/php-curl-class/src/Curl/ArrayUtil.php +++ b/vendor/php-curl-class/php-curl-class/src/Curl/ArrayUtil.php @@ -1,18 +1,16 @@ -options[$option]) ? $this->options[$option] : null; + return $this->options[$option] ?? null; } /** @@ -75,8 +72,7 @@ abstract class BaseCurl * Remove an internal header from the request. * Using `curl -H "Host:" ...' is equivalent to $curl->removeHeader('Host');. * - * @access public - * @param $key + * @param $key */ public function removeHeader($key) { @@ -86,7 +82,7 @@ abstract class BaseCurl /** * Set auto referer * - * @access public + * @param mixed $auto_referer */ public function setAutoReferer($auto_referer = true) { @@ -96,7 +92,7 @@ abstract class BaseCurl /** * Set auto referrer * - * @access public + * @param mixed $auto_referrer */ public function setAutoReferrer($auto_referrer = true) { @@ -106,9 +102,8 @@ abstract class BaseCurl /** * Set Basic Authentication * - * @access public - * @param $username - * @param $password + * @param $username + * @param $password */ public function setBasicAuthentication($username, $password = '') { @@ -119,8 +114,7 @@ abstract class BaseCurl /** * Set Connect Timeout * - * @access public - * @param $seconds + * @param $seconds */ public function setConnectTimeout($seconds) { @@ -136,9 +130,8 @@ abstract class BaseCurl /** * Set Digest Authentication * - * @access public - * @param $username - * @param $password + * @param $username + * @param $password */ public function setDigestAuthentication($username, $password = '') { @@ -146,21 +139,48 @@ abstract class BaseCurl $this->setOpt(CURLOPT_USERPWD, $username . ':' . $password); } + /** + * After Send + * + * This function is called after the request has been sent. + * + * It can be used to override whether or not the request errored. The + * instance is passed as the first argument to the function and the instance + * has attributes like $instance->httpStatusCode and $instance->response to + * help decide if the request errored. Set $instance->error to true or false + * within the function. + * + * When $instance->error is true indicating a request error, the error + * callback set by Curl::error() is called. When $instance->error is false, + * the success callback set by Curl::success() is called. + * + * @param $callback callable|null + */ + public function afterSend($callback) + { + $this->afterSendCallback = $callback; + } + /** * Set File * - * @access public - * @param $file + * @param $file */ public function setFile($file) { $this->setOpt(CURLOPT_FILE, $file); } + protected function setFileInternal($file) + { + $this->setOptInternal(CURLOPT_FILE, $file); + } + /** * Set follow location * - * @access public + * @param mixed $follow_location + * @see Curl::setMaximumRedirects() */ public function setFollowLocation($follow_location = true) { @@ -170,7 +190,7 @@ abstract class BaseCurl /** * Set forbid reuse * - * @access public + * @param mixed $forbid_reuse */ public function setForbidReuse($forbid_reuse = true) { @@ -186,8 +206,7 @@ abstract class BaseCurl * The name of the outgoing network interface to use. * This can be an interface name, an IP address or a host name. * - * @access public - * @param $interface + * @param $interface */ public function setInterface($interface) { @@ -199,7 +218,8 @@ abstract class BaseCurl /** * Set maximum redirects * - * @access public + * @param mixed $maximum_redirects + * @see Curl::setFollowLocation() */ public function setMaximumRedirects($maximum_redirects) { @@ -207,13 +227,17 @@ abstract class BaseCurl } abstract public function setOpt($option, $value); + + protected function setOptInternal($option, $value) + { + } + abstract public function setOpts($options); /** * Set Port * - * @access public - * @param $port + * @param $port */ public function setPort($port) { @@ -225,11 +249,10 @@ abstract class BaseCurl * * Set an HTTP proxy to tunnel requests through. * - * @access public - * @param $proxy - The HTTP proxy to tunnel requests through. May include port number. - * @param $port - The port number of the proxy to connect to. This port number can also be set in $proxy. - * @param $username - The username to use for the connection to the proxy. - * @param $password - The password to use for the connection to the proxy. + * @param $proxy - The HTTP proxy to tunnel requests through. May include port number. + * @param $port - The port number of the proxy to connect to. This port number can also be set in $proxy. + * @param $username - The username to use for the connection to the proxy. + * @param $password - The password to use for the connection to the proxy. */ public function setProxy($proxy, $port = null, $username = null, $password = null) { @@ -247,8 +270,7 @@ abstract class BaseCurl * * Set the HTTP authentication method(s) to use for the proxy connection. * - * @access public - * @param $auth + * @param $auth */ public function setProxyAuth($auth) { @@ -260,8 +282,7 @@ abstract class BaseCurl * * Set the proxy to tunnel through HTTP proxy. * - * @access public - * @param $tunnel boolean + * @param $tunnel boolean */ public function setProxyTunnel($tunnel = true) { @@ -273,8 +294,7 @@ abstract class BaseCurl * * Set the proxy protocol type. * - * @access public - * @param $type + * @param $type */ public function setProxyType($type) { @@ -284,19 +304,22 @@ abstract class BaseCurl /** * Set Range * - * @access public - * @param $range + * @param $range */ public function setRange($range) { $this->setOpt(CURLOPT_RANGE, $range); } + protected function setRangeInternal($range) + { + $this->setOptInternal(CURLOPT_RANGE, $range); + } + /** * Set Referer * - * @access public - * @param $referer + * @param $referer */ public function setReferer($referer) { @@ -306,8 +329,7 @@ abstract class BaseCurl /** * Set Referrer * - * @access public - * @param $referrer + * @param $referrer */ public function setReferrer($referrer) { @@ -319,35 +341,42 @@ abstract class BaseCurl /** * Set Timeout * - * @access public - * @param $seconds + * @param $seconds */ public function setTimeout($seconds) { $this->setOpt(CURLOPT_TIMEOUT, $seconds); } + protected function setTimeoutInternal($seconds) + { + $this->setOptInternal(CURLOPT_TIMEOUT, $seconds); + } + abstract public function setUrl($url, $mixed_data = ''); /** * Set User Agent * - * @access public - * @param $user_agent + * @param $user_agent */ public function setUserAgent($user_agent) { $this->setOpt(CURLOPT_USERAGENT, $user_agent); } + protected function setUserAgentInternal($user_agent) + { + $this->setOptInternal(CURLOPT_USERAGENT, $user_agent); + } + abstract public function setXmlDecoder($mixed); abstract public function stop(); /** * Success * - * @access public - * @param $callback callable|null + * @param $callback callable|null */ public function success($callback) { @@ -360,8 +389,6 @@ abstract class BaseCurl * Unset Proxy * * Disable use of the proxy. - * - * @access public */ public function unsetProxy() { @@ -371,9 +398,8 @@ abstract class BaseCurl /** * Verbose * - * @access public - * @param bool $on - * @param resource|string $output + * @param bool $on + * @param resource|string $output */ public function verbose($on = true, $output = 'STDERR') { diff --git a/vendor/php-curl-class/php-curl-class/src/Curl/CaseInsensitiveArray.php b/vendor/php-curl-class/php-curl-class/src/Curl/CaseInsensitiveArray.php index 13fb015..3a4e1db 100644 --- a/vendor/php-curl-class/php-curl-class/src/Curl/CaseInsensitiveArray.php +++ b/vendor/php-curl-class/php-curl-class/src/Curl/CaseInsensitiveArray.php @@ -1,4 +1,6 @@ -= PHP 7.1. + // Trying to use the nullable type declaration on PHP 7.0: + // public function __construct(?array $initial = null) + // results in: + // ParseError: syntax error, unexpected '?', expecting variable (T_VARIABLE) + public function __construct($initial = null) { if ($initial !== null) { foreach ($initial as $key => $value) { @@ -58,14 +63,10 @@ class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator * stores the case-sensitive offset and the data at the lowercase indexes in * $this->keys and @this->data. * - * @see https://secure.php.net/manual/en/arrayaccess.offsetset.php - * - * @param string $offset The offset to store the data at (case-insensitive). - * @param mixed $value The data to store at the specified offset. - * + * @param string $offset The offset to store the data at (case-insensitive). + * @param mixed $value The data to store at the specified offset. * @return void - * - * @access public + * @see https://secure.php.net/manual/en/arrayaccess.offsetset.php */ #[\ReturnTypeWillChange] public function offsetSet($offset, $value) @@ -85,13 +86,9 @@ class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator * Checks if the offset exists in data storage. The index is looked up with * the lowercase version of the provided offset. * + * @param string $offset Offset to check + * @return bool If the offset exists. * @see https://secure.php.net/manual/en/arrayaccess.offsetexists.php - * - * @param string $offset Offset to check - * - * @return bool If the offset exists. - * - * @access public */ #[\ReturnTypeWillChange] public function offsetExists($offset) @@ -105,13 +102,9 @@ class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator * Unsets the specified offset. Converts the provided offset to lowercase, * and unsets the case-sensitive key, as well as the stored data. * - * @see https://secure.php.net/manual/en/arrayaccess.offsetunset.php - * - * @param string $offset The offset to unset. - * + * @param string $offset The offset to unset. * @return void - * - * @access public + * @see https://secure.php.net/manual/en/arrayaccess.offsetunset.php */ #[\ReturnTypeWillChange] public function offsetUnset($offset) @@ -127,31 +120,23 @@ class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator * Return the stored data at the provided offset. The offset is converted to * lowercase and the lookup is done on the data store directly. * + * @param string $offset Offset to lookup. + * @return mixed The data stored at the offset. * @see https://secure.php.net/manual/en/arrayaccess.offsetget.php - * - * @param string $offset Offset to lookup. - * - * @return mixed The data stored at the offset. - * - * @access public */ #[\ReturnTypeWillChange] public function offsetGet($offset) { $offsetlower = strtolower($offset); - return isset($this->data[$offsetlower]) ? $this->data[$offsetlower] : null; + return $this->data[$offsetlower] ?? null; } /** * Count * - * @see https://secure.php.net/manual/en/countable.count.php - * * @param void - * - * @return integer The number of elements stored in the array. - * - * @access public + * @return int The number of elements stored in the array. + * @see https://secure.php.net/manual/en/countable.count.php */ #[\ReturnTypeWillChange] public function count() @@ -162,13 +147,9 @@ class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator /** * Current * - * @see https://secure.php.net/manual/en/iterator.current.php - * * @param void - * * @return mixed Data at the current position. - * - * @access public + * @see https://secure.php.net/manual/en/iterator.current.php */ #[\ReturnTypeWillChange] public function current() @@ -179,13 +160,9 @@ class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator /** * Next * - * @see https://secure.php.net/manual/en/iterator.next.php - * * @param void - * * @return void - * - * @access public + * @see https://secure.php.net/manual/en/iterator.next.php */ #[\ReturnTypeWillChange] public function next() @@ -196,29 +173,22 @@ class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator /** * Key * - * @see https://secure.php.net/manual/en/iterator.key.php - * * @param void - * * @return mixed Case-sensitive key at current position. - * - * @access public + * @see https://secure.php.net/manual/en/iterator.key.php */ #[\ReturnTypeWillChange] public function key() { $key = key($this->data); - return isset($this->keys[$key]) ? $this->keys[$key] : $key; + return $this->keys[$key] ?? $key; } /** * Valid * - * @see https://secure.php.net/manual/en/iterator.valid.php - * * @return bool If the current position is valid. - * - * @access public + * @see https://secure.php.net/manual/en/iterator.valid.php */ #[\ReturnTypeWillChange] public function valid() @@ -229,13 +199,9 @@ class CaseInsensitiveArray implements \ArrayAccess, \Countable, \Iterator /** * Rewind * - * @see https://secure.php.net/manual/en/iterator.rewind.php - * * @param void - * * @return void - * - * @access public + * @see https://secure.php.net/manual/en/iterator.rewind.php */ #[\ReturnTypeWillChange] public function rewind() diff --git a/vendor/php-curl-class/php-curl-class/src/Curl/Curl.php b/vendor/php-curl-class/php-curl-class/src/Curl/Curl.php index 1447911..04cbcd9 100644 --- a/vendor/php-curl-class/php-curl-class/src/Curl/Curl.php +++ b/vendor/php-curl-class/php-curl-class/src/Curl/Curl.php @@ -1,14 +1,12 @@ -headers['Content-Type']) && + if ( + isset($this->headers['Content-Type']) && preg_match($this->jsonPattern, $this->headers['Content-Type']) && ( is_array($data) || @@ -157,7 +154,8 @@ class Curl extends BaseCurl interface_exists('JsonSerializable', false) && $data instanceof \JsonSerializable ) - )) { + ) + ) { $data = \Curl\Encoder::encodeJson($data); } elseif (is_array($data)) { // Manually build a single-dimensional array from a multi-dimensional array as using curl_setopt($ch, @@ -185,12 +183,14 @@ class Curl extends BaseCurl } } - if (!$binary_data && + if ( + !$binary_data && (is_array($data) || is_object($data)) && ( !isset($this->headers['Content-Type']) || !preg_match('/^multipart\/form-data/', $this->headers['Content-Type']) - )) { + ) + ) { // Avoid using http_build_query() as keys with null values are // unexpectedly excluded from the resulting string. // @@ -222,8 +222,6 @@ class Curl extends BaseCurl /** * Call - * - * @access public */ public function call() { @@ -237,8 +235,6 @@ class Curl extends BaseCurl /** * Close - * - * @access public */ public function close() { @@ -247,6 +243,7 @@ class Curl extends BaseCurl } $this->curl = null; $this->options = null; + $this->userSetOptions = null; $this->jsonDecoder = null; $this->jsonDecoderArgs = null; $this->xmlDecoder = null; @@ -258,8 +255,7 @@ class Curl extends BaseCurl /** * Progress * - * @access public - * @param $callback callable|null + * @param $callback callable|null */ public function progress($callback) { @@ -267,14 +263,18 @@ class Curl extends BaseCurl $this->setOpt(CURLOPT_NOPROGRESS, false); } + private function progressInternal($callback) + { + $this->setOptInternal(CURLOPT_PROGRESSFUNCTION, $callback); + $this->setOptInternal(CURLOPT_NOPROGRESS, false); + } + /** * Delete * - * @access public - * @param $url - * @param $query_parameters - * @param $data - * + * @param $url + * @param $query_parameters + * @param $data * @return mixed Returns the value provided by exec. */ public function delete($url, $query_parameters = [], $data = []) @@ -304,11 +304,9 @@ class Curl extends BaseCurl /** * Download * - * @access public - * @param $url - * @param $mixed_filename - * - * @return boolean + * @param $url + * @param $mixed_filename + * @return bool */ public function download($url, $mixed_filename) { @@ -357,100 +355,114 @@ class Curl extends BaseCurl /** * Fast download * - * @access private - * @param $url - * @param $filename - * @param $connections - * - * @return boolean + * @param $url + * @param $filename + * @param $connections + * @return bool */ - public function _fastDownload($url, $filename, $connections = 4) + public function fastDownload($url, $filename, $connections = 4) { - // First we need to retrive the 'Content-Length' header. - // Use GET because not all hosts support HEAD requests. - $this->setOpts([ - CURLOPT_CUSTOMREQUEST => 'GET', - CURLOPT_NOBODY => true, - CURLOPT_HEADER => true, - CURLOPT_ENCODING => '', - ]); - $this->setUrl($url); - $this->exec(); + // Retrieve content length from the "Content-Length" header from the url + // to download. Use an HTTP GET request without a body instead of a HEAD + // request because not all hosts support HEAD requests. + $curl = new Curl(); + $curl->setOptInternal(CURLOPT_NOBODY, true); - $content_length = isset($this->responseHeaders['Content-Length']) ? - $this->responseHeaders['Content-Length'] : null; + // Pass user-specified options to the instance checking for content-length. + $curl->setOpts($this->userSetOptions); + $curl->get($url); - // If content length header is missing, use the normal download. + // Exit early when an error occurred. + if ($curl->error) { + return false; + } + + $content_length = $curl->responseHeaders['Content-Length'] ?? null; + + // Use a regular download when content length could not be determined. if (!$content_length) { return $this->download($url, $filename); } - // Try to divide chunk_size equally. - $chunkSize = ceil($content_length / $connections); + // Divide chunk_size across the number of connections. + $chunk_size = ceil($content_length / $connections); - // First bytes. - $offset = 0; - $nextChunk = $chunkSize; - - // We need this later. - $file_parts = []; + // Keep track of file name parts. + $part_file_names = []; $multi_curl = new MultiCurl(); $multi_curl->setConcurrency($connections); - $multi_curl->error(function ($instance) { - return false; - }); - - for ($i = 1; $i <= $connections; $i++) { - // If last chunk then no need to supply it. - // Range starts with 0, so subtract 1. - $nextChunk = $i === $connections ? '' : $nextChunk - 1; - - // Create part file. - $fpath = "$filename.part$i"; - if (is_file($fpath)) { - unlink($fpath); + for ($part_number = 1; $part_number <= $connections; $part_number++) { + $range_start = ($part_number - 1) * $chunk_size; + $range_end = $range_start + $chunk_size - 1; + if ($part_number === $connections) { + $range_end = ''; } - $fp = fopen($fpath, 'w'); + $range = $range_start . '-' . $range_end; - // Track all fileparts names; we need this later. - $file_parts[] = $fpath; + $part_file_name = $filename . '.part' . $part_number; + // Save the file name of this part. + $part_file_names[] = $part_file_name; + + // Remove any existing file part. + if (is_file($part_file_name)) { + unlink($part_file_name); + } + + // Create file part. + $file_handle = tmpfile(); + + // Setup the instance downloading a part. $curl = new Curl(); - $curl->setOpt(CURLOPT_ENCODING, ''); - $curl->setRange("$offset-$nextChunk"); - $curl->setFile($fp); - $curl->disableTimeout(); // otherwise download may fail. $curl->setUrl($url); - $curl->complete(function () use ($fp) { - fclose($fp); - }); + // Pass user-specified options to the instance downloading a part. + $curl->setOpts($this->userSetOptions); + + $curl->setOptInternal(CURLOPT_CUSTOMREQUEST, 'GET'); + $curl->setOptInternal(CURLOPT_HTTPGET, true); + $curl->setRangeInternal($range); + $curl->setFileInternal($file_handle); + $curl->fileHandle = $file_handle; + + $curl->downloadCompleteCallback = function ($instance, $tmpfile) use ($part_file_name) { + $fh = fopen($part_file_name, 'wb'); + stream_copy_to_stream($tmpfile, $fh); + fclose($fh); + }; $multi_curl->addCurl($curl); - - if ($i !== $connections) { - $offset = $nextChunk + 1; // Add 1 to match offset. - $nextChunk = $nextChunk + $chunkSize; - } } - // let the magic begin. + // Start the simultaneous downloads for each of the ranges in parallel. $multi_curl->start(); - // Concatenate chunks to single. + // Remove existing download file name at destination. if (is_file($filename)) { unlink($filename); } - $mainfp = fopen($filename, 'w'); - foreach ($file_parts as $part) { - $fp = fopen($part, 'r'); - stream_copy_to_stream($fp, $mainfp); - fclose($fp); - unlink($part); + + // Combine downloaded chunks into a single file. + $main_file_handle = fopen($filename, 'w'); + + foreach ($part_file_names as $part_file_name) { + if (!is_file($part_file_name)) { + return false; + } + + $file_handle = fopen($part_file_name, 'r'); + if ($file_handle === false) { + return false; + } + + stream_copy_to_stream($file_handle, $main_file_handle); + fclose($file_handle); + unlink($part_file_name); } - fclose($mainfp); + + fclose($main_file_handle); return true; } @@ -458,9 +470,7 @@ class Curl extends BaseCurl /** * Exec * - * @access public - * @param $ch - * + * @param $ch * @return mixed Returns the value provided by parseResponse. */ public function exec($ch = null) @@ -516,11 +526,6 @@ class Curl extends BaseCurl $this->curlErrorMessage = $curl_error_message; } - $this->httpStatusCode = $this->getInfo(CURLINFO_HTTP_CODE); - $this->httpError = in_array((int) floor($this->httpStatusCode / 100), [4, 5], true); - $this->error = $this->curlError || $this->httpError; - $this->errorCode = $this->error ? ($this->curlError ? $this->curlErrorCode : $this->httpStatusCode) : 0; - // NOTE: CURLINFO_HEADER_OUT set to true is required for requestHeaders // to not be empty (e.g. $curl->setOpt(CURLINFO_HEADER_OUT, true);). if ($this->getOpt(CURLINFO_HEADER_OUT) === true) { @@ -529,6 +534,18 @@ class Curl extends BaseCurl $this->responseHeaders = $this->parseResponseHeaders($this->rawResponseHeaders); $this->response = $this->parseResponse($this->responseHeaders, $this->rawResponse); + $this->httpStatusCode = $this->getInfo(CURLINFO_HTTP_CODE); + $this->httpError = in_array((int) floor($this->httpStatusCode / 100), [4, 5], true); + $this->error = $this->curlError || $this->httpError; + + $this->call($this->afterSendCallback); + + if (!in_array($this->error, [true, false], true)) { + trigger_error('$instance->error MUST be set to true or false', E_USER_WARNING); + } + + $this->errorCode = $this->error ? ($this->curlError ? $this->curlErrorCode : $this->httpStatusCode) : 0; + $this->httpErrorMessage = ''; if ($this->error) { if (isset($this->responseHeaders['Status-Line'])) { @@ -546,7 +563,7 @@ class Curl extends BaseCurl $this->unsetHeader('Content-Length'); // Reset nobody setting possibly set from a HEAD request. - $this->setOpt(CURLOPT_NOBODY, false); + $this->setOptInternal(CURLOPT_NOBODY, false); // Allow multicurl to attempt retry as needed. if ($this->isChildOfMultiCurl()) { @@ -581,10 +598,8 @@ class Curl extends BaseCurl /** * Get * - * @access public - * @param $url - * @param $data - * + * @param $url + * @param $data * @return mixed Returns the value provided by exec. */ public function get($url, $data = []) @@ -594,17 +609,15 @@ class Curl extends BaseCurl $url = (string)$this->url; } $this->setUrl($url, $data); - $this->setOpt(CURLOPT_CUSTOMREQUEST, 'GET'); - $this->setOpt(CURLOPT_HTTPGET, true); + $this->setOptInternal(CURLOPT_CUSTOMREQUEST, 'GET'); + $this->setOptInternal(CURLOPT_HTTPGET, true); return $this->exec(); } /** * Get Info * - * @access public - * @param $opt - * + * @param $opt * @return mixed */ public function getInfo($opt = null) @@ -622,10 +635,8 @@ class Curl extends BaseCurl /** * Head * - * @access public - * @param $url - * @param $data - * + * @param $url + * @param $data * @return mixed Returns the value provided by exec. */ public function head($url, $data = []) @@ -643,10 +654,8 @@ class Curl extends BaseCurl /** * Options * - * @access public - * @param $url - * @param $data - * + * @param $url + * @param $data * @return mixed Returns the value provided by exec. */ public function options($url, $data = []) @@ -663,10 +672,8 @@ class Curl extends BaseCurl /** * Patch * - * @access public - * @param $url - * @param $data - * + * @param $url + * @param $data * @return mixed Returns the value provided by exec. */ public function patch($url, $data = []) @@ -689,22 +696,23 @@ class Curl extends BaseCurl /** * Post * - * @access public - * @param $url - * @param $data - * @param $follow_303_with_post - * If true, will cause 303 redirections to be followed using a POST request (default: false). - * Notes: - * - Redirections are only followed if the CURLOPT_FOLLOWLOCATION option is set to true. - * - According to the HTTP specs (see [1]), a 303 redirection should be followed using - * the GET method. 301 and 302 must not. - * - In order to force a 303 redirection to be performed using the same method, the - * underlying cURL object must be set in a special state (the CURLOPT_CUSTOMREQUEST - * option must be set to the method to use after the redirection). Due to a limitation - * of the cURL extension of PHP < 5.5.11 ([2], [3]), it is not possible to reset this - * option. Using these PHP engines, it is therefore impossible to restore this behavior - * on an existing php-curl-class Curl object. - * + * @param $url + * @param $data + * @param $follow_303_with_post + * If true, will cause 303 redirections to be followed using a POST request + * (default: false). + * Notes: + * - Redirections are only followed if the CURLOPT_FOLLOWLOCATION option is set + * to true. + * - According to the HTTP specs (see [1]), a 303 redirection should be followed + * using the GET method. 301 and 302 must not. + * - In order to force a 303 redirection to be performed using the same method, + * the underlying cURL object must be set in a special state (the + * CURLOPT_CUSTOMREQUEST option must be set to the method to use after the + * redirection). Due to a limitation of the cURL extension of PHP < 5.5.11 ([2], + * [3]), it is not possible to reset this option. Using these PHP engines, it is + * therefore impossible to restore this behavior on an existing php-curl-class + * Curl object. * @return mixed Returns the value provided by exec. * * [1] https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2 @@ -742,10 +750,8 @@ class Curl extends BaseCurl /** * Put * - * @access public - * @param $url - * @param $data - * + * @param $url + * @param $data * @return mixed Returns the value provided by exec. */ public function put($url, $data = []) @@ -771,10 +777,8 @@ class Curl extends BaseCurl /** * Search * - * @access public - * @param $url - * @param $data - * + * @param $url + * @param $data * @return mixed Returns the value provided by exec. */ public function search($url, $data = []) @@ -800,9 +804,8 @@ class Curl extends BaseCurl /** * Set Cookie * - * @access public - * @param $key - * @param $value + * @param $key + * @param $value */ public function setCookie($key, $value) { @@ -813,8 +816,7 @@ class Curl extends BaseCurl /** * Set Cookies * - * @access public - * @param $cookies + * @param $cookies */ public function setCookies($cookies) { @@ -827,9 +829,7 @@ class Curl extends BaseCurl /** * Get Cookie * - * @access public - * @param $key - * + * @param $key * @return mixed */ public function getCookie($key) @@ -840,21 +840,18 @@ class Curl extends BaseCurl /** * Get Response Cookie * - * @access public - * @param $key - * + * @param $key * @return mixed */ public function getResponseCookie($key) { - return isset($this->responseCookies[$key]) ? $this->responseCookies[$key] : null; + return $this->responseCookies[$key] ?? null; } /** * Set Max Filesize * - * @access public - * @param $bytes + * @param $bytes */ public function setMaxFilesize($bytes) { @@ -868,9 +865,7 @@ class Curl extends BaseCurl /** * Set Cookie String * - * @access public - * @param $string - * + * @param $string * @return bool */ public function setCookieString($string) @@ -881,10 +876,8 @@ class Curl extends BaseCurl /** * Set Cookie File * - * @access public - * @param $cookie_file - * - * @return boolean + * @param $cookie_file + * @return bool */ public function setCookieFile($cookie_file) { @@ -894,10 +887,8 @@ class Curl extends BaseCurl /** * Set Cookie Jar * - * @access public - * @param $cookie_jar - * - * @return boolean + * @param $cookie_jar + * @return bool */ public function setCookieJar($cookie_jar) { @@ -907,10 +898,9 @@ class Curl extends BaseCurl /** * Set Default JSON Decoder * - * @access public - * @param $assoc - * @param $depth - * @param $options + * @param $assoc + * @param $depth + * @param $options */ public function setDefaultJsonDecoder() { @@ -921,11 +911,10 @@ class Curl extends BaseCurl /** * Set Default XML Decoder * - * @access public - * @param $class_name - * @param $options - * @param $ns - * @param $is_prefix + * @param $class_name + * @param $options + * @param $ns + * @param $is_prefix */ public function setDefaultXmlDecoder() { @@ -936,8 +925,7 @@ class Curl extends BaseCurl /** * Set Default Decoder * - * @access public - * @param $mixed boolean|callable|string + * @param $mixed boolean|callable|string */ public function setDefaultDecoder($mixed = 'json') { @@ -954,36 +942,50 @@ class Curl extends BaseCurl /** * Set Default Header Out - * - * @access public */ public function setDefaultHeaderOut() { $this->setOpt(CURLINFO_HEADER_OUT, true); } + private function setDefaultHeaderOutInternal() + { + $this->setOptInternal(CURLINFO_HEADER_OUT, true); + } + /** * Set Default Timeout - * - * @access public */ public function setDefaultTimeout() { $this->setTimeout(self::DEFAULT_TIMEOUT); } + private function setDefaultTimeoutInternal() + { + $this->setTimeoutInternal(self::DEFAULT_TIMEOUT); + } + /** * Set Default User Agent - * - * @access public */ public function setDefaultUserAgent() + { + $this->setUserAgent($this->getDefaultUserAgent()); + } + + private function setDefaultUserAgentInternal() + { + $this->setUserAgentInternal($this->getDefaultUserAgent()); + } + + private function getDefaultUserAgent() { $user_agent = 'PHP-Curl-Class/' . self::VERSION . ' (+https://github.com/php-curl-class/php-curl-class)'; $user_agent .= ' PHP/' . PHP_VERSION; $curl_version = curl_version(); $user_agent .= ' curl/' . $curl_version['version']; - $this->setUserAgent($user_agent); + return $user_agent; } /** @@ -991,9 +993,8 @@ class Curl extends BaseCurl * * Add extra header to include in the request. * - * @access public - * @param $key - * @param $value + * @param $key + * @param $value */ public function setHeader($key, $value) { @@ -1010,8 +1011,7 @@ class Curl extends BaseCurl * * Add extra headers to include in the request. * - * @access public - * @param $headers + * @param $headers */ public function setHeaders($headers) { @@ -1041,8 +1041,7 @@ class Curl extends BaseCurl /** * Set JSON Decoder * - * @access public - * @param $mixed boolean|callable + * @param $mixed boolean|callable */ public function setJsonDecoder($mixed) { @@ -1055,8 +1054,7 @@ class Curl extends BaseCurl /** * Set XML Decoder * - * @access public - * @param $mixed boolean|callable + * @param $mixed boolean|callable */ public function setXmlDecoder($mixed) { @@ -1069,11 +1067,9 @@ class Curl extends BaseCurl /** * Set Opt * - * @access public - * @param $option - * @param $value - * - * @return boolean + * @param $option + * @param $value + * @return bool */ public function setOpt($option, $value) { @@ -1085,6 +1081,23 @@ class Curl extends BaseCurl trigger_error($required_options[$option] . ' is a required option', E_USER_WARNING); } + $success = curl_setopt($this->curl, $option, $value); + if ($success) { + $this->options[$option] = $value; + $this->userSetOptions[$option] = $value; + } + return $success; + } + + /** + * Set Opt Internal + * + * @param $option + * @param $value + * @return bool + */ + protected function setOptInternal($option, $value) + { $success = curl_setopt($this->curl, $option, $value); if ($success) { $this->options[$option] = $value; @@ -1095,15 +1108,18 @@ class Curl extends BaseCurl /** * Set Opts * - * @access public - * @param $options - * - * @return boolean - * Returns true if all options were successfully set. If an option could not be successfully set, false is - * immediately returned, ignoring any future options in the options array. Similar to curl_setopt_array(). + * @param $options + * @return bool + * Returns true if all options were successfully set. If an + * option could not be successfully set, false is immediately + * returned, ignoring any future options in the options array. + * Similar to curl_setopt_array(). */ public function setOpts($options) { + if (!count($options)) { + return true; + } foreach ($options as $option => $value) { if (!$this->setOpt($option, $value)) { return false; @@ -1117,8 +1133,7 @@ class Curl extends BaseCurl * * Limit what protocols libcurl will accept for a request. * - * @access public - * @param $protocols + * @param $protocols * @see Curl::setRedirectProtocols() */ public function setProtocols($protocols) @@ -1126,6 +1141,11 @@ class Curl extends BaseCurl $this->setOpt(CURLOPT_PROTOCOLS, $protocols); } + private function setProtocolsInternal($protocols) + { + $this->setOptInternal(CURLOPT_PROTOCOLS, $protocols); + } + /** * Set Retry * @@ -1137,8 +1157,7 @@ class Curl extends BaseCurl * When using a callable decider, the request will be retried until the * function returns a value which evaluates to false. * - * @access public - * @param $mixed + * @param $mixed */ public function setRetry($mixed) { @@ -1155,8 +1174,7 @@ class Curl extends BaseCurl * * Limit what protocols libcurl will accept when following a redirect. * - * @access public - * @param $redirect_protocols + * @param $redirect_protocols * @see Curl::setProtocols() */ public function setRedirectProtocols($redirect_protocols) @@ -1164,12 +1182,16 @@ class Curl extends BaseCurl $this->setOpt(CURLOPT_REDIR_PROTOCOLS, $redirect_protocols); } + private function setRedirectProtocolsInternal($redirect_protocols) + { + $this->setOptInternal(CURLOPT_REDIR_PROTOCOLS, $redirect_protocols); + } + /** * Set Url * - * @access public - * @param $url - * @param $mixed_data + * @param $url + * @param $mixed_data */ public function setUrl($url, $mixed_data = '') { @@ -1186,8 +1208,6 @@ class Curl extends BaseCurl /** * Attempt Retry - * - * @access public */ public function attemptRetry() { @@ -1213,8 +1233,7 @@ class Curl extends BaseCurl * * Remove extra header previously set using Curl::setHeader(). * - * @access public - * @param $key + * @param $key */ public function unsetHeader($key) { @@ -1229,8 +1248,7 @@ class Curl extends BaseCurl /** * Diagnose * - * @access public - * @param bool $return + * @param bool $return */ public function diagnose($return = false) { @@ -1249,7 +1267,7 @@ class Curl extends BaseCurl if ($this->attempts === 0) { echo 'No HTTP requests have been made.' . "\n"; } else { - $request_types = array( + $request_types = [ 'DELETE' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'DELETE', 'GET' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'GET' || $this->getOpt(CURLOPT_HTTPGET), 'HEAD' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'HEAD', @@ -1258,7 +1276,7 @@ class Curl extends BaseCurl 'POST' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'POST' || $this->getOpt(CURLOPT_POST), 'PUT' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'PUT', 'SEARCH' => $this->getOpt(CURLOPT_CUSTOMREQUEST) === 'SEARCH', - ); + ]; $request_method = ''; foreach ($request_types as $http_method_name => $http_method_used) { if ($http_method_used) { @@ -1270,8 +1288,7 @@ class Curl extends BaseCurl $request_options_count = count($this->options); $request_headers_count = count($this->requestHeaders); $request_body_empty = empty($this->getOpt(CURLOPT_POSTFIELDS)); - $response_header_length = isset($this->responseHeaders['Content-Length']) ? - $this->responseHeaders['Content-Length'] : '(not specified in response header)'; + $response_header_length = $this->responseHeaders['Content-Length'] ?? '(not specified in response header)'; $response_calculated_length = is_string($this->rawResponse) ? strlen($this->rawResponse) : '(' . var_export($this->rawResponse, true) . ')'; $response_headers_count = count($this->responseHeaders); @@ -1284,30 +1301,13 @@ class Curl extends BaseCurl $i = 1; foreach ($this->options as $option => $value) { echo ' ' . $i . ' '; - if (isset($this->curlOptionCodeConstants[$option])) { - echo $this->curlOptionCodeConstants[$option] . ':'; - } else { - echo $option . ':'; - } - - if (is_string($value)) { - echo ' ' . $value . "\n"; - } elseif (is_int($value)) { - echo ' ' . $value . "\n"; - } elseif (is_bool($value)) { - echo ' ' . ($value ? 'true' : 'false') . "\n"; - } elseif (is_callable($value)) { - echo ' (callable)' . "\n"; - } else { - echo ' ' . gettype($value) . ':' . "\n"; - var_dump($value); - } + $this->displayCurlOptionValue($option, $value); $i += 1; } } echo - 'Sent an HTTP ' . $request_method . ' request to "' . $request_url . '".' . "\n" . + 'Sent an HTTP ' . $request_method . ' request to "' . $request_url . '".' . "\n" . 'Request contained ' . $request_headers_count . ' ' . ( $request_headers_count === 1 ? 'header:' : 'headers:' ) . "\n"; @@ -1321,10 +1321,12 @@ class Curl extends BaseCurl echo 'Request contained ' . ($request_body_empty ? 'no body' : 'a body') . '.' . "\n"; - if ($request_headers_count === 0 && ( + if ( + $request_headers_count === 0 && ( $this->getOpt(CURLOPT_VERBOSE) || !$this->getOpt(CURLINFO_HEADER_OUT) - )) { + ) + ) { echo 'Warning: Request headers (Curl::requestHeaders) are expected to be empty ' . '(CURLOPT_VERBOSE was enabled or CURLINFO_HEADER_OUT was disabled).' . "\n"; @@ -1337,8 +1339,8 @@ class Curl extends BaseCurl foreach ($request_types as $http_method_name => $http_method_used) { if ($http_method_used && !in_array($http_method_name, $allowed_request_types, true)) { echo - 'Warning: A ' . $http_method_name . ' request was made, but only the following request ' . - 'types are allowed: ' . implode(', ', $allowed_request_types) . "\n"; + 'Warning: An HTTP ' . $http_method_name . ' request was made, but only the following ' . + 'request types are allowed: ' . implode(', ', $allowed_request_types) . "\n"; } } } @@ -1389,7 +1391,10 @@ class Curl extends BaseCurl echo 'Response content length (calculated): ' . $response_calculated_length . "\n"; } - if (preg_match($this->jsonPattern, $this->responseHeaders['Content-Type'])) { + if ( + isset($this->responseHeaders['Content-Type']) && + preg_match($this->jsonPattern, $this->responseHeaders['Content-Type']) + ) { $parsed_response = json_decode($this->rawResponse, true); if ($parsed_response !== null) { $messages = []; @@ -1430,8 +1435,6 @@ class Curl extends BaseCurl /** * Reset - * - * @access public */ public function reset() { @@ -1441,9 +1444,9 @@ class Curl extends BaseCurl $this->curl = curl_init(); } - $this->setDefaultUserAgent(); - $this->setDefaultTimeout(); - $this->setDefaultHeaderOut(); + $this->setDefaultUserAgentInternal(); + $this->setDefaultTimeoutInternal(); + $this->setDefaultHeaderOutInternal(); $this->initialize(); } @@ -1508,6 +1511,16 @@ class Curl extends BaseCurl return $this->url; } + public function getOptions() + { + return $this->options; + } + + public function getUserSetOptions() + { + return $this->userSetOptions; + } + public function getRequestHeaders() { return $this->requestHeaders; @@ -1610,8 +1623,6 @@ class Curl extends BaseCurl /** * Destruct - * - * @access public */ public function __destruct() { @@ -1621,8 +1632,10 @@ class Curl extends BaseCurl public function __get($name) { $return = null; - if (in_array($name, self::$deferredProperties, true) && - is_callable([$this, $getter = '_get' . ucfirst($name)])) { + if ( + in_array($name, self::$deferredProperties, true) && + is_callable([$this, $getter = 'get' . ucfirst($name)]) + ) { $return = $this->$name = $this->$getter(); } return $return; @@ -1630,10 +1643,8 @@ class Curl extends BaseCurl /** * Get Curl Error Code Constants - * - * @access private */ - private function _getCurlErrorCodeConstants() + private function getCurlErrorCodeConstants() { $constants = get_defined_constants(true); $filtered_array = array_filter( @@ -1649,10 +1660,8 @@ class Curl extends BaseCurl /** * Get Curl Error Code Constant - * - * @access private */ - private function _getCurlErrorCodeConstant() + private function getCurlErrorCodeConstant() { $curl_const_by_code = $this->curlErrorCodeConstants; if (isset($curl_const_by_code[$this->curlErrorCode])) { @@ -1663,10 +1672,8 @@ class Curl extends BaseCurl /** * Get Curl Option Code Constants - * - * @access private */ - private function _getCurlOptionCodeConstants() + private function getCurlOptionCodeConstants() { $constants = get_defined_constants(true); $filtered_array = array_filter( @@ -1686,49 +1693,118 @@ class Curl extends BaseCurl } /** - * Get Effective Url + * Display Curl Option Value. * - * @access private + * @param $option + * @param $value */ - private function _getEffectiveUrl() + public function displayCurlOptionValue($option, $value = null) + { + if ($value === null) { + $value = $this->getOpt($option); + } + + if (isset($this->curlOptionCodeConstants[$option])) { + echo $this->curlOptionCodeConstants[$option] . ':'; + } else { + echo $option . ':'; + } + + if (is_string($value)) { + echo ' "' . $value . '"' . "\n"; + } elseif (is_int($value)) { + echo ' ' . $value; + + $bit_flag_lookups = [ + 'CURLOPT_HTTPAUTH' => 'CURLAUTH_', + 'CURLOPT_PROTOCOLS' => 'CURLPROTO_', + 'CURLOPT_PROXYAUTH' => 'CURLAUTH_', + 'CURLOPT_PROXY_SSL_OPTIONS' => 'CURLSSLOPT_', + 'CURLOPT_REDIR_PROTOCOLS' => 'CURLPROTO_', + 'CURLOPT_SSH_AUTH_TYPES' => 'CURLSSH_AUTH_', + 'CURLOPT_SSL_OPTIONS' => 'CURLSSLOPT_', + ]; + if (isset($this->curlOptionCodeConstants[$option])) { + $option_name = $this->curlOptionCodeConstants[$option]; + if (in_array($option_name, array_keys($bit_flag_lookups), true)) { + $curl_const_prefix = $bit_flag_lookups[$option_name]; + $constants = get_defined_constants(true); + $curl_constants = array_filter( + $constants['curl'], + function ($key) use ($curl_const_prefix) { + return strpos($key, $curl_const_prefix) !== false; + }, + ARRAY_FILTER_USE_KEY + ); + + $bit_flags = []; + foreach ($curl_constants as $const_name => $const_value) { + // Attempt to detect bit flags in use that use constants with negative values (e.g. + // CURLAUTH_ANY, CURLAUTH_ANYSAFE, CURLPROTO_ALL, CURLSSH_AUTH_ANY, + // CURLSSH_AUTH_DEFAULT, etc.) + if ($value < 0 && $value === $const_value) { + $bit_flags[] = $const_name; + break; + } elseif ($value >= 0 && $const_value >= 0 && ($value & $const_value)) { + $bit_flags[] = $const_name; + } + } + + if (count($bit_flags)) { + asort($bit_flags); + echo ' (' . implode(' | ', $bit_flags) . ')'; + } + } + } + + echo "\n"; + } elseif (is_bool($value)) { + echo ' ' . ($value ? 'true' : 'false') . "\n"; + } elseif (is_array($value)) { + echo ' '; + var_dump($value); + } elseif (is_callable($value)) { + echo ' (callable)' . "\n"; + } else { + echo ' ' . gettype($value) . ':' . "\n"; + var_dump($value); + } + } + + /** + * Get Effective Url + */ + private function getEffectiveUrl() { return $this->getInfo(CURLINFO_EFFECTIVE_URL); } /** * Get RFC 2616 - * - * @access private */ - private function _getRfc2616() + private function getRfc2616() { return array_fill_keys(self::$RFC2616, true); } /** * Get RFC 6265 - * - * @access private */ - private function _getRfc6265() + private function getRfc6265() { return array_fill_keys(self::$RFC6265, true); } /** * Get Total Time - * - * @access private */ - private function _getTotalTime() + private function getTotalTime() { return $this->getInfo(CURLINFO_TOTAL_TIME); } /** * Build Cookies - * - * @access private */ private function buildCookies() { @@ -1745,8 +1821,7 @@ class Curl extends BaseCurl /** * Download Complete * - * @access private - * @param $fh + * @param $fh */ private function downloadComplete($fh) { @@ -1782,9 +1857,7 @@ class Curl extends BaseCurl /** * Parse Headers * - * @access private - * @param $raw_headers - * + * @param $raw_headers * @return array */ private function parseHeaders($raw_headers) @@ -1807,15 +1880,13 @@ class Curl extends BaseCurl } } - return [isset($raw_headers['0']) ? $raw_headers['0'] : '', $http_headers]; + return [$raw_headers['0'] ?? '', $http_headers]; } /** * Parse Request Headers * - * @access private - * @param $raw_headers - * + * @param $raw_headers * @return \Curl\CaseInsensitiveArray */ private function parseRequestHeaders($raw_headers) @@ -1832,21 +1903,21 @@ class Curl extends BaseCurl /** * Parse Response * - * @access private - * @param $response_headers - * @param $raw_response - * + * @param $response_headers + * @param $raw_response * @return mixed - * If the response content-type is json: - * Returns the json decoder's return value: A stdClass object when the default json decoder is used. - * If the response content-type is xml: - * Returns the xml decoder's return value: A SimpleXMLElement object when the default xml decoder is used. - * If the response content-type is something else: - * Returns the original raw response unless a default decoder has been set. - * If the response content-type cannot be determined: - * Returns the original raw response. - * If the response content-encoding is gzip: - * Returns the response gzip-decoded. + * If the response content-type is json: Returns the json decoder's return value: A stdClass object + * when the default json decoder is used. + * + * If the response content-type is xml: Returns the xml decoder's return value: A SimpleXMLElement + * object when the default xml decoder is used. + * + * If the response content-type is something else: Returns the original raw response unless a default + * decoder has been set. + * + * If the response content-type cannot be determined: Returns the original raw response. + * + * If the response content-encoding is gzip: Returns the response gzip-decoded. */ private function parseResponse($response_headers, $raw_response) { @@ -1871,8 +1942,35 @@ class Curl extends BaseCurl } } - if (isset($response_headers['Content-Encoding']) && $response_headers['Content-Encoding'] === 'gzip' && - is_string($response)) { + if ( + ( + // Ensure that the server says the response is compressed with + // gzip and the response has not already been decoded. Use + // is_string() to ensure that $response is a string being passed + // to mb_strpos() and gzdecode(). Use extension_loaded() to + // ensure that mb_strpos() uses the mbstring extension and not a + // polyfill. + isset($response_headers['Content-Encoding']) && + $response_headers['Content-Encoding'] === 'gzip' && + is_string($response) && + ( + ( + extension_loaded('mbstring') && + mb_strpos($response, "\x1f" . "\x8b" . "\x08", 0, 'US-ASCII') === 0 + ) || + !extension_loaded('mbstring') + ) + ) || ( + // Or ensure that the response looks like it is compressed with + // gzip. Use is_string() to ensure that $response is a string + // being passed to mb_strpos() and gzdecode(). Use + // extension_loaded() to ensure that mb_strpos() uses the + // mbstring extension and not a polyfill. + is_string($response) && + extension_loaded('mbstring') && + mb_strpos($response, "\x1f" . "\x8b" . "\x08", 0, 'US-ASCII') === 0 + ) + ) { // Use @ to suppress message "Warning gzdecode(): data error". $decoded_response = @gzdecode($response); if ($decoded_response !== false) { @@ -1886,15 +1984,13 @@ class Curl extends BaseCurl /** * Parse Response Headers * - * @access private - * @param $raw_response_headers - * + * @param $raw_response_headers * @return \Curl\CaseInsensitiveArray */ private function parseResponseHeaders($raw_response_headers) { $response_header_array = explode("\r\n\r\n", $raw_response_headers); - $response_header = ''; + $response_header = ''; for ($i = count($response_header_array) - 1; $i >= 0; $i--) { if (isset($response_header_array[$i]) && stripos($response_header_array[$i], 'HTTP/') === 0) { $response_header = $response_header_array[$i]; @@ -1914,9 +2010,8 @@ class Curl extends BaseCurl /** * Set Encoded Cookie * - * @access private - * @param $key - * @param $value + * @param $key + * @param $value */ private function setEncodedCookie($key, $value) { @@ -1944,32 +2039,32 @@ class Curl extends BaseCurl /** * Initialize * - * @access private - * @param $base_url + * @param $base_url + * @param mixed $options */ private function initialize($base_url = null, $options = []) { - $this->setProtocols(CURLPROTO_HTTPS | CURLPROTO_HTTP); - $this->setRedirectProtocols(CURLPROTO_HTTPS | CURLPROTO_HTTP); + $this->setProtocolsInternal(CURLPROTO_HTTPS | CURLPROTO_HTTP); + $this->setRedirectProtocolsInternal(CURLPROTO_HTTPS | CURLPROTO_HTTP); if (isset($options)) { $this->setOpts($options); } - $this->id = uniqid('', true); + $this->id = bin2hex(random_bytes(16)); // Only set default user agent if not already set. if (!array_key_exists(CURLOPT_USERAGENT, $this->options)) { - $this->setDefaultUserAgent(); + $this->setDefaultUserAgentInternal(); } // Only set default timeout if not already set. if (!array_key_exists(CURLOPT_TIMEOUT, $this->options)) { - $this->setDefaultTimeout(); + $this->setDefaultTimeoutInternal(); } if (!array_key_exists(CURLINFO_HEADER_OUT, $this->options)) { - $this->setDefaultHeaderOut(); + $this->setDefaultHeaderOutInternal(); } // Create a placeholder to temporarily store the header callback data. @@ -1979,10 +2074,10 @@ class Curl extends BaseCurl $header_callback_data->stopRequestDecider = null; $header_callback_data->stopRequest = false; $this->headerCallbackData = $header_callback_data; - $this->setStop(); - $this->setOpt(CURLOPT_HEADERFUNCTION, createHeaderCallback($header_callback_data)); + $this->setStopInternal(); + $this->setOptInternal(CURLOPT_HEADERFUNCTION, createHeaderCallback($header_callback_data)); - $this->setOpt(CURLOPT_RETURNTRANSFER, true); + $this->setOptInternal(CURLOPT_RETURNTRANSFER, true); $this->headers = new CaseInsensitiveArray(); if ($base_url !== null) { @@ -2007,8 +2102,7 @@ class Curl extends BaseCurl * callback and instead just check the value of stopRequest for attempting * to stop the request as used by Curl::stop(). * - * @access public - * @param $callback callable|null + * @param $callback callable|null */ public function setStop($callback = null) { @@ -2019,14 +2113,21 @@ class Curl extends BaseCurl $this->progress(createStopRequestFunction($header_callback_data)); } + private function setStopInternal($callback = null) + { + $this->headerCallbackData->stopRequestDecider = $callback; + $this->headerCallbackData->stopRequest = false; + + $header_callback_data = $this->headerCallbackData; + $this->progressInternal(createStopRequestFunction($header_callback_data)); + } + /** * Stop * * Attempt to stop request. * * Used by MultiCurl::stop() when making multiple parallel requests. - * - * @access public */ public function stop() { @@ -2041,8 +2142,7 @@ class Curl extends BaseCurl * unset($curl) automatically calls __destruct() as expected. Otherwise, manually calling $curl->close() will be * necessary to prevent a memory leak. * - * @param $header_callback_data - * + * @param $header_callback_data * @return callable */ function createHeaderCallback($header_callback_data) @@ -2071,8 +2171,7 @@ function createHeaderCallback($header_callback_data) * stopRequest flag is on. Keep this function separate from the class to prevent * a memory leak. * - * @param $header_callback_data - * + * @param $header_callback_data * @return callable */ function createStopRequestFunction($header_callback_data) diff --git a/vendor/php-curl-class/php-curl-class/src/Curl/Decoder.php b/vendor/php-curl-class/php-curl-class/src/Curl/Decoder.php index 603f4c3..5f98219 100644 --- a/vendor/php-curl-class/php-curl-class/src/Curl/Decoder.php +++ b/vendor/php-curl-class/php-curl-class/src/Curl/Decoder.php @@ -1,4 +1,6 @@ -queuedCurls as $curl_id => $curl) { - if (!isset($this->instanceSpecificOptions[$curl_id][$option]) || - $this->instanceSpecificOptions[$curl_id][$option] === null) { + if ( + !isset($this->instanceSpecificOptions[$curl_id][$option]) || + $this->instanceSpecificOptions[$curl_id][$option] === null + ) { $this->instanceSpecificOptions[$curl_id][$option] = $value; } } @@ -568,8 +534,7 @@ class MultiCurl extends BaseCurl /** * Set Opts * - * @access public - * @param $options + * @param $options */ public function setOpts($options) { @@ -581,8 +546,7 @@ class MultiCurl extends BaseCurl /** * Set Rate Limit * - * @access public - * @param $rate_limit string (e.g. "60/1m"). + * @param $rate_limit string (e.g. "60/1m"). * @throws \UnexpectedValueException */ public function setRateLimit($rate_limit) @@ -641,8 +605,7 @@ class MultiCurl extends BaseCurl * When using a callable decider, the request will be retried until the * function returns a value which evaluates to false. * - * @access public - * @param $mixed + * @param $mixed */ public function setRetry($mixed) { @@ -652,9 +615,8 @@ class MultiCurl extends BaseCurl /** * Set Url * - * @access public - * @param $url - * @param $mixed_data + * @param $url + * @param $mixed_data */ public function setUrl($url, $mixed_data = '') { @@ -672,7 +634,6 @@ class MultiCurl extends BaseCurl /** * Start * - * @access public * @throws \ErrorException */ public function start() @@ -687,7 +648,8 @@ class MultiCurl extends BaseCurl $this->currentRequestCount = 0; do { - while (count($this->queuedCurls) && + while ( + count($this->queuedCurls) && count($this->activeCurls) < $this->concurrency && (!$this->rateLimitEnabled || $this->hasRequestQuota()) ) { @@ -733,8 +695,10 @@ class MultiCurl extends BaseCurl } } - while ((is_resource($this->multiCurl) || $this->multiCurl instanceof \CurlMultiHandle) && - (($info_array = curl_multi_info_read($this->multiCurl)) !== false)) { + while ( + (is_resource($this->multiCurl) || $this->multiCurl instanceof \CurlMultiHandle) && + (($info_array = curl_multi_info_read($this->multiCurl)) !== false) + ) { if ($info_array['msg'] === CURLMSG_DONE) { foreach ($this->activeCurls as $key => $curl) { if ($curl->curl === $info_array['handle']) { @@ -782,8 +746,6 @@ class MultiCurl extends BaseCurl /** * Stop - * - * @access public */ public function stop() { @@ -810,8 +772,7 @@ class MultiCurl extends BaseCurl * * Remove extra header previously set using Curl::setHeader(). * - * @access public - * @param $key + * @param $key */ public function unsetHeader($key) { @@ -820,8 +781,6 @@ class MultiCurl extends BaseCurl /** * Set request time accuracy - * - * @access public */ public function setRequestTimeAccuracy() { @@ -830,8 +789,6 @@ class MultiCurl extends BaseCurl /** * Destruct - * - * @access public */ public function __destruct() { @@ -840,8 +797,6 @@ class MultiCurl extends BaseCurl /** * Update Headers - * - * @access private */ private function updateHeaders() { @@ -853,8 +808,7 @@ class MultiCurl extends BaseCurl /** * Queue Handle * - * @access private - * @param $curl + * @param $curl */ private function queueHandle($curl) { @@ -863,14 +817,16 @@ class MultiCurl extends BaseCurl $curl->childOfMultiCurl = true; $this->queuedCurls[$curl->id] = $curl; - $curl->setHeaders($this->headers); + // Avoid overwriting any existing header. + if ($curl->getOpt(CURLOPT_HTTPHEADER) === null) { + $curl->setHeaders($this->headers); + } } /** * Init Handle * - * @access private - * @param $curl + * @param $curl * @throws \ErrorException */ private function initHandle() @@ -888,6 +844,9 @@ class MultiCurl extends BaseCurl if ($curl->beforeSendCallback === null) { $curl->beforeSend($this->beforeSendCallback); } + if ($curl->afterSendCallback === null) { + $curl->afterSend($this->afterSendCallback); + } if ($curl->successCallback === null) { $curl->success($this->successCallback); } @@ -934,8 +893,6 @@ class MultiCurl extends BaseCurl * * Checks if there is any available quota to make additional requests while * rate limiting is enabled. - * - * @access private */ private function hasRequestQuota() { @@ -965,8 +922,6 @@ class MultiCurl extends BaseCurl * Wait Until Request Quota Available * * Waits until there is available request quota available based on the rate limit. - * - * @access private */ private function waitUntilRequestQuotaAvailable() { diff --git a/vendor/php-curl-class/php-curl-class/src/Curl/StringUtil.php b/vendor/php-curl-class/php-curl-class/src/Curl/StringUtil.php index 86341f9..cc7c68b 100644 --- a/vendor/php-curl-class/php-curl-class/src/Curl/StringUtil.php +++ b/vendor/php-curl-class/php-curl-class/src/Curl/StringUtil.php @@ -1,4 +1,6 @@ -relativeUrl = $relative_url; } - public function __toString() : string + public function __toString(): string { return $this->absolutizeUrl(); } @@ -24,6 +24,8 @@ class Url * Remove dot segments. * * Interpret and remove the special "." and ".." path segments from a referenced path. + * + * @param mixed $input */ public static function removeDotSegments($input) { @@ -87,10 +89,8 @@ class Url /** * Build Url * - * @access public - * @param $url - * @param $mixed_data - * + * @param $url + * @param $mixed_data * @return string */ public static function buildUrl($url, $mixed_data = '') @@ -127,29 +127,29 @@ class Url $target = []; if (isset($r['scheme'])) { $target['scheme'] = $r['scheme']; - $target['host'] = isset($r['host']) ? $r['host'] : null; - $target['port'] = isset($r['port']) ? $r['port'] : null; - $target['user'] = isset($r['user']) ? $r['user'] : null; - $target['pass'] = isset($r['pass']) ? $r['pass'] : null; + $target['host'] = $r['host'] ?? null; + $target['port'] = $r['port'] ?? null; + $target['user'] = $r['user'] ?? null; + $target['pass'] = $r['pass'] ?? null; $target['path'] = isset($r['path']) ? self::removeDotSegments($r['path']) : null; - $target['query'] = isset($r['query']) ? $r['query'] : null; + $target['query'] = $r['query'] ?? null; } else { - $target['scheme'] = isset($b['scheme']) ? $b['scheme'] : null; + $target['scheme'] = $b['scheme'] ?? null; if ($r['authorized']) { - $target['host'] = isset($r['host']) ? $r['host'] : null; - $target['port'] = isset($r['port']) ? $r['port'] : null; - $target['user'] = isset($r['user']) ? $r['user'] : null; - $target['pass'] = isset($r['pass']) ? $r['pass'] : null; + $target['host'] = $r['host'] ?? null; + $target['port'] = $r['port'] ?? null; + $target['user'] = $r['user'] ?? null; + $target['pass'] = $r['pass'] ?? null; $target['path'] = isset($r['path']) ? self::removeDotSegments($r['path']) : null; - $target['query'] = isset($r['query']) ? $r['query'] : null; + $target['query'] = $r['query'] ?? null; } else { - $target['host'] = isset($b['host']) ? $b['host'] : null; - $target['port'] = isset($b['port']) ? $b['port'] : null; - $target['user'] = isset($b['user']) ? $b['user'] : null; - $target['pass'] = isset($b['pass']) ? $b['pass'] : null; + $target['host'] = $b['host'] ?? null; + $target['port'] = $b['port'] ?? null; + $target['user'] = $b['user'] ?? null; + $target['pass'] = $b['pass'] ?? null; if (!isset($r['path']) || $r['path'] === '') { $target['path'] = $b['path']; - $target['query'] = isset($r['query']) ? $r['query'] : (isset($b['query']) ? $b['query'] : null); + $target['query'] = $r['query'] ?? $b['query'] ?? null; } else { if (StringUtil::startsWith($r['path'], '/')) { $target['path'] = self::removeDotSegments($r['path']); @@ -160,14 +160,14 @@ class Url } $target['path'] = self::removeDotSegments($base . '/' . $r['path']); } - $target['query'] = isset($r['query']) ? $r['query'] : null; + $target['query'] = $r['query'] ?? null; } } } if ($this->relativeUrl === '') { - $target['fragment'] = isset($b['fragment']) ? $b['fragment'] : null; + $target['fragment'] = $b['fragment'] ?? null; } else { - $target['fragment'] = isset($r['fragment']) ? $r['fragment'] : null; + $target['fragment'] = $r['fragment'] ?? null; } $absolutized_url = $this->unparseUrl($target); return $absolutized_url; @@ -177,6 +177,8 @@ class Url * Parse url. * * Parse url into components of a URI as specified by RFC 3986. + * + * @param mixed $url */ public static function parseUrl($url) { @@ -192,6 +194,8 @@ class Url * * Percent-encode characters to represent a data octet in a component when * that octet's corresponding character is outside the allowed set. + * + * @param mixed $chars */ private static function percentEncodeChars($chars) { @@ -229,16 +233,18 @@ class Url * Unparse url. * * Combine url components into a url. + * + * @param mixed $parsed_url */ private function unparseUrl($parsed_url) { $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : ''; - $user = isset($parsed_url['user']) ? $parsed_url['user'] : ''; + $user = $parsed_url['user'] ?? ''; $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : ''; $pass = ($user || $pass) ? $pass . '@' : ''; - $host = isset($parsed_url['host']) ? $parsed_url['host'] : ''; + $host = $parsed_url['host'] ?? ''; $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : ''; - $path = isset($parsed_url['path']) ? $parsed_url['path'] : ''; + $path = $parsed_url['path'] ?? ''; $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : ''; $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : ''; $unparsed_url = $scheme . $user . $pass . $host . $port . $path . $query . $fragment; diff --git a/vendor/services.php b/vendor/services.php index 92505cd..a22babf 100644 --- a/vendor/services.php +++ b/vendor/services.php @@ -1,5 +1,5 @@ 'think\\trace\\Service', diff --git a/vendor/symfony/cache-contracts/CHANGELOG.md b/vendor/symfony/cache-contracts/CHANGELOG.md new file mode 100644 index 0000000..7932e26 --- /dev/null +++ b/vendor/symfony/cache-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/vendor/symfony/cache-contracts/CacheInterface.php b/vendor/symfony/cache-contracts/CacheInterface.php new file mode 100644 index 0000000..70cb0d5 --- /dev/null +++ b/vendor/symfony/cache-contracts/CacheInterface.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\CacheItemInterface; +use Psr\Cache\InvalidArgumentException; + +/** + * Covers most simple to advanced caching needs. + * + * @author Nicolas Grekas
+ */ +interface CacheInterface +{ + /** + * Fetches a value from the pool or computes it if not found. + * + * On cache misses, a callback is called that should return the missing value. + * This callback is given a PSR-6 CacheItemInterface instance corresponding to the + * requested key, that could be used e.g. for expiration control. It could also + * be an ItemInterface instance when its additional features are needed. + * + * @param string $key The key of the item to retrieve from the cache + * @param callable|CallbackInterface $callback Should return the computed value for the given key/item + * @param float|null $beta A float that, as it grows, controls the likeliness of triggering + * early expiration. 0 disables it, INF forces immediate expiration. + * The default (or providing null) is implementation dependent but should + * typically be 1.0, which should provide optimal stampede protection. + * See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration + * @param array &$metadata The metadata of the cached item {@see ItemInterface::getMetadata()} + * + * @return mixed + * + * @throws InvalidArgumentException When $key is not valid or when $beta is negative + */ + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null); + + /** + * Removes an item from the pool. + * + * @param string $key The key to delete + * + * @return bool True if the item was successfully removed, false if there was any error + * + * @throws InvalidArgumentException When $key is not valid + */ + public function delete(string $key): bool; +} diff --git a/vendor/symfony/cache-contracts/CacheTrait.php b/vendor/symfony/cache-contracts/CacheTrait.php new file mode 100644 index 0000000..b9feafb --- /dev/null +++ b/vendor/symfony/cache-contracts/CacheTrait.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\CacheItemPoolInterface; +use Psr\Cache\InvalidArgumentException; +use Psr\Log\LoggerInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(InvalidArgumentException::class); + +/** + * An implementation of CacheInterface for PSR-6 CacheItemPoolInterface classes. + * + * @author Nicolas Grekas
+ */ +trait CacheTrait +{ + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null) + { + return $this->doGet($this, $key, $callback, $beta, $metadata); + } + + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + return $this->deleteItem($key); + } + + private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null, ?LoggerInterface $logger = null) + { + if (0 > $beta = $beta ?? 1.0) { + throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException { }; + } + + $item = $pool->getItem($key); + $recompute = !$item->isHit() || \INF === $beta; + $metadata = $item instanceof ItemInterface ? $item->getMetadata() : []; + + if (!$recompute && $metadata) { + $expiry = $metadata[ItemInterface::METADATA_EXPIRY] ?? false; + $ctime = $metadata[ItemInterface::METADATA_CTIME] ?? false; + + if ($recompute = $ctime && $expiry && $expiry <= ($now = microtime(true)) - $ctime / 1000 * $beta * log(random_int(1, \PHP_INT_MAX) / \PHP_INT_MAX)) { + // force applying defaultLifetime to expiry + $item->expiresAt(null); + $logger && $logger->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [ + 'key' => $key, + 'delta' => sprintf('%.1f', $expiry - $now), + ]); + } + } + + if ($recompute) { + $save = true; + $item->set($callback($item, $save)); + if ($save) { + $pool->save($item); + } + } + + return $item->get(); + } +} diff --git a/vendor/symfony/cache-contracts/CallbackInterface.php b/vendor/symfony/cache-contracts/CallbackInterface.php new file mode 100644 index 0000000..7dae2aa --- /dev/null +++ b/vendor/symfony/cache-contracts/CallbackInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\CacheItemInterface; + +/** + * Computes and returns the cached value of an item. + * + * @author Nicolas Grekas
+ */ +interface CallbackInterface +{ + /** + * @param CacheItemInterface|ItemInterface $item The item to compute the value for + * @param bool &$save Should be set to false when the value should not be saved in the pool + * + * @return mixed The computed value for the passed item + */ + public function __invoke(CacheItemInterface $item, bool &$save); +} diff --git a/vendor/symfony/cache-contracts/ItemInterface.php b/vendor/symfony/cache-contracts/ItemInterface.php new file mode 100644 index 0000000..10c0488 --- /dev/null +++ b/vendor/symfony/cache-contracts/ItemInterface.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\CacheException; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\InvalidArgumentException; + +/** + * Augments PSR-6's CacheItemInterface with support for tags and metadata. + * + * @author Nicolas Grekas
+ */ +interface ItemInterface extends CacheItemInterface +{ + /** + * References the Unix timestamp stating when the item will expire. + */ + public const METADATA_EXPIRY = 'expiry'; + + /** + * References the time the item took to be created, in milliseconds. + */ + public const METADATA_CTIME = 'ctime'; + + /** + * References the list of tags that were assigned to the item, as string[]. + */ + public const METADATA_TAGS = 'tags'; + + /** + * Reserved characters that cannot be used in a key or tag. + */ + public const RESERVED_CHARACTERS = '{}()/\@:'; + + /** + * Adds a tag to a cache item. + * + * Tags are strings that follow the same validation rules as keys. + * + * @param string|string[] $tags A tag or array of tags + * + * @return $this + * + * @throws InvalidArgumentException When $tag is not valid + * @throws CacheException When the item comes from a pool that is not tag-aware + */ + public function tag($tags): self; + + /** + * Returns a list of metadata info that were saved alongside with the cached value. + * + * See ItemInterface::METADATA_* consts for keys potentially found in the returned array. + */ + public function getMetadata(): array; +} diff --git a/vendor/symfony/polyfill-php72/LICENSE b/vendor/symfony/cache-contracts/LICENSE similarity index 95% rename from vendor/symfony/polyfill-php72/LICENSE rename to vendor/symfony/cache-contracts/LICENSE index 4cd8bdd..7536cae 100644 --- a/vendor/symfony/polyfill-php72/LICENSE +++ b/vendor/symfony/cache-contracts/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/cache-contracts/README.md b/vendor/symfony/cache-contracts/README.md new file mode 100644 index 0000000..7085a69 --- /dev/null +++ b/vendor/symfony/cache-contracts/README.md @@ -0,0 +1,9 @@ +Symfony Cache Contracts +======================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/vendor/symfony/cache-contracts/TagAwareCacheInterface.php b/vendor/symfony/cache-contracts/TagAwareCacheInterface.php new file mode 100644 index 0000000..7c4cf11 --- /dev/null +++ b/vendor/symfony/cache-contracts/TagAwareCacheInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\InvalidArgumentException; + +/** + * Allows invalidating cached items using tags. + * + * @author Nicolas Grekas
+ */ +interface TagAwareCacheInterface extends CacheInterface +{ + /** + * Invalidates cached items using tags. + * + * When implemented on a PSR-6 pool, invalidation should not apply + * to deferred items. Instead, they should be committed as usual. + * This allows replacing old tagged values by new ones without + * race conditions. + * + * @param string[] $tags An array of tags to invalidate + * + * @return bool True on success + * + * @throws InvalidArgumentException When $tags is not valid + */ + public function invalidateTags(array $tags); +} diff --git a/vendor/symfony/cache-contracts/composer.json b/vendor/symfony/cache-contracts/composer.json new file mode 100644 index 0000000..9f45e17 --- /dev/null +++ b/vendor/symfony/cache-contracts/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/cache-contracts", + "type": "library", + "description": "Generic abstractions related to caching", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Cache\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/vendor/symfony/cache/Adapter/AbstractAdapter.php b/vendor/symfony/cache/Adapter/AbstractAdapter.php new file mode 100644 index 0000000..de5af17 --- /dev/null +++ b/vendor/symfony/cache/Adapter/AbstractAdapter.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\CacheInterface; + +/** + * @author Nicolas Grekas
+ */ +abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface +{ + use AbstractAdapterTrait; + use ContractsTrait; + + /** + * @internal + */ + protected const NS_SEPARATOR = ':'; + + private static $apcuSupported; + private static $phpFilesSupported; + + protected function __construct(string $namespace = '', int $defaultLifetime = 0) + { + $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR; + $this->defaultLifetime = $defaultLifetime; + if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { + throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); + } + self::$createCacheItem ?? self::$createCacheItem = \Closure::bind( + static function ($key, $value, $isHit) { + $item = new CacheItem(); + $item->key = $key; + $item->value = $v = $value; + $item->isHit = $isHit; + // Detect wrapped values that encode for their expiry and creation duration + // For compactness, these values are packed in the key of an array using + // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { + $item->value = $v[$k]; + $v = unpack('Ve/Nc', substr($k, 1, -1)); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } + + return $item; + }, + null, + CacheItem::class + ); + self::$mergeByLifetime ?? self::$mergeByLifetime = \Closure::bind( + static function ($deferred, $namespace, &$expiredIds, $getId, $defaultLifetime) { + $byLifetime = []; + $now = microtime(true); + $expiredIds = []; + + foreach ($deferred as $key => $item) { + $key = (string) $key; + if (null === $item->expiry) { + $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0; + } elseif (!$item->expiry) { + $ttl = 0; + } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) { + $expiredIds[] = $getId($key); + continue; + } + if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) { + unset($metadata[CacheItem::METADATA_TAGS]); + } + // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators + $byLifetime[$ttl][$getId($key)] = $metadata ? ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item->value] : $item->value; + } + + return $byLifetime; + }, + null, + CacheItem::class + ); + } + + /** + * Returns the best possible adapter that your runtime supports. + * + * Using ApcuAdapter makes system caches compatible with read-only filesystems. + * + * @return AdapterInterface + */ + public static function createSystemCache(string $namespace, int $defaultLifetime, string $version, string $directory, ?LoggerInterface $logger = null) + { + $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true); + if (null !== $logger) { + $opcache->setLogger($logger); + } + + if (!self::$apcuSupported = self::$apcuSupported ?? ApcuAdapter::isSupported()) { + return $opcache; + } + + if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) { + return $opcache; + } + + $apcu = new ApcuAdapter($namespace, intdiv($defaultLifetime, 5), $version); + if (null !== $logger) { + $apcu->setLogger($logger); + } + + return new ChainAdapter([$apcu, $opcache]); + } + + public static function createConnection(string $dsn, array $options = []) + { + if (str_starts_with($dsn, 'redis:') || str_starts_with($dsn, 'rediss:')) { + return RedisAdapter::createConnection($dsn, $options); + } + if (str_starts_with($dsn, 'memcached:')) { + return MemcachedAdapter::createConnection($dsn, $options); + } + if (0 === strpos($dsn, 'couchbase:')) { + if (CouchbaseBucketAdapter::isSupported()) { + return CouchbaseBucketAdapter::createConnection($dsn, $options); + } + + return CouchbaseCollectionAdapter::createConnection($dsn, $options); + } + + throw new InvalidArgumentException('Unsupported DSN: it does not start with "redis[s]:", "memcached:" nor "couchbase:".'); + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function commit() + { + $ok = true; + $byLifetime = (self::$mergeByLifetime)($this->deferred, $this->namespace, $expiredIds, \Closure::fromCallable([$this, 'getId']), $this->defaultLifetime); + $retry = $this->deferred = []; + + if ($expiredIds) { + try { + $this->doDelete($expiredIds); + } catch (\Exception $e) { + $ok = false; + CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } + } + foreach ($byLifetime as $lifetime => $values) { + try { + $e = $this->doSave($values, $lifetime); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + if (\is_array($e) || 1 === \count($values)) { + foreach (\is_array($e) ? $e : array_keys($values) as $id) { + $ok = false; + $v = $values[$id]; + $type = get_debug_type($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); + } + } else { + foreach ($values as $id => $v) { + $retry[$lifetime][] = $id; + } + } + } + + // When bulk-save failed, retry each item individually + foreach ($retry as $lifetime => $ids) { + foreach ($ids as $id) { + try { + $v = $byLifetime[$lifetime][$id]; + $e = $this->doSave([$id => $v], $lifetime); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + $ok = false; + $type = get_debug_type($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); + } + } + + return $ok; + } +} diff --git a/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php new file mode 100644 index 0000000..a384b16 --- /dev/null +++ b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php @@ -0,0 +1,330 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Log\LoggerAwareInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + +/** + * Abstract for native TagAware adapters. + * + * To keep info on tags, the tags are both serialized as part of cache value and provided as tag ids + * to Adapters on operations when needed for storage to doSave(), doDelete() & doInvalidate(). + * + * @author Nicolas Grekas
+ * @author André Rømcke
+ */
+class ApcuAdapter extends AbstractAdapter
+{
+ private $marshaller;
+
+ /**
+ * @throws CacheException if APCu is not enabled
+ */
+ public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $version = null, ?MarshallerInterface $marshaller = null)
+ {
+ if (!static::isSupported()) {
+ throw new CacheException('APCu is not enabled.');
+ }
+ if ('cli' === \PHP_SAPI) {
+ ini_set('apc.use_request_time', 0);
+ }
+ parent::__construct($namespace, $defaultLifetime);
+
+ if (null !== $version) {
+ CacheItem::validateKey($version);
+
+ if (!apcu_exists($version.'@'.$namespace)) {
+ $this->doClear($namespace);
+ apcu_add($version.'@'.$namespace, null);
+ }
+ }
+
+ $this->marshaller = $marshaller;
+ }
+
+ public static function isSupported()
+ {
+ return \function_exists('apcu_fetch') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch(array $ids)
+ {
+ $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
+ try {
+ $values = [];
+ $ids = array_flip($ids);
+ foreach (apcu_fetch(array_keys($ids), $ok) ?: [] as $k => $v) {
+ if (!isset($ids[$k])) {
+ // work around https://github.com/krakjoe/apcu/issues/247
+ $k = key($ids);
+ }
+ unset($ids[$k]);
+
+ if (null !== $v || $ok) {
+ $values[$k] = null !== $this->marshaller ? $this->marshaller->unmarshall($v) : $v;
+ }
+ }
+
+ return $values;
+ } catch (\Error $e) {
+ throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
+ } finally {
+ ini_set('unserialize_callback_func', $unserializeCallbackHandler);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doHave(string $id)
+ {
+ return apcu_exists($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doClear(string $namespace)
+ {
+ return isset($namespace[0]) && class_exists(\APCUIterator::class, false) && ('cli' !== \PHP_SAPI || filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))
+ ? apcu_delete(new \APCUIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY))
+ : apcu_clear_cache();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete(array $ids)
+ {
+ foreach ($ids as $id) {
+ apcu_delete($id);
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave(array $values, int $lifetime)
+ {
+ if (null !== $this->marshaller && (!$values = $this->marshaller->marshall($values, $failed))) {
+ return $failed;
+ }
+
+ try {
+ if (false === $failures = apcu_store($values, null, $lifetime)) {
+ $failures = $values;
+ }
+
+ return array_keys($failures);
+ } catch (\Throwable $e) {
+ if (1 === \count($values)) {
+ // Workaround https://github.com/krakjoe/apcu/issues/170
+ apcu_delete(array_key_first($values));
+ }
+
+ throw $e;
+ }
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/ArrayAdapter.php b/vendor/symfony/cache/Adapter/ArrayAdapter.php
new file mode 100644
index 0000000..b251814
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/ArrayAdapter.php
@@ -0,0 +1,407 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Psr\Cache\CacheItemInterface;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerAwareTrait;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Contracts\Cache\CacheInterface;
+
+/**
+ * An in-memory cache storage.
+ *
+ * Acts as a least-recently-used (LRU) storage when configured with a maximum number of items.
+ *
+ * @author Nicolas Grekas
+ */
+class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface
+{
+ use LoggerAwareTrait;
+
+ private $storeSerialized;
+ private $values = [];
+ private $expiries = [];
+ private $defaultLifetime;
+ private $maxLifetime;
+ private $maxItems;
+
+ private static $createCacheItem;
+
+ /**
+ * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise
+ */
+ public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true, float $maxLifetime = 0, int $maxItems = 0)
+ {
+ if (0 > $maxLifetime) {
+ throw new InvalidArgumentException(sprintf('Argument $maxLifetime must be positive, %F passed.', $maxLifetime));
+ }
+
+ if (0 > $maxItems) {
+ throw new InvalidArgumentException(sprintf('Argument $maxItems must be a positive integer, %d passed.', $maxItems));
+ }
+
+ $this->defaultLifetime = $defaultLifetime;
+ $this->storeSerialized = $storeSerialized;
+ $this->maxLifetime = $maxLifetime;
+ $this->maxItems = $maxItems;
+ self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
+ static function ($key, $value, $isHit) {
+ $item = new CacheItem();
+ $item->key = $key;
+ $item->value = $value;
+ $item->isHit = $isHit;
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null)
+ {
+ $item = $this->getItem($key);
+ $metadata = $item->getMetadata();
+
+ // ArrayAdapter works in memory, we don't care about stampede protection
+ if (\INF === $beta || !$item->isHit()) {
+ $save = true;
+ $item->set($callback($item, $save));
+ if ($save) {
+ $this->save($item);
+ }
+ }
+
+ return $item->get();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete(string $key): bool
+ {
+ return $this->deleteItem($key);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function hasItem($key)
+ {
+ if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) {
+ if ($this->maxItems) {
+ // Move the item last in the storage
+ $value = $this->values[$key];
+ unset($this->values[$key]);
+ $this->values[$key] = $value;
+ }
+
+ return true;
+ }
+ \assert('' !== CacheItem::validateKey($key));
+
+ return isset($this->expiries[$key]) && !$this->deleteItem($key);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItem($key)
+ {
+ if (!$isHit = $this->hasItem($key)) {
+ $value = null;
+
+ if (!$this->maxItems) {
+ // Track misses in non-LRU mode only
+ $this->values[$key] = null;
+ }
+ } else {
+ $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
+ }
+
+ return (self::$createCacheItem)($key, $value, $isHit);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItems(array $keys = [])
+ {
+ \assert(self::validateKeys($keys));
+
+ return $this->generateItems($keys, microtime(true), self::$createCacheItem);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItem($key)
+ {
+ \assert('' !== CacheItem::validateKey($key));
+ unset($this->values[$key], $this->expiries[$key]);
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItems(array $keys)
+ {
+ foreach ($keys as $key) {
+ $this->deleteItem($key);
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function save(CacheItemInterface $item)
+ {
+ if (!$item instanceof CacheItem) {
+ return false;
+ }
+ $item = (array) $item;
+ $key = $item["\0*\0key"];
+ $value = $item["\0*\0value"];
+ $expiry = $item["\0*\0expiry"];
+
+ $now = microtime(true);
+
+ if (null !== $expiry) {
+ if (!$expiry) {
+ $expiry = \PHP_INT_MAX;
+ } elseif ($expiry <= $now) {
+ $this->deleteItem($key);
+
+ return true;
+ }
+ }
+ if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
+ return false;
+ }
+ if (null === $expiry && 0 < $this->defaultLifetime) {
+ $expiry = $this->defaultLifetime;
+ $expiry = $now + ($expiry > ($this->maxLifetime ?: $expiry) ? $this->maxLifetime : $expiry);
+ } elseif ($this->maxLifetime && (null === $expiry || $expiry > $now + $this->maxLifetime)) {
+ $expiry = $now + $this->maxLifetime;
+ }
+
+ if ($this->maxItems) {
+ unset($this->values[$key]);
+
+ // Iterate items and vacuum expired ones while we are at it
+ foreach ($this->values as $k => $v) {
+ if ($this->expiries[$k] > $now && \count($this->values) < $this->maxItems) {
+ break;
+ }
+
+ unset($this->values[$k], $this->expiries[$k]);
+ }
+ }
+
+ $this->values[$key] = $value;
+ $this->expiries[$key] = $expiry ?? \PHP_INT_MAX;
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function saveDeferred(CacheItemInterface $item)
+ {
+ return $this->save($item);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function commit()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function clear(string $prefix = '')
+ {
+ if ('' !== $prefix) {
+ $now = microtime(true);
+
+ foreach ($this->values as $key => $value) {
+ if (!isset($this->expiries[$key]) || $this->expiries[$key] <= $now || 0 === strpos($key, $prefix)) {
+ unset($this->values[$key], $this->expiries[$key]);
+ }
+ }
+
+ if ($this->values) {
+ return true;
+ }
+ }
+
+ $this->values = $this->expiries = [];
+
+ return true;
+ }
+
+ /**
+ * Returns all cached values, with cache miss as null.
+ *
+ * @return array
+ */
+ public function getValues()
+ {
+ if (!$this->storeSerialized) {
+ return $this->values;
+ }
+
+ $values = $this->values;
+ foreach ($values as $k => $v) {
+ if (null === $v || 'N;' === $v) {
+ continue;
+ }
+ if (!\is_string($v) || !isset($v[2]) || ':' !== $v[1]) {
+ $values[$k] = serialize($v);
+ }
+ }
+
+ return $values;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset()
+ {
+ $this->clear();
+ }
+
+ private function generateItems(array $keys, float $now, \Closure $f): \Generator
+ {
+ foreach ($keys as $i => $key) {
+ if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) {
+ $value = null;
+
+ if (!$this->maxItems) {
+ // Track misses in non-LRU mode only
+ $this->values[$key] = null;
+ }
+ } else {
+ if ($this->maxItems) {
+ // Move the item last in the storage
+ $value = $this->values[$key];
+ unset($this->values[$key]);
+ $this->values[$key] = $value;
+ }
+
+ $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
+ }
+ unset($keys[$i]);
+
+ yield $key => $f($key, $value, $isHit);
+ }
+
+ foreach ($keys as $key) {
+ yield $key => $f($key, null, false);
+ }
+ }
+
+ private function freeze($value, string $key)
+ {
+ if (null === $value) {
+ return 'N;';
+ }
+ if (\is_string($value)) {
+ // Serialize strings if they could be confused with serialized objects or arrays
+ if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
+ return serialize($value);
+ }
+ } elseif (!\is_scalar($value)) {
+ try {
+ $serialized = serialize($value);
+ } catch (\Exception $e) {
+ unset($this->values[$key]);
+ $type = get_debug_type($value);
+ $message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage());
+ CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]);
+
+ return;
+ }
+ // Keep value serialized if it contains any objects or any internal references
+ if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) {
+ return $serialized;
+ }
+ }
+
+ return $value;
+ }
+
+ private function unfreeze(string $key, bool &$isHit)
+ {
+ if ('N;' === $value = $this->values[$key]) {
+ return null;
+ }
+ if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
+ try {
+ $value = unserialize($value);
+ } catch (\Exception $e) {
+ CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]);
+ $value = false;
+ }
+ if (false === $value) {
+ $value = null;
+ $isHit = false;
+
+ if (!$this->maxItems) {
+ $this->values[$key] = null;
+ }
+ }
+ }
+
+ return $value;
+ }
+
+ private function validateKeys(array $keys): bool
+ {
+ foreach ($keys as $key) {
+ if (!\is_string($key) || !isset($this->expiries[$key])) {
+ CacheItem::validateKey($key);
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/ChainAdapter.php b/vendor/symfony/cache/Adapter/ChainAdapter.php
new file mode 100644
index 0000000..7d95528
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/ChainAdapter.php
@@ -0,0 +1,342 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Psr\Cache\CacheItemInterface;
+use Psr\Cache\CacheItemPoolInterface;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Component\Cache\Traits\ContractsTrait;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Service\ResetInterface;
+
+/**
+ * Chains several adapters together.
+ *
+ * Cached items are fetched from the first adapter having them in its data store.
+ * They are saved and deleted in all adapters at once.
+ *
+ * @author Kévin Dunglas
+ *
+ * @deprecated Since Symfony 5.4, use Doctrine\Common\Cache\Psr6\CacheAdapter instead
+ */
+class DoctrineAdapter extends AbstractAdapter
+{
+ private $provider;
+
+ public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0)
+ {
+ trigger_deprecation('symfony/cache', '5.4', '"%s" is deprecated, use "%s" instead.', __CLASS__, CacheAdapter::class);
+
+ parent::__construct('', $defaultLifetime);
+ $this->provider = $provider;
+ $provider->setNamespace($namespace);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->provider->setNamespace($this->provider->getNamespace());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch(array $ids)
+ {
+ $unserializeCallbackHandler = ini_set('unserialize_callback_func', parent::class.'::handleUnserializeCallback');
+ try {
+ return $this->provider->fetchMultiple($ids);
+ } catch (\Error $e) {
+ $trace = $e->getTrace();
+
+ if (isset($trace[0]['function']) && !isset($trace[0]['class'])) {
+ switch ($trace[0]['function']) {
+ case 'unserialize':
+ case 'apcu_fetch':
+ case 'apc_fetch':
+ throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
+ }
+ }
+
+ throw $e;
+ } finally {
+ ini_set('unserialize_callback_func', $unserializeCallbackHandler);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doHave(string $id)
+ {
+ return $this->provider->contains($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doClear(string $namespace)
+ {
+ $namespace = $this->provider->getNamespace();
+
+ return isset($namespace[0])
+ ? $this->provider->deleteAll()
+ : $this->provider->flushAll();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete(array $ids)
+ {
+ $ok = true;
+ foreach ($ids as $id) {
+ $ok = $this->provider->delete($id) && $ok;
+ }
+
+ return $ok;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave(array $values, int $lifetime)
+ {
+ return $this->provider->saveMultiple($values, $lifetime);
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/DoctrineDbalAdapter.php b/vendor/symfony/cache/Adapter/DoctrineDbalAdapter.php
new file mode 100644
index 0000000..c126824
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/DoctrineDbalAdapter.php
@@ -0,0 +1,448 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Doctrine\DBAL\ArrayParameterType;
+use Doctrine\DBAL\Configuration;
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
+use Doctrine\DBAL\DriverManager;
+use Doctrine\DBAL\Exception as DBALException;
+use Doctrine\DBAL\Exception\TableNotFoundException;
+use Doctrine\DBAL\ParameterType;
+use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\ServerVersionProvider;
+use Doctrine\DBAL\Tools\DsnParser;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\PruneableInterface;
+
+class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface
+{
+ protected $maxIdLength = 255;
+
+ private $marshaller;
+ private $conn;
+ private $platformName;
+ private $serverVersion;
+ private $table = 'cache_items';
+ private $idCol = 'item_id';
+ private $dataCol = 'item_data';
+ private $lifetimeCol = 'item_lifetime';
+ private $timeCol = 'item_time';
+ private $namespace;
+
+ /**
+ * You can either pass an existing database Doctrine DBAL Connection or
+ * a DSN string that will be used to connect to the database.
+ *
+ * The cache table is created automatically when possible.
+ * Otherwise, use the createTable() method.
+ *
+ * List of available options:
+ * * db_table: The name of the table [default: cache_items]
+ * * db_id_col: The column where to store the cache id [default: item_id]
+ * * db_data_col: The column where to store the cache data [default: item_data]
+ * * db_lifetime_col: The column where to store the lifetime [default: item_lifetime]
+ * * db_time_col: The column where to store the timestamp [default: item_time]
+ *
+ * @param Connection|string $connOrDsn
+ *
+ * @throws InvalidArgumentException When namespace contains invalid characters
+ */
+ public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null)
+ {
+ if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) {
+ throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0]));
+ }
+
+ if ($connOrDsn instanceof Connection) {
+ $this->conn = $connOrDsn;
+ } elseif (\is_string($connOrDsn)) {
+ if (!class_exists(DriverManager::class)) {
+ throw new InvalidArgumentException('Failed to parse DSN. Try running "composer require doctrine/dbal".');
+ }
+ if (class_exists(DsnParser::class)) {
+ $params = (new DsnParser([
+ 'db2' => 'ibm_db2',
+ 'mssql' => 'pdo_sqlsrv',
+ 'mysql' => 'pdo_mysql',
+ 'mysql2' => 'pdo_mysql',
+ 'postgres' => 'pdo_pgsql',
+ 'postgresql' => 'pdo_pgsql',
+ 'pgsql' => 'pdo_pgsql',
+ 'sqlite' => 'pdo_sqlite',
+ 'sqlite3' => 'pdo_sqlite',
+ ]))->parse($connOrDsn);
+ } else {
+ $params = ['url' => $connOrDsn];
+ }
+
+ $config = new Configuration();
+ if (class_exists(DefaultSchemaManagerFactory::class)) {
+ $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory());
+ }
+
+ $this->conn = DriverManager::getConnection($params, $config);
+ } else {
+ throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be "%s" or string, "%s" given.', __METHOD__, Connection::class, get_debug_type($connOrDsn)));
+ }
+
+ $this->table = $options['db_table'] ?? $this->table;
+ $this->idCol = $options['db_id_col'] ?? $this->idCol;
+ $this->dataCol = $options['db_data_col'] ?? $this->dataCol;
+ $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol;
+ $this->timeCol = $options['db_time_col'] ?? $this->timeCol;
+ $this->namespace = $namespace;
+ $this->marshaller = $marshaller ?? new DefaultMarshaller();
+
+ parent::__construct($namespace, $defaultLifetime);
+ }
+
+ /**
+ * Creates the table to store cache items which can be called once for setup.
+ *
+ * Cache ID are saved in a column of maximum length 255. Cache data is
+ * saved in a BLOB.
+ *
+ * @throws DBALException When the table already exists
+ */
+ public function createTable()
+ {
+ $schema = new Schema();
+ $this->addTableToSchema($schema);
+
+ foreach ($schema->toSql($this->conn->getDatabasePlatform()) as $sql) {
+ $this->conn->executeStatement($sql);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function configureSchema(Schema $schema, Connection $forConnection): void
+ {
+ // only update the schema for this connection
+ if ($forConnection !== $this->conn) {
+ return;
+ }
+
+ if ($schema->hasTable($this->table)) {
+ return;
+ }
+
+ $this->addTableToSchema($schema);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prune(): bool
+ {
+ $deleteSql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ?";
+ $params = [time()];
+ $paramTypes = [ParameterType::INTEGER];
+
+ if ('' !== $this->namespace) {
+ $deleteSql .= " AND $this->idCol LIKE ?";
+ $params[] = sprintf('%s%%', $this->namespace);
+ $paramTypes[] = ParameterType::STRING;
+ }
+
+ try {
+ $this->conn->executeStatement($deleteSql, $params, $paramTypes);
+ } catch (TableNotFoundException $e) {
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch(array $ids): iterable
+ {
+ $now = time();
+ $expired = [];
+
+ $sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN (?)";
+ $result = $this->conn->executeQuery($sql, [
+ $now,
+ $ids,
+ ], [
+ ParameterType::INTEGER,
+ class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY,
+ ])->iterateNumeric();
+
+ foreach ($result as $row) {
+ if (null === $row[1]) {
+ $expired[] = $row[0];
+ } else {
+ yield $row[0] => $this->marshaller->unmarshall(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]);
+ }
+ }
+
+ if ($expired) {
+ $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN (?)";
+ $this->conn->executeStatement($sql, [
+ $now,
+ $expired,
+ ], [
+ ParameterType::INTEGER,
+ class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY,
+ ]);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doHave(string $id): bool
+ {
+ $sql = "SELECT 1 FROM $this->table WHERE $this->idCol = ? AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ?)";
+ $result = $this->conn->executeQuery($sql, [
+ $id,
+ time(),
+ ], [
+ ParameterType::STRING,
+ ParameterType::INTEGER,
+ ]);
+
+ return (bool) $result->fetchOne();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doClear(string $namespace): bool
+ {
+ if ('' === $namespace) {
+ if ('sqlite' === $this->getPlatformName()) {
+ $sql = "DELETE FROM $this->table";
+ } else {
+ $sql = "TRUNCATE TABLE $this->table";
+ }
+ } else {
+ $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'";
+ }
+
+ try {
+ $this->conn->executeStatement($sql);
+ } catch (TableNotFoundException $e) {
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete(array $ids): bool
+ {
+ $sql = "DELETE FROM $this->table WHERE $this->idCol IN (?)";
+ try {
+ $this->conn->executeStatement($sql, [array_values($ids)], [class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY]);
+ } catch (TableNotFoundException $e) {
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave(array $values, int $lifetime)
+ {
+ if (!$values = $this->marshaller->marshall($values, $failed)) {
+ return $failed;
+ }
+
+ $platformName = $this->getPlatformName();
+ $insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?)";
+
+ switch (true) {
+ case 'mysql' === $platformName:
+ $sql = $insertSql." ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)";
+ break;
+ case 'oci' === $platformName:
+ // DUAL is Oracle specific dummy table
+ $sql = "MERGE INTO $this->table USING DUAL ON ($this->idCol = ?) ".
+ "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ".
+ "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?";
+ break;
+ case 'sqlsrv' === $platformName && version_compare($this->getServerVersion(), '10', '>='):
+ // MERGE is only available since SQL Server 2008 and must be terminated by semicolon
+ // It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx
+ $sql = "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = ?) ".
+ "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ".
+ "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;";
+ break;
+ case 'sqlite' === $platformName:
+ $sql = 'INSERT OR REPLACE'.substr($insertSql, 6);
+ break;
+ case 'pgsql' === $platformName && version_compare($this->getServerVersion(), '9.5', '>='):
+ $sql = $insertSql." ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)";
+ break;
+ default:
+ $platformName = null;
+ $sql = "UPDATE $this->table SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ? WHERE $this->idCol = ?";
+ break;
+ }
+
+ $now = time();
+ $lifetime = $lifetime ?: null;
+ try {
+ $stmt = $this->conn->prepare($sql);
+ } catch (TableNotFoundException $e) {
+ if (!$this->conn->isTransactionActive() || \in_array($platformName, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
+ $this->createTable();
+ }
+ $stmt = $this->conn->prepare($sql);
+ }
+
+ if ('sqlsrv' === $platformName || 'oci' === $platformName) {
+ $bind = static function ($id, $data) use ($stmt) {
+ $stmt->bindValue(1, $id);
+ $stmt->bindValue(2, $id);
+ $stmt->bindValue(3, $data, ParameterType::LARGE_OBJECT);
+ $stmt->bindValue(6, $data, ParameterType::LARGE_OBJECT);
+ };
+ $stmt->bindValue(4, $lifetime, ParameterType::INTEGER);
+ $stmt->bindValue(5, $now, ParameterType::INTEGER);
+ $stmt->bindValue(7, $lifetime, ParameterType::INTEGER);
+ $stmt->bindValue(8, $now, ParameterType::INTEGER);
+ } elseif (null !== $platformName) {
+ $bind = static function ($id, $data) use ($stmt) {
+ $stmt->bindValue(1, $id);
+ $stmt->bindValue(2, $data, ParameterType::LARGE_OBJECT);
+ };
+ $stmt->bindValue(3, $lifetime, ParameterType::INTEGER);
+ $stmt->bindValue(4, $now, ParameterType::INTEGER);
+ } else {
+ $stmt->bindValue(2, $lifetime, ParameterType::INTEGER);
+ $stmt->bindValue(3, $now, ParameterType::INTEGER);
+
+ $insertStmt = $this->conn->prepare($insertSql);
+ $insertStmt->bindValue(3, $lifetime, ParameterType::INTEGER);
+ $insertStmt->bindValue(4, $now, ParameterType::INTEGER);
+
+ $bind = static function ($id, $data) use ($stmt, $insertStmt) {
+ $stmt->bindValue(1, $data, ParameterType::LARGE_OBJECT);
+ $stmt->bindValue(4, $id);
+ $insertStmt->bindValue(1, $id);
+ $insertStmt->bindValue(2, $data, ParameterType::LARGE_OBJECT);
+ };
+ }
+
+ foreach ($values as $id => $data) {
+ $bind($id, $data);
+ try {
+ $rowCount = $stmt->executeStatement();
+ } catch (TableNotFoundException $e) {
+ if (!$this->conn->isTransactionActive() || \in_array($platformName, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
+ $this->createTable();
+ }
+ $rowCount = $stmt->executeStatement();
+ }
+ if (null === $platformName && 0 === $rowCount) {
+ try {
+ $insertStmt->executeStatement();
+ } catch (DBALException $e) {
+ // A concurrent write won, let it be
+ }
+ }
+ }
+
+ return $failed;
+ }
+
+ /**
+ * @internal
+ */
+ protected function getId($key)
+ {
+ if ('pgsql' !== $this->getPlatformName()) {
+ return parent::getId($key);
+ }
+
+ if (str_contains($key, "\0") || str_contains($key, '%') || !preg_match('//u', $key)) {
+ $key = rawurlencode($key);
+ }
+
+ return parent::getId($key);
+ }
+
+ private function getPlatformName(): string
+ {
+ if (isset($this->platformName)) {
+ return $this->platformName;
+ }
+
+ $platform = $this->conn->getDatabasePlatform();
+
+ switch (true) {
+ case $platform instanceof \Doctrine\DBAL\Platforms\MySQLPlatform:
+ case $platform instanceof \Doctrine\DBAL\Platforms\MySQL57Platform:
+ return $this->platformName = 'mysql';
+
+ case $platform instanceof \Doctrine\DBAL\Platforms\SqlitePlatform:
+ return $this->platformName = 'sqlite';
+
+ case $platform instanceof \Doctrine\DBAL\Platforms\PostgreSQLPlatform:
+ case $platform instanceof \Doctrine\DBAL\Platforms\PostgreSQL94Platform:
+ return $this->platformName = 'pgsql';
+
+ case $platform instanceof \Doctrine\DBAL\Platforms\OraclePlatform:
+ return $this->platformName = 'oci';
+
+ case $platform instanceof \Doctrine\DBAL\Platforms\SQLServerPlatform:
+ case $platform instanceof \Doctrine\DBAL\Platforms\SQLServer2012Platform:
+ return $this->platformName = 'sqlsrv';
+
+ default:
+ return $this->platformName = \get_class($platform);
+ }
+ }
+
+ private function getServerVersion(): string
+ {
+ if (isset($this->serverVersion)) {
+ return $this->serverVersion;
+ }
+
+ if ($this->conn instanceof ServerVersionProvider || $this->conn instanceof ServerInfoAwareConnection) {
+ return $this->serverVersion = $this->conn->getServerVersion();
+ }
+
+ // The condition should be removed once support for DBAL <3.3 is dropped
+ $conn = method_exists($this->conn, 'getNativeConnection') ? $this->conn->getNativeConnection() : $this->conn->getWrappedConnection();
+
+ return $this->serverVersion = $conn->getAttribute(\PDO::ATTR_SERVER_VERSION);
+ }
+
+ private function addTableToSchema(Schema $schema): void
+ {
+ $types = [
+ 'mysql' => 'binary',
+ 'sqlite' => 'text',
+ ];
+
+ $table = $schema->createTable($this->table);
+ $table->addColumn($this->idCol, $types[$this->getPlatformName()] ?? 'string', ['length' => 255]);
+ $table->addColumn($this->dataCol, 'blob', ['length' => 16777215]);
+ $table->addColumn($this->lifetimeCol, 'integer', ['unsigned' => true, 'notnull' => false]);
+ $table->addColumn($this->timeCol, 'integer', ['unsigned' => true]);
+ $table->setPrimaryKey([$this->idCol]);
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/FilesystemAdapter.php b/vendor/symfony/cache/Adapter/FilesystemAdapter.php
new file mode 100644
index 0000000..13daa56
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/FilesystemAdapter.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\Cache\Traits\FilesystemTrait;
+
+class FilesystemAdapter extends AbstractAdapter implements PruneableInterface
+{
+ use FilesystemTrait;
+
+ public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, ?MarshallerInterface $marshaller = null)
+ {
+ $this->marshaller = $marshaller ?? new DefaultMarshaller();
+ parent::__construct('', $defaultLifetime);
+ $this->init($namespace, $directory);
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php
new file mode 100644
index 0000000..440a37a
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php
@@ -0,0 +1,239 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\Cache\Traits\FilesystemTrait;
+
+/**
+ * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls.
+ *
+ * @author Nicolas Grekas
+ * @author André Rømcke
+ */
+class MemcachedAdapter extends AbstractAdapter
+{
+ /**
+ * We are replacing characters that are illegal in Memcached keys with reserved characters from
+ * {@see \Symfony\Contracts\Cache\ItemInterface::RESERVED_CHARACTERS} that are legal in Memcached.
+ * Note: don’t use {@see \Symfony\Component\Cache\Adapter\AbstractAdapter::NS_SEPARATOR}.
+ */
+ private const RESERVED_MEMCACHED = " \n\r\t\v\f\0";
+ private const RESERVED_PSR6 = '@()\{}/';
+
+ protected $maxIdLength = 250;
+
+ private $marshaller;
+ private $client;
+ private $lazyClient;
+
+ /**
+ * Using a MemcachedAdapter with a TagAwareAdapter for storing tags is discouraged.
+ * Using a RedisAdapter is recommended instead. If you cannot do otherwise, be aware that:
+ * - the Memcached::OPT_BINARY_PROTOCOL must be enabled
+ * (that's the default when using MemcachedAdapter::createConnection());
+ * - tags eviction by Memcached's LRU algorithm will break by-tags invalidation;
+ * your Memcached memory should be large enough to never trigger LRU.
+ *
+ * Using a MemcachedAdapter as a pure items store is fine.
+ */
+ public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
+ {
+ if (!static::isSupported()) {
+ throw new CacheException('Memcached '.(\PHP_VERSION_ID >= 80100 ? '> 3.1.5' : '>= 2.2.0').' is required.');
+ }
+ if ('Memcached' === \get_class($client)) {
+ $opt = $client->getOption(\Memcached::OPT_SERIALIZER);
+ if (\Memcached::SERIALIZER_PHP !== $opt && \Memcached::SERIALIZER_IGBINARY !== $opt) {
+ throw new CacheException('MemcachedAdapter: "serializer" option must be "php" or "igbinary".');
+ }
+ $this->maxIdLength -= \strlen($client->getOption(\Memcached::OPT_PREFIX_KEY));
+ $this->client = $client;
+ } else {
+ $this->lazyClient = $client;
+ }
+
+ parent::__construct($namespace, $defaultLifetime);
+ $this->enableVersioning();
+ $this->marshaller = $marshaller ?? new DefaultMarshaller();
+ }
+
+ public static function isSupported()
+ {
+ return \extension_loaded('memcached') && version_compare(phpversion('memcached'), \PHP_VERSION_ID >= 80100 ? '3.1.6' : '2.2.0', '>=');
+ }
+
+ /**
+ * Creates a Memcached instance.
+ *
+ * By default, the binary protocol, no block, and libketama compatible options are enabled.
+ *
+ * Examples for servers:
+ * - 'memcached://user:pass@localhost?weight=33'
+ * - [['localhost', 11211, 33]]
+ *
+ * @param array[]|string|string[] $servers An array of servers, a DSN, or an array of DSNs
+ *
+ * @return \Memcached
+ *
+ * @throws \ErrorException When invalid options or servers are provided
+ */
+ public static function createConnection($servers, array $options = [])
+ {
+ if (\is_string($servers)) {
+ $servers = [$servers];
+ } elseif (!\is_array($servers)) {
+ throw new InvalidArgumentException(sprintf('MemcachedAdapter::createClient() expects array or string as first argument, "%s" given.', get_debug_type($servers)));
+ }
+ if (!static::isSupported()) {
+ throw new CacheException('Memcached '.(\PHP_VERSION_ID >= 80100 ? '> 3.1.5' : '>= 2.2.0').' is required.');
+ }
+ set_error_handler(function ($type, $msg, $file, $line) { throw new \ErrorException($msg, 0, $type, $file, $line); });
+ try {
+ $client = new \Memcached($options['persistent_id'] ?? null);
+ $username = $options['username'] ?? null;
+ $password = $options['password'] ?? null;
+
+ // parse any DSN in $servers
+ foreach ($servers as $i => $dsn) {
+ if (\is_array($dsn)) {
+ continue;
+ }
+ if (!str_starts_with($dsn, 'memcached:')) {
+ throw new InvalidArgumentException('Invalid Memcached DSN: it does not start with "memcached:".');
+ }
+ $params = preg_replace_callback('#^memcached:(//)?(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) {
+ if (!empty($m[2])) {
+ [$username, $password] = explode(':', $m[2], 2) + [1 => null];
+ $username = rawurldecode($username);
+ $password = null !== $password ? rawurldecode($password) : null;
+ }
+
+ return 'file:'.($m[1] ?? '');
+ }, $dsn);
+ if (false === $params = parse_url($params)) {
+ throw new InvalidArgumentException('Invalid Memcached DSN.');
+ }
+ $query = $hosts = [];
+ if (isset($params['query'])) {
+ parse_str($params['query'], $query);
+
+ if (isset($query['host'])) {
+ if (!\is_array($hosts = $query['host'])) {
+ throw new InvalidArgumentException('Invalid Memcached DSN: query parameter "host" must be an array.');
+ }
+ foreach ($hosts as $host => $weight) {
+ if (false === $port = strrpos($host, ':')) {
+ $hosts[$host] = [$host, 11211, (int) $weight];
+ } else {
+ $hosts[$host] = [substr($host, 0, $port), (int) substr($host, 1 + $port), (int) $weight];
+ }
+ }
+ $hosts = array_values($hosts);
+ unset($query['host']);
+ }
+ if ($hosts && !isset($params['host']) && !isset($params['path'])) {
+ unset($servers[$i]);
+ $servers = array_merge($servers, $hosts);
+ continue;
+ }
+ }
+ if (!isset($params['host']) && !isset($params['path'])) {
+ throw new InvalidArgumentException('Invalid Memcached DSN: missing host or path.');
+ }
+ if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) {
+ $params['weight'] = $m[1];
+ $params['path'] = substr($params['path'], 0, -\strlen($m[0]));
+ }
+ $params += [
+ 'host' => $params['host'] ?? $params['path'],
+ 'port' => isset($params['host']) ? 11211 : null,
+ 'weight' => 0,
+ ];
+ if ($query) {
+ $params += $query;
+ $options = $query + $options;
+ }
+
+ $servers[$i] = [$params['host'], $params['port'], $params['weight']];
+
+ if ($hosts) {
+ $servers = array_merge($servers, $hosts);
+ }
+ }
+
+ // set client's options
+ unset($options['persistent_id'], $options['username'], $options['password'], $options['weight'], $options['lazy']);
+ $options = array_change_key_case($options, \CASE_UPPER);
+ $client->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
+ $client->setOption(\Memcached::OPT_NO_BLOCK, true);
+ $client->setOption(\Memcached::OPT_TCP_NODELAY, true);
+ if (!\array_key_exists('LIBKETAMA_COMPATIBLE', $options) && !\array_key_exists(\Memcached::OPT_LIBKETAMA_COMPATIBLE, $options)) {
+ $client->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
+ }
+ foreach ($options as $name => $value) {
+ if (\is_int($name)) {
+ continue;
+ }
+ if ('HASH' === $name || 'SERIALIZER' === $name || 'DISTRIBUTION' === $name) {
+ $value = \constant('Memcached::'.$name.'_'.strtoupper($value));
+ }
+ unset($options[$name]);
+
+ if (\defined('Memcached::OPT_'.$name)) {
+ $options[\constant('Memcached::OPT_'.$name)] = $value;
+ }
+ }
+ $client->setOptions($options + [\Memcached::OPT_SERIALIZER => \Memcached::SERIALIZER_PHP]);
+
+ // set client's servers, taking care of persistent connections
+ if (!$client->isPristine()) {
+ $oldServers = [];
+ foreach ($client->getServerList() as $server) {
+ $oldServers[] = [$server['host'], $server['port']];
+ }
+
+ $newServers = [];
+ foreach ($servers as $server) {
+ if (1 < \count($server)) {
+ $server = array_values($server);
+ unset($server[2]);
+ $server[1] = (int) $server[1];
+ }
+ $newServers[] = $server;
+ }
+
+ if ($oldServers !== $newServers) {
+ $client->resetServerList();
+ $client->addServers($servers);
+ }
+ } else {
+ $client->addServers($servers);
+ }
+
+ if (null !== $username || null !== $password) {
+ if (!method_exists($client, 'setSaslAuthData')) {
+ trigger_error('Missing SASL support: the memcached extension must be compiled with --enable-memcached-sasl.');
+ }
+ $client->setSaslAuthData($username, $password);
+ }
+
+ return $client;
+ } finally {
+ restore_error_handler();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave(array $values, int $lifetime)
+ {
+ if (!$values = $this->marshaller->marshall($values, $failed)) {
+ return $failed;
+ }
+
+ if ($lifetime && $lifetime > 30 * 86400) {
+ $lifetime += time();
+ }
+
+ $encodedValues = [];
+ foreach ($values as $key => $value) {
+ $encodedValues[self::encodeKey($key)] = $value;
+ }
+
+ return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime)) ? $failed : false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch(array $ids)
+ {
+ try {
+ $encodedIds = array_map([__CLASS__, 'encodeKey'], $ids);
+
+ $encodedResult = $this->checkResultCode($this->getClient()->getMulti($encodedIds));
+
+ $result = [];
+ foreach ($encodedResult as $key => $value) {
+ $result[self::decodeKey($key)] = $this->marshaller->unmarshall($value);
+ }
+
+ return $result;
+ } catch (\Error $e) {
+ throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doHave(string $id)
+ {
+ return false !== $this->getClient()->get(self::encodeKey($id)) || $this->checkResultCode(\Memcached::RES_SUCCESS === $this->client->getResultCode());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete(array $ids)
+ {
+ $ok = true;
+ $encodedIds = array_map([__CLASS__, 'encodeKey'], $ids);
+ foreach ($this->checkResultCode($this->getClient()->deleteMulti($encodedIds)) as $result) {
+ if (\Memcached::RES_SUCCESS !== $result && \Memcached::RES_NOTFOUND !== $result) {
+ $ok = false;
+ }
+ }
+
+ return $ok;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doClear(string $namespace)
+ {
+ return '' === $namespace && $this->getClient()->flush();
+ }
+
+ private function checkResultCode($result)
+ {
+ $code = $this->client->getResultCode();
+
+ if (\Memcached::RES_SUCCESS === $code || \Memcached::RES_NOTFOUND === $code) {
+ return $result;
+ }
+
+ throw new CacheException('MemcachedAdapter client error: '.strtolower($this->client->getResultMessage()));
+ }
+
+ private function getClient(): \Memcached
+ {
+ if ($this->client) {
+ return $this->client;
+ }
+
+ $opt = $this->lazyClient->getOption(\Memcached::OPT_SERIALIZER);
+ if (\Memcached::SERIALIZER_PHP !== $opt && \Memcached::SERIALIZER_IGBINARY !== $opt) {
+ throw new CacheException('MemcachedAdapter: "serializer" option must be "php" or "igbinary".');
+ }
+ if ('' !== $prefix = (string) $this->lazyClient->getOption(\Memcached::OPT_PREFIX_KEY)) {
+ throw new CacheException(sprintf('MemcachedAdapter: "prefix_key" option must be empty when using proxified connections, "%s" given.', $prefix));
+ }
+
+ return $this->client = $this->lazyClient;
+ }
+
+ private static function encodeKey(string $key): string
+ {
+ return strtr($key, self::RESERVED_MEMCACHED, self::RESERVED_PSR6);
+ }
+
+ private static function decodeKey(string $key): string
+ {
+ return strtr($key, self::RESERVED_PSR6, self::RESERVED_MEMCACHED);
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/NullAdapter.php b/vendor/symfony/cache/Adapter/NullAdapter.php
new file mode 100644
index 0000000..bf5382f
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/NullAdapter.php
@@ -0,0 +1,152 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Psr\Cache\CacheItemInterface;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Contracts\Cache\CacheInterface;
+
+/**
+ * @author Titouan Galopin
+ */
+class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
+{
+ use ContractsTrait;
+ use ProxyTrait;
+
+ private $file;
+ private $keys;
+ private $values;
+
+ private static $createCacheItem;
+ private static $valuesCache = [];
+
+ /**
+ * @param string $file The PHP file were values are cached
+ * @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit
+ */
+ public function __construct(string $file, AdapterInterface $fallbackPool)
+ {
+ $this->file = $file;
+ $this->pool = $fallbackPool;
+ self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
+ static function ($key, $value, $isHit) {
+ $item = new CacheItem();
+ $item->key = $key;
+ $item->value = $value;
+ $item->isHit = $isHit;
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+ }
+
+ /**
+ * This adapter takes advantage of how PHP stores arrays in its latest versions.
+ *
+ * @param string $file The PHP file were values are cached
+ * @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit
+ *
+ * @return CacheItemPoolInterface
+ */
+ public static function create(string $file, CacheItemPoolInterface $fallbackPool)
+ {
+ if (!$fallbackPool instanceof AdapterInterface) {
+ $fallbackPool = new ProxyAdapter($fallbackPool);
+ }
+
+ return new static($file, $fallbackPool);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null)
+ {
+ if (null === $this->values) {
+ $this->initialize();
+ }
+ if (!isset($this->keys[$key])) {
+ get_from_pool:
+ if ($this->pool instanceof CacheInterface) {
+ return $this->pool->get($key, $callback, $beta, $metadata);
+ }
+
+ return $this->doGet($this->pool, $key, $callback, $beta, $metadata);
+ }
+ $value = $this->values[$this->keys[$key]];
+
+ if ('N;' === $value) {
+ return null;
+ }
+ try {
+ if ($value instanceof \Closure) {
+ return $value();
+ }
+ } catch (\Throwable $e) {
+ unset($this->keys[$key]);
+ goto get_from_pool;
+ }
+
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItem($key)
+ {
+ if (!\is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key)));
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+ if (!isset($this->keys[$key])) {
+ return $this->pool->getItem($key);
+ }
+
+ $value = $this->values[$this->keys[$key]];
+ $isHit = true;
+
+ if ('N;' === $value) {
+ $value = null;
+ } elseif ($value instanceof \Closure) {
+ try {
+ $value = $value();
+ } catch (\Throwable $e) {
+ $value = null;
+ $isHit = false;
+ }
+ }
+
+ return (self::$createCacheItem)($key, $value, $isHit);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItems(array $keys = [])
+ {
+ foreach ($keys as $key) {
+ if (!\is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key)));
+ }
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return $this->generateItems($keys);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function hasItem($key)
+ {
+ if (!\is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key)));
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return isset($this->keys[$key]) || $this->pool->hasItem($key);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItem($key)
+ {
+ if (!\is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key)));
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return !isset($this->keys[$key]) && $this->pool->deleteItem($key);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItems(array $keys)
+ {
+ $deleted = true;
+ $fallbackKeys = [];
+
+ foreach ($keys as $key) {
+ if (!\is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key)));
+ }
+
+ if (isset($this->keys[$key])) {
+ $deleted = false;
+ } else {
+ $fallbackKeys[] = $key;
+ }
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ if ($fallbackKeys) {
+ $deleted = $this->pool->deleteItems($fallbackKeys) && $deleted;
+ }
+
+ return $deleted;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function save(CacheItemInterface $item)
+ {
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return !isset($this->keys[$item->getKey()]) && $this->pool->save($item);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function saveDeferred(CacheItemInterface $item)
+ {
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function commit()
+ {
+ return $this->pool->commit();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function clear(string $prefix = '')
+ {
+ $this->keys = $this->values = [];
+
+ $cleared = @unlink($this->file) || !file_exists($this->file);
+ unset(self::$valuesCache[$this->file]);
+
+ if ($this->pool instanceof AdapterInterface) {
+ return $this->pool->clear($prefix) && $cleared;
+ }
+
+ return $this->pool->clear() && $cleared;
+ }
+
+ /**
+ * Store an array of cached values.
+ *
+ * @param array $values The cached values
+ *
+ * @return string[] A list of classes to preload on PHP 7.4+
+ */
+ public function warmUp(array $values)
+ {
+ if (file_exists($this->file)) {
+ if (!is_file($this->file)) {
+ throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: "%s".', $this->file));
+ }
+
+ if (!is_writable($this->file)) {
+ throw new InvalidArgumentException(sprintf('Cache file is not writable: "%s".', $this->file));
+ }
+ } else {
+ $directory = \dirname($this->file);
+
+ if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
+ throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: "%s".', $directory));
+ }
+
+ if (!is_writable($directory)) {
+ throw new InvalidArgumentException(sprintf('Cache directory is not writable: "%s".', $directory));
+ }
+ }
+
+ $preload = [];
+ $dumpedValues = '';
+ $dumpedMap = [];
+ $dump = <<<'EOF'
+ $value) {
+ CacheItem::validateKey(\is_int($key) ? (string) $key : $key);
+ $isStaticValue = true;
+
+ if (null === $value) {
+ $value = "'N;'";
+ } elseif (\is_object($value) || \is_array($value)) {
+ try {
+ $value = VarExporter::export($value, $isStaticValue, $preload);
+ } catch (\Exception $e) {
+ throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)), 0, $e);
+ }
+ } elseif (\is_string($value)) {
+ // Wrap "N;" in a closure to not confuse it with an encoded `null`
+ if ('N;' === $value) {
+ $isStaticValue = false;
+ }
+ $value = var_export($value, true);
+ } elseif (!\is_scalar($value)) {
+ throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)));
+ } else {
+ $value = var_export($value, true);
+ }
+
+ if (!$isStaticValue) {
+ $value = str_replace("\n", "\n ", $value);
+ $value = "static function () {\n return {$value};\n}";
+ }
+ $hash = hash('md5', $value);
+
+ if (null === $id = $dumpedMap[$hash] ?? null) {
+ $id = $dumpedMap[$hash] = \count($dumpedMap);
+ $dumpedValues .= "{$id} => {$value},\n";
+ }
+
+ $dump .= var_export($key, true)." => {$id},\n";
+ }
+
+ $dump .= "\n], [\n\n{$dumpedValues}\n]];\n";
+
+ $tmpFile = uniqid($this->file, true);
+
+ file_put_contents($tmpFile, $dump);
+ @chmod($tmpFile, 0666 & ~umask());
+ unset($serialized, $value, $dump);
+
+ @rename($tmpFile, $this->file);
+ unset(self::$valuesCache[$this->file]);
+
+ $this->initialize();
+
+ return $preload;
+ }
+
+ /**
+ * Load the cache file.
+ */
+ private function initialize()
+ {
+ if (isset(self::$valuesCache[$this->file])) {
+ $values = self::$valuesCache[$this->file];
+ } elseif (!is_file($this->file)) {
+ $this->keys = $this->values = [];
+
+ return;
+ } else {
+ $values = self::$valuesCache[$this->file] = (include $this->file) ?: [[], []];
+ }
+
+ if (2 !== \count($values) || !isset($values[0], $values[1])) {
+ $this->keys = $this->values = [];
+ } else {
+ [$this->keys, $this->values] = $values;
+ }
+ }
+
+ private function generateItems(array $keys): \Generator
+ {
+ $f = self::$createCacheItem;
+ $fallbackKeys = [];
+
+ foreach ($keys as $key) {
+ if (isset($this->keys[$key])) {
+ $value = $this->values[$this->keys[$key]];
+
+ if ('N;' === $value) {
+ yield $key => $f($key, null, true);
+ } elseif ($value instanceof \Closure) {
+ try {
+ yield $key => $f($key, $value(), true);
+ } catch (\Throwable $e) {
+ yield $key => $f($key, null, false);
+ }
+ } else {
+ yield $key => $f($key, $value, true);
+ }
+ } else {
+ $fallbackKeys[] = $key;
+ }
+ }
+
+ if ($fallbackKeys) {
+ yield from $this->pool->getItems($fallbackKeys);
+ }
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/PhpFilesAdapter.php b/vendor/symfony/cache/Adapter/PhpFilesAdapter.php
new file mode 100644
index 0000000..8dcd79c
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/PhpFilesAdapter.php
@@ -0,0 +1,330 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Symfony\Component\Cache\Exception\CacheException;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\Cache\Traits\FilesystemCommonTrait;
+use Symfony\Component\VarExporter\VarExporter;
+
+/**
+ * @author Piotr Stankowski
+ * @author Rob Frawley 2nd
+ */
+class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
+{
+ use ContractsTrait;
+ use ProxyTrait;
+
+ private $namespace = '';
+ private $namespaceLen;
+ private $poolHash;
+ private $defaultLifetime;
+
+ private static $createCacheItem;
+ private static $setInnerItem;
+
+ public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0)
+ {
+ $this->pool = $pool;
+ $this->poolHash = $poolHash = spl_object_hash($pool);
+ if ('' !== $namespace) {
+ \assert('' !== CacheItem::validateKey($namespace));
+ $this->namespace = $namespace;
+ }
+ $this->namespaceLen = \strlen($namespace);
+ $this->defaultLifetime = $defaultLifetime;
+ self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
+ static function ($key, $innerItem, $poolHash) {
+ $item = new CacheItem();
+ $item->key = $key;
+
+ if (null === $innerItem) {
+ return $item;
+ }
+
+ $item->value = $v = $innerItem->get();
+ $item->isHit = $innerItem->isHit();
+ $item->innerItem = $innerItem;
+ $item->poolHash = $poolHash;
+
+ // Detect wrapped values that encode for their expiry and creation duration
+ // For compactness, these values are packed in the key of an array using
+ // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
+ if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) {
+ $item->value = $v[$k];
+ $v = unpack('Ve/Nc', substr($k, 1, -1));
+ $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET;
+ $item->metadata[CacheItem::METADATA_CTIME] = $v['c'];
+ } elseif ($innerItem instanceof CacheItem) {
+ $item->metadata = $innerItem->metadata;
+ }
+ $innerItem->set(null);
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+ self::$setInnerItem ?? self::$setInnerItem = \Closure::bind(
+ /**
+ * @param array $item A CacheItem cast to (array); accessing protected properties requires adding the "\0*\0" PHP prefix
+ */
+ static function (CacheItemInterface $innerItem, array $item) {
+ // Tags are stored separately, no need to account for them when considering this item's newly set metadata
+ if (isset(($metadata = $item["\0*\0newMetadata"])[CacheItem::METADATA_TAGS])) {
+ unset($metadata[CacheItem::METADATA_TAGS]);
+ }
+ if ($metadata) {
+ // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
+ $item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
+ }
+ $innerItem->set($item["\0*\0value"]);
+ $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null);
+ },
+ null,
+ CacheItem::class
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null)
+ {
+ if (!$this->pool instanceof CacheInterface) {
+ return $this->doGet($this, $key, $callback, $beta, $metadata);
+ }
+
+ return $this->pool->get($this->getId($key), function ($innerItem, bool &$save) use ($key, $callback) {
+ $item = (self::$createCacheItem)($key, $innerItem, $this->poolHash);
+ $item->set($value = $callback($item, $save));
+ (self::$setInnerItem)($innerItem, (array) $item);
+
+ return $value;
+ }, $beta, $metadata);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItem($key)
+ {
+ $item = $this->pool->getItem($this->getId($key));
+
+ return (self::$createCacheItem)($key, $item, $this->poolHash);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItems(array $keys = [])
+ {
+ if ($this->namespaceLen) {
+ foreach ($keys as $i => $key) {
+ $keys[$i] = $this->getId($key);
+ }
+ }
+
+ return $this->generateItems($this->pool->getItems($keys));
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function hasItem($key)
+ {
+ return $this->pool->hasItem($this->getId($key));
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function clear(string $prefix = '')
+ {
+ if ($this->pool instanceof AdapterInterface) {
+ return $this->pool->clear($this->namespace.$prefix);
+ }
+
+ return $this->pool->clear();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItem($key)
+ {
+ return $this->pool->deleteItem($this->getId($key));
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItems(array $keys)
+ {
+ if ($this->namespaceLen) {
+ foreach ($keys as $i => $key) {
+ $keys[$i] = $this->getId($key);
+ }
+ }
+
+ return $this->pool->deleteItems($keys);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function save(CacheItemInterface $item)
+ {
+ return $this->doSave($item, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function saveDeferred(CacheItemInterface $item)
+ {
+ return $this->doSave($item, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function commit()
+ {
+ return $this->pool->commit();
+ }
+
+ private function doSave(CacheItemInterface $item, string $method)
+ {
+ if (!$item instanceof CacheItem) {
+ return false;
+ }
+ $item = (array) $item;
+ if (null === $item["\0*\0expiry"] && 0 < $this->defaultLifetime) {
+ $item["\0*\0expiry"] = microtime(true) + $this->defaultLifetime;
+ }
+
+ if ($item["\0*\0poolHash"] === $this->poolHash && $item["\0*\0innerItem"]) {
+ $innerItem = $item["\0*\0innerItem"];
+ } elseif ($this->pool instanceof AdapterInterface) {
+ // this is an optimization specific for AdapterInterface implementations
+ // so we can save a round-trip to the backend by just creating a new item
+ $innerItem = (self::$createCacheItem)($this->namespace.$item["\0*\0key"], null, $this->poolHash);
+ } else {
+ $innerItem = $this->pool->getItem($this->namespace.$item["\0*\0key"]);
+ }
+
+ (self::$setInnerItem)($innerItem, $item);
+
+ return $this->pool->$method($innerItem);
+ }
+
+ private function generateItems(iterable $items): \Generator
+ {
+ $f = self::$createCacheItem;
+
+ foreach ($items as $key => $item) {
+ if ($this->namespaceLen) {
+ $key = substr($key, $this->namespaceLen);
+ }
+
+ yield $key => $f($key, $item, $this->poolHash);
+ }
+ }
+
+ private function getId($key): string
+ {
+ \assert('' !== CacheItem::validateKey($key));
+
+ return $this->namespace.$key;
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/Psr16Adapter.php b/vendor/symfony/cache/Adapter/Psr16Adapter.php
new file mode 100644
index 0000000..a56aa39
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/Psr16Adapter.php
@@ -0,0 +1,86 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Psr\SimpleCache\CacheInterface;
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Component\Cache\Traits\ProxyTrait;
+
+/**
+ * Turns a PSR-16 cache into a PSR-6 one.
+ *
+ * @author Nicolas Grekas
+ */
+class Psr16Adapter extends AbstractAdapter implements PruneableInterface, ResettableInterface
+{
+ use ProxyTrait;
+
+ /**
+ * @internal
+ */
+ protected const NS_SEPARATOR = '_';
+
+ private $miss;
+
+ public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0)
+ {
+ parent::__construct($namespace, $defaultLifetime);
+
+ $this->pool = $pool;
+ $this->miss = new \stdClass();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doFetch(array $ids)
+ {
+ foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) {
+ if ($this->miss !== $value) {
+ yield $key => $value;
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doHave(string $id)
+ {
+ return $this->pool->has($id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doClear(string $namespace)
+ {
+ return $this->pool->clear();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete(array $ids)
+ {
+ return $this->pool->deleteMultiple($ids);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doSave(array $values, int $lifetime)
+ {
+ return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime);
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/RedisAdapter.php b/vendor/symfony/cache/Adapter/RedisAdapter.php
new file mode 100644
index 0000000..86714ae
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/RedisAdapter.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\Traits\RedisClusterProxy;
+use Symfony\Component\Cache\Traits\RedisProxy;
+use Symfony\Component\Cache\Traits\RedisTrait;
+
+class RedisAdapter extends AbstractAdapter
+{
+ use RedisTrait;
+
+ /**
+ * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis The redis client
+ * @param string $namespace The default namespace
+ * @param int $defaultLifetime The default lifetime
+ */
+ public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null)
+ {
+ $this->init($redis, $namespace, $defaultLifetime, $marshaller);
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php
new file mode 100644
index 0000000..958486e
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php
@@ -0,0 +1,325 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Predis\Connection\Aggregate\ClusterInterface;
+use Predis\Connection\Aggregate\PredisCluster;
+use Predis\Connection\Aggregate\ReplicationInterface;
+use Predis\Response\ErrorInterface;
+use Predis\Response\Status;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Exception\LogicException;
+use Symfony\Component\Cache\Marshaller\DeflateMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+use Symfony\Component\Cache\Marshaller\TagAwareMarshaller;
+use Symfony\Component\Cache\Traits\RedisClusterProxy;
+use Symfony\Component\Cache\Traits\RedisProxy;
+use Symfony\Component\Cache\Traits\RedisTrait;
+
+/**
+ * Stores tag id <> cache id relationship as a Redis Set.
+ *
+ * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even
+ * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache
+ * relationship survives eviction (cache cleanup when Redis runs out of memory).
+ *
+ * Redis server 2.8+ with any `volatile-*` eviction policy, OR `noeviction` if you're sure memory will NEVER fill up
+ *
+ * Design limitations:
+ * - Max 4 billion cache keys per cache tag as limited by Redis Set datatype.
+ * E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 4 billion cache items also.
+ *
+ * @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies.
+ * @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype.
+ *
+ * @author Nicolas Grekas
+ * @author André Rømcke
+ */
+class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface, LoggerAwareInterface
+{
+ use ContractsTrait;
+ use LoggerAwareTrait;
+ use ProxyTrait;
+
+ public const TAGS_PREFIX = "\0tags\0";
+
+ private $deferred = [];
+ private $tags;
+ private $knownTagVersions = [];
+ private $knownTagVersionsTtl;
+
+ private static $createCacheItem;
+ private static $setCacheItemTags;
+ private static $getTagsByKey;
+ private static $saveTags;
+
+ public function __construct(AdapterInterface $itemsPool, ?AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15)
+ {
+ $this->pool = $itemsPool;
+ $this->tags = $tagsPool ?: $itemsPool;
+ $this->knownTagVersionsTtl = $knownTagVersionsTtl;
+ self::$createCacheItem ?? self::$createCacheItem = \Closure::bind(
+ static function ($key, $value, CacheItem $protoItem) {
+ $item = new CacheItem();
+ $item->key = $key;
+ $item->value = $value;
+ $item->expiry = $protoItem->expiry;
+ $item->poolHash = $protoItem->poolHash;
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+ self::$setCacheItemTags ?? self::$setCacheItemTags = \Closure::bind(
+ static function (CacheItem $item, $key, array &$itemTags) {
+ $item->isTaggable = true;
+ if (!$item->isHit) {
+ return $item;
+ }
+ if (isset($itemTags[$key])) {
+ foreach ($itemTags[$key] as $tag => $version) {
+ $item->metadata[CacheItem::METADATA_TAGS][$tag] = $tag;
+ }
+ unset($itemTags[$key]);
+ } else {
+ $item->value = null;
+ $item->isHit = false;
+ }
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+ self::$getTagsByKey ?? self::$getTagsByKey = \Closure::bind(
+ static function ($deferred) {
+ $tagsByKey = [];
+ foreach ($deferred as $key => $item) {
+ $tagsByKey[$key] = $item->newMetadata[CacheItem::METADATA_TAGS] ?? [];
+ $item->metadata = $item->newMetadata;
+ }
+
+ return $tagsByKey;
+ },
+ null,
+ CacheItem::class
+ );
+ self::$saveTags ?? self::$saveTags = \Closure::bind(
+ static function (AdapterInterface $tagsAdapter, array $tags) {
+ ksort($tags);
+
+ foreach ($tags as $v) {
+ $v->expiry = 0;
+ $tagsAdapter->saveDeferred($v);
+ }
+
+ return $tagsAdapter->commit();
+ },
+ null,
+ CacheItem::class
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function invalidateTags(array $tags)
+ {
+ $ids = [];
+ foreach ($tags as $tag) {
+ \assert('' !== CacheItem::validateKey($tag));
+ unset($this->knownTagVersions[$tag]);
+ $ids[] = $tag.static::TAGS_PREFIX;
+ }
+
+ return !$tags || $this->tags->deleteItems($ids);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function hasItem($key)
+ {
+ if (\is_string($key) && isset($this->deferred[$key])) {
+ $this->commit();
+ }
+
+ if (!$this->pool->hasItem($key)) {
+ return false;
+ }
+
+ $itemTags = $this->pool->getItem(static::TAGS_PREFIX.$key);
+
+ if (!$itemTags->isHit()) {
+ return false;
+ }
+
+ if (!$itemTags = $itemTags->get()) {
+ return true;
+ }
+
+ foreach ($this->getTagVersions([$itemTags]) as $tag => $version) {
+ if ($itemTags[$tag] !== $version) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItem($key)
+ {
+ foreach ($this->getItems([$key]) as $item) {
+ return $item;
+ }
+
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItems(array $keys = [])
+ {
+ $tagKeys = [];
+ $commit = false;
+
+ foreach ($keys as $key) {
+ if ('' !== $key && \is_string($key)) {
+ $commit = $commit || isset($this->deferred[$key]);
+ $key = static::TAGS_PREFIX.$key;
+ $tagKeys[$key] = $key;
+ }
+ }
+
+ if ($commit) {
+ $this->commit();
+ }
+
+ try {
+ $items = $this->pool->getItems($tagKeys + $keys);
+ } catch (InvalidArgumentException $e) {
+ $this->pool->getItems($keys); // Should throw an exception
+
+ throw $e;
+ }
+
+ return $this->generateItems($items, $tagKeys);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function clear(string $prefix = '')
+ {
+ if ('' !== $prefix) {
+ foreach ($this->deferred as $key => $item) {
+ if (str_starts_with($key, $prefix)) {
+ unset($this->deferred[$key]);
+ }
+ }
+ } else {
+ $this->deferred = [];
+ }
+
+ if ($this->pool instanceof AdapterInterface) {
+ return $this->pool->clear($prefix);
+ }
+
+ return $this->pool->clear();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItem($key)
+ {
+ return $this->deleteItems([$key]);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItems(array $keys)
+ {
+ foreach ($keys as $key) {
+ if ('' !== $key && \is_string($key)) {
+ $keys[] = static::TAGS_PREFIX.$key;
+ }
+ }
+
+ return $this->pool->deleteItems($keys);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function save(CacheItemInterface $item)
+ {
+ if (!$item instanceof CacheItem) {
+ return false;
+ }
+ $this->deferred[$item->getKey()] = $item;
+
+ return $this->commit();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function saveDeferred(CacheItemInterface $item)
+ {
+ if (!$item instanceof CacheItem) {
+ return false;
+ }
+ $this->deferred[$item->getKey()] = $item;
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function commit()
+ {
+ if (!$this->deferred) {
+ return true;
+ }
+
+ $ok = true;
+ foreach ($this->deferred as $key => $item) {
+ if (!$this->pool->saveDeferred($item)) {
+ unset($this->deferred[$key]);
+ $ok = false;
+ }
+ }
+
+ $items = $this->deferred;
+ $tagsByKey = (self::$getTagsByKey)($items);
+ $this->deferred = [];
+
+ $tagVersions = $this->getTagVersions($tagsByKey);
+ $f = self::$createCacheItem;
+
+ foreach ($tagsByKey as $key => $tags) {
+ $this->pool->saveDeferred($f(static::TAGS_PREFIX.$key, array_intersect_key($tagVersions, $tags), $items[$key]));
+ }
+
+ return $this->pool->commit() && $ok;
+ }
+
+ /**
+ * @return array
+ */
+ public function __sleep()
+ {
+ throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
+ }
+
+ public function __wakeup()
+ {
+ throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
+ }
+
+ public function __destruct()
+ {
+ $this->commit();
+ }
+
+ private function generateItems(iterable $items, array $tagKeys): \Generator
+ {
+ $bufferedItems = $itemTags = [];
+ $f = self::$setCacheItemTags;
+
+ foreach ($items as $key => $item) {
+ if (!$tagKeys) {
+ yield $key => $f($item, static::TAGS_PREFIX.$key, $itemTags);
+ continue;
+ }
+ if (!isset($tagKeys[$key])) {
+ $bufferedItems[$key] = $item;
+ continue;
+ }
+
+ unset($tagKeys[$key]);
+
+ if ($item->isHit()) {
+ $itemTags[$key] = $item->get() ?: [];
+ }
+
+ if (!$tagKeys) {
+ $tagVersions = $this->getTagVersions($itemTags);
+
+ foreach ($itemTags as $key => $tags) {
+ foreach ($tags as $tag => $version) {
+ if ($tagVersions[$tag] !== $version) {
+ unset($itemTags[$key]);
+ continue 2;
+ }
+ }
+ }
+ $tagVersions = $tagKeys = null;
+
+ foreach ($bufferedItems as $key => $item) {
+ yield $key => $f($item, static::TAGS_PREFIX.$key, $itemTags);
+ }
+ $bufferedItems = null;
+ }
+ }
+ }
+
+ private function getTagVersions(array $tagsByKey)
+ {
+ $tagVersions = [];
+ $fetchTagVersions = false;
+
+ foreach ($tagsByKey as $tags) {
+ $tagVersions += $tags;
+
+ foreach ($tags as $tag => $version) {
+ if ($tagVersions[$tag] !== $version) {
+ unset($this->knownTagVersions[$tag]);
+ }
+ }
+ }
+
+ if (!$tagVersions) {
+ return [];
+ }
+
+ $now = microtime(true);
+ $tags = [];
+ foreach ($tagVersions as $tag => $version) {
+ $tags[$tag.static::TAGS_PREFIX] = $tag;
+ if ($fetchTagVersions || ($this->knownTagVersions[$tag][1] ?? null) !== $version || $now - $this->knownTagVersions[$tag][0] >= $this->knownTagVersionsTtl) {
+ // reuse previously fetched tag versions up to the ttl
+ $fetchTagVersions = true;
+ }
+ }
+
+ if (!$fetchTagVersions) {
+ return $tagVersions;
+ }
+
+ $newTags = [];
+ $newVersion = null;
+ foreach ($this->tags->getItems(array_keys($tags)) as $tag => $version) {
+ if (!$version->isHit()) {
+ $newTags[$tag] = $version->set($newVersion ?? $newVersion = random_int(\PHP_INT_MIN, \PHP_INT_MAX));
+ }
+ $tagVersions[$tag = $tags[$tag]] = $version->get();
+ $this->knownTagVersions[$tag] = [$now, $tagVersions[$tag]];
+ }
+
+ if ($newTags) {
+ (self::$saveTags)($this->tags, $newTags);
+ }
+
+ return $tagVersions;
+ }
+}
diff --git a/vendor/symfony/cache/Adapter/TagAwareAdapterInterface.php b/vendor/symfony/cache/Adapter/TagAwareAdapterInterface.php
new file mode 100644
index 0000000..afa18d3
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/TagAwareAdapterInterface.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Psr\Cache\InvalidArgumentException;
+
+/**
+ * Interface for invalidating cached items using tags.
+ *
+ * @author Nicolas Grekas
+ */
+interface TagAwareAdapterInterface extends AdapterInterface
+{
+ /**
+ * Invalidates cached items using tags.
+ *
+ * @param string[] $tags An array of tags to invalidate
+ *
+ * @return bool
+ *
+ * @throws InvalidArgumentException When $tags is not valid
+ */
+ public function invalidateTags(array $tags);
+}
diff --git a/vendor/symfony/cache/Adapter/TraceableAdapter.php b/vendor/symfony/cache/Adapter/TraceableAdapter.php
new file mode 100644
index 0000000..06951db
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/TraceableAdapter.php
@@ -0,0 +1,295 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Psr\Cache\CacheItemInterface;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\Cache\ResettableInterface;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Service\ResetInterface;
+
+/**
+ * An adapter that collects data about all cache calls.
+ *
+ * @author Aaron Scherer
+ */
+class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
+{
+ protected $pool;
+ private $calls = [];
+
+ public function __construct(AdapterInterface $pool)
+ {
+ $this->pool = $pool;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null)
+ {
+ if (!$this->pool instanceof CacheInterface) {
+ throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', get_debug_type($this->pool), CacheInterface::class));
+ }
+
+ $isHit = true;
+ $callback = function (CacheItem $item, bool &$save) use ($callback, &$isHit) {
+ $isHit = $item->isHit();
+
+ return $callback($item, $save);
+ };
+
+ $event = $this->start(__FUNCTION__);
+ try {
+ $value = $this->pool->get($key, $callback, $beta, $metadata);
+ $event->result[$key] = get_debug_type($value);
+ } finally {
+ $event->end = microtime(true);
+ }
+ if ($isHit) {
+ ++$event->hits;
+ } else {
+ ++$event->misses;
+ }
+
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItem($key)
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ $item = $this->pool->getItem($key);
+ } finally {
+ $event->end = microtime(true);
+ }
+ if ($event->result[$key] = $item->isHit()) {
+ ++$event->hits;
+ } else {
+ ++$event->misses;
+ }
+
+ return $item;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function hasItem($key)
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ return $event->result[$key] = $this->pool->hasItem($key);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItem($key)
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ return $event->result[$key] = $this->pool->deleteItem($key);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function save(CacheItemInterface $item)
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ return $event->result[$item->getKey()] = $this->pool->save($item);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function saveDeferred(CacheItemInterface $item)
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ return $event->result[$item->getKey()] = $this->pool->saveDeferred($item);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItems(array $keys = [])
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ $result = $this->pool->getItems($keys);
+ } finally {
+ $event->end = microtime(true);
+ }
+ $f = function () use ($result, $event) {
+ $event->result = [];
+ foreach ($result as $key => $item) {
+ if ($event->result[$key] = $item->isHit()) {
+ ++$event->hits;
+ } else {
+ ++$event->misses;
+ }
+ yield $key => $item;
+ }
+ };
+
+ return $f();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function clear(string $prefix = '')
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ if ($this->pool instanceof AdapterInterface) {
+ return $event->result = $this->pool->clear($prefix);
+ }
+
+ return $event->result = $this->pool->clear();
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteItems(array $keys)
+ {
+ $event = $this->start(__FUNCTION__);
+ $event->result['keys'] = $keys;
+ try {
+ return $event->result['result'] = $this->pool->deleteItems($keys);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function commit()
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ return $event->result = $this->pool->commit();
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prune()
+ {
+ if (!$this->pool instanceof PruneableInterface) {
+ return false;
+ }
+ $event = $this->start(__FUNCTION__);
+ try {
+ return $event->result = $this->pool->prune();
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset()
+ {
+ if ($this->pool instanceof ResetInterface) {
+ $this->pool->reset();
+ }
+
+ $this->clearCalls();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete(string $key): bool
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ return $event->result[$key] = $this->pool->deleteItem($key);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ public function getCalls()
+ {
+ return $this->calls;
+ }
+
+ public function clearCalls()
+ {
+ $this->calls = [];
+ }
+
+ protected function start(string $name)
+ {
+ $this->calls[] = $event = new TraceableAdapterEvent();
+ $event->name = $name;
+ $event->start = microtime(true);
+
+ return $event;
+ }
+}
+
+class TraceableAdapterEvent
+{
+ public $name;
+ public $start;
+ public $end;
+ public $result;
+ public $hits = 0;
+ public $misses = 0;
+}
diff --git a/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php b/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php
new file mode 100644
index 0000000..69461b8
--- /dev/null
+++ b/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php
@@ -0,0 +1,38 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Adapter;
+
+use Symfony\Contracts\Cache\TagAwareCacheInterface;
+
+/**
+ * @author Robin Chalas
+ */
+final class CacheItem implements ItemInterface
+{
+ private const METADATA_EXPIRY_OFFSET = 1527506807;
+
+ protected $key;
+ protected $value;
+ protected $isHit = false;
+ protected $expiry;
+ protected $metadata = [];
+ protected $newMetadata = [];
+ protected $innerItem;
+ protected $poolHash;
+ protected $isTaggable = false;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getKey(): string
+ {
+ return $this->key;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return mixed
+ */
+ public function get()
+ {
+ return $this->value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHit(): bool
+ {
+ return $this->isHit;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return $this
+ */
+ public function set($value): self
+ {
+ $this->value = $value;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return $this
+ */
+ public function expiresAt($expiration): self
+ {
+ if (null === $expiration) {
+ $this->expiry = null;
+ } elseif ($expiration instanceof \DateTimeInterface) {
+ $this->expiry = (float) $expiration->format('U.u');
+ } else {
+ throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given.', get_debug_type($expiration)));
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return $this
+ */
+ public function expiresAfter($time): self
+ {
+ if (null === $time) {
+ $this->expiry = null;
+ } elseif ($time instanceof \DateInterval) {
+ $this->expiry = microtime(true) + \DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
+ } elseif (\is_int($time)) {
+ $this->expiry = $time + microtime(true);
+ } else {
+ throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', get_debug_type($time)));
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function tag($tags): ItemInterface
+ {
+ if (!$this->isTaggable) {
+ throw new LogicException(sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key));
+ }
+ if (!is_iterable($tags)) {
+ $tags = [$tags];
+ }
+ foreach ($tags as $tag) {
+ if (!\is_string($tag) && !(\is_object($tag) && method_exists($tag, '__toString'))) {
+ throw new InvalidArgumentException(sprintf('Cache tag must be string or object that implements __toString(), "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag)));
+ }
+ $tag = (string) $tag;
+ if (isset($this->newMetadata[self::METADATA_TAGS][$tag])) {
+ continue;
+ }
+ if ('' === $tag) {
+ throw new InvalidArgumentException('Cache tag length must be greater than zero.');
+ }
+ if (false !== strpbrk($tag, self::RESERVED_CHARACTERS)) {
+ throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters "%s".', $tag, self::RESERVED_CHARACTERS));
+ }
+ $this->newMetadata[self::METADATA_TAGS][$tag] = $tag;
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMetadata(): array
+ {
+ return $this->metadata;
+ }
+
+ /**
+ * Validates a cache key according to PSR-6.
+ *
+ * @param mixed $key The key to validate
+ *
+ * @throws InvalidArgumentException When $key is not valid
+ */
+ public static function validateKey($key): string
+ {
+ if (!\is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key)));
+ }
+ if ('' === $key) {
+ throw new InvalidArgumentException('Cache key length must be greater than zero.');
+ }
+ if (false !== strpbrk($key, self::RESERVED_CHARACTERS)) {
+ throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS));
+ }
+
+ return $key;
+ }
+
+ /**
+ * Internal logging helper.
+ *
+ * @internal
+ */
+ public static function log(?LoggerInterface $logger, string $message, array $context = [])
+ {
+ if ($logger) {
+ $logger->warning($message, $context);
+ } else {
+ $replace = [];
+ foreach ($context as $k => $v) {
+ if (\is_scalar($v)) {
+ $replace['{'.$k.'}'] = $v;
+ }
+ }
+ @trigger_error(strtr($message, $replace), \E_USER_WARNING);
+ }
+ }
+}
diff --git a/vendor/symfony/cache/DataCollector/CacheDataCollector.php b/vendor/symfony/cache/DataCollector/CacheDataCollector.php
new file mode 100644
index 0000000..0479580
--- /dev/null
+++ b/vendor/symfony/cache/DataCollector/CacheDataCollector.php
@@ -0,0 +1,183 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\DataCollector;
+
+use Symfony\Component\Cache\Adapter\TraceableAdapter;
+use Symfony\Component\Cache\Adapter\TraceableAdapterEvent;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
+
+/**
+ * @author Aaron Scherer
+ */
+class CachePoolClearerPass implements CompilerPassInterface
+{
+ private $cachePoolClearerTag;
+
+ public function __construct(string $cachePoolClearerTag = 'cache.pool.clearer')
+ {
+ if (0 < \func_num_args()) {
+ trigger_deprecation('symfony/cache', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
+ }
+
+ $this->cachePoolClearerTag = $cachePoolClearerTag;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(ContainerBuilder $container)
+ {
+ $container->getParameterBag()->remove('cache.prefix.seed');
+
+ foreach ($container->findTaggedServiceIds($this->cachePoolClearerTag) as $id => $attr) {
+ $clearer = $container->getDefinition($id);
+ $pools = [];
+ foreach ($clearer->getArgument(0) as $name => $ref) {
+ if ($container->hasDefinition($ref)) {
+ $pools[$name] = new Reference($ref);
+ }
+ }
+ $clearer->replaceArgument(0, $pools);
+ }
+ }
+}
diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php
new file mode 100644
index 0000000..ee539af
--- /dev/null
+++ b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php
@@ -0,0 +1,274 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\DependencyInjection;
+
+use Symfony\Component\Cache\Adapter\AbstractAdapter;
+use Symfony\Component\Cache\Adapter\ArrayAdapter;
+use Symfony\Component\Cache\Adapter\ChainAdapter;
+use Symfony\Component\Cache\Adapter\NullAdapter;
+use Symfony\Component\Cache\Adapter\ParameterNormalizer;
+use Symfony\Component\Cache\Messenger\EarlyExpirationDispatcher;
+use Symfony\Component\DependencyInjection\ChildDefinition;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * @author Nicolas Grekas
+ */
+class CachePoolPass implements CompilerPassInterface
+{
+ private $cachePoolTag;
+ private $kernelResetTag;
+ private $cacheClearerId;
+ private $cachePoolClearerTag;
+ private $cacheSystemClearerId;
+ private $cacheSystemClearerTag;
+ private $reverseContainerId;
+ private $reversibleTag;
+ private $messageHandlerId;
+
+ public function __construct(string $cachePoolTag = 'cache.pool', string $kernelResetTag = 'kernel.reset', string $cacheClearerId = 'cache.global_clearer', string $cachePoolClearerTag = 'cache.pool.clearer', string $cacheSystemClearerId = 'cache.system_clearer', string $cacheSystemClearerTag = 'kernel.cache_clearer', string $reverseContainerId = 'reverse_container', string $reversibleTag = 'container.reversible', string $messageHandlerId = 'cache.early_expiration_handler')
+ {
+ if (0 < \func_num_args()) {
+ trigger_deprecation('symfony/cache', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
+ }
+
+ $this->cachePoolTag = $cachePoolTag;
+ $this->kernelResetTag = $kernelResetTag;
+ $this->cacheClearerId = $cacheClearerId;
+ $this->cachePoolClearerTag = $cachePoolClearerTag;
+ $this->cacheSystemClearerId = $cacheSystemClearerId;
+ $this->cacheSystemClearerTag = $cacheSystemClearerTag;
+ $this->reverseContainerId = $reverseContainerId;
+ $this->reversibleTag = $reversibleTag;
+ $this->messageHandlerId = $messageHandlerId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(ContainerBuilder $container)
+ {
+ if ($container->hasParameter('cache.prefix.seed')) {
+ $seed = $container->getParameterBag()->resolveValue($container->getParameter('cache.prefix.seed'));
+ } else {
+ $seed = '_'.$container->getParameter('kernel.project_dir');
+ $seed .= '.'.$container->getParameter('kernel.container_class');
+ }
+
+ $needsMessageHandler = false;
+ $allPools = [];
+ $clearers = [];
+ $attributes = [
+ 'provider',
+ 'name',
+ 'namespace',
+ 'default_lifetime',
+ 'early_expiration_message_bus',
+ 'reset',
+ ];
+ foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) {
+ $adapter = $pool = $container->getDefinition($id);
+ if ($pool->isAbstract()) {
+ continue;
+ }
+ $class = $adapter->getClass();
+ while ($adapter instanceof ChildDefinition) {
+ $adapter = $container->findDefinition($adapter->getParent());
+ $class = $class ?: $adapter->getClass();
+ if ($t = $adapter->getTag($this->cachePoolTag)) {
+ $tags[0] += $t[0];
+ }
+ }
+ $name = $tags[0]['name'] ?? $id;
+ if (!isset($tags[0]['namespace'])) {
+ $namespaceSeed = $seed;
+ if (null !== $class) {
+ $namespaceSeed .= '.'.$class;
+ }
+
+ $tags[0]['namespace'] = $this->getNamespace($namespaceSeed, $name);
+ }
+ if (isset($tags[0]['clearer'])) {
+ $clearer = $tags[0]['clearer'];
+ while ($container->hasAlias($clearer)) {
+ $clearer = (string) $container->getAlias($clearer);
+ }
+ } else {
+ $clearer = null;
+ }
+ unset($tags[0]['clearer'], $tags[0]['name']);
+
+ if (isset($tags[0]['provider'])) {
+ $tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider']));
+ }
+
+ if (ChainAdapter::class === $class) {
+ $adapters = [];
+ foreach ($adapter->getArgument(0) as $provider => $adapter) {
+ if ($adapter instanceof ChildDefinition) {
+ $chainedPool = $adapter;
+ } else {
+ $chainedPool = $adapter = new ChildDefinition($adapter);
+ }
+
+ $chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]];
+ $chainedClass = '';
+
+ while ($adapter instanceof ChildDefinition) {
+ $adapter = $container->findDefinition($adapter->getParent());
+ $chainedClass = $chainedClass ?: $adapter->getClass();
+ if ($t = $adapter->getTag($this->cachePoolTag)) {
+ $chainedTags[0] += $t[0];
+ }
+ }
+
+ if (ChainAdapter::class === $chainedClass) {
+ throw new InvalidArgumentException(sprintf('Invalid service "%s": chain of adapters cannot reference another chain, found "%s".', $id, $chainedPool->getParent()));
+ }
+
+ $i = 0;
+
+ if (isset($chainedTags[0]['provider'])) {
+ $chainedPool->replaceArgument($i++, new Reference(static::getServiceProvider($container, $chainedTags[0]['provider'])));
+ }
+
+ if (isset($tags[0]['namespace']) && !\in_array($adapter->getClass(), [ArrayAdapter::class, NullAdapter::class], true)) {
+ $chainedPool->replaceArgument($i++, $tags[0]['namespace']);
+ }
+
+ if (isset($tags[0]['default_lifetime'])) {
+ $chainedPool->replaceArgument($i++, $tags[0]['default_lifetime']);
+ }
+
+ $adapters[] = $chainedPool;
+ }
+
+ $pool->replaceArgument(0, $adapters);
+ unset($tags[0]['provider'], $tags[0]['namespace']);
+ $i = 1;
+ } else {
+ $i = 0;
+ }
+
+ foreach ($attributes as $attr) {
+ if (!isset($tags[0][$attr])) {
+ // no-op
+ } elseif ('reset' === $attr) {
+ if ($tags[0][$attr]) {
+ $pool->addTag($this->kernelResetTag, ['method' => $tags[0][$attr]]);
+ }
+ } elseif ('early_expiration_message_bus' === $attr) {
+ $needsMessageHandler = true;
+ $pool->addMethodCall('setCallbackWrapper', [(new Definition(EarlyExpirationDispatcher::class))
+ ->addArgument(new Reference($tags[0]['early_expiration_message_bus']))
+ ->addArgument(new Reference($this->reverseContainerId))
+ ->addArgument((new Definition('callable'))
+ ->setFactory([new Reference($id), 'setCallbackWrapper'])
+ ->addArgument(null)
+ ),
+ ]);
+ $pool->addTag($this->reversibleTag);
+ } elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) {
+ $argument = $tags[0][$attr];
+
+ if ('default_lifetime' === $attr && !is_numeric($argument)) {
+ $argument = (new Definition('int', [$argument]))
+ ->setFactory([ParameterNormalizer::class, 'normalizeDuration']);
+ }
+
+ $pool->replaceArgument($i++, $argument);
+ }
+ unset($tags[0][$attr]);
+ }
+ if (!empty($tags[0])) {
+ throw new InvalidArgumentException(sprintf('Invalid "%s" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime", "early_expiration_message_bus" and "reset", found "%s".', $this->cachePoolTag, $id, implode('", "', array_keys($tags[0]))));
+ }
+
+ if (null !== $clearer) {
+ $clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
+ }
+
+ $allPools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE);
+ }
+
+ if (!$needsMessageHandler) {
+ $container->removeDefinition($this->messageHandlerId);
+ }
+
+ $notAliasedCacheClearerId = $this->cacheClearerId;
+ while ($container->hasAlias($notAliasedCacheClearerId)) {
+ $notAliasedCacheClearerId = (string) $container->getAlias($notAliasedCacheClearerId);
+ }
+ if ($container->hasDefinition($notAliasedCacheClearerId)) {
+ $clearers[$notAliasedCacheClearerId] = $allPools;
+ }
+
+ foreach ($clearers as $id => $pools) {
+ $clearer = $container->getDefinition($id);
+ if ($clearer instanceof ChildDefinition) {
+ $clearer->replaceArgument(0, $pools);
+ } else {
+ $clearer->setArgument(0, $pools);
+ }
+ $clearer->addTag($this->cachePoolClearerTag);
+
+ if ($this->cacheSystemClearerId === $id) {
+ $clearer->addTag($this->cacheSystemClearerTag);
+ }
+ }
+
+ $allPoolsKeys = array_keys($allPools);
+
+ if ($container->hasDefinition('console.command.cache_pool_list')) {
+ $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, $allPoolsKeys);
+ }
+
+ if ($container->hasDefinition('console.command.cache_pool_clear')) {
+ $container->getDefinition('console.command.cache_pool_clear')->addArgument($allPoolsKeys);
+ }
+
+ if ($container->hasDefinition('console.command.cache_pool_delete')) {
+ $container->getDefinition('console.command.cache_pool_delete')->addArgument($allPoolsKeys);
+ }
+ }
+
+ private function getNamespace(string $seed, string $id)
+ {
+ return substr(str_replace('/', '-', base64_encode(hash('sha256', $id.$seed, true))), 0, 10);
+ }
+
+ /**
+ * @internal
+ */
+ public static function getServiceProvider(ContainerBuilder $container, string $name)
+ {
+ $container->resolveEnvPlaceholders($name, null, $usedEnvs);
+
+ if ($usedEnvs || preg_match('#^[a-z]++:#', $name)) {
+ $dsn = $name;
+
+ if (!$container->hasDefinition($name = '.cache_connection.'.ContainerBuilder::hash($dsn))) {
+ $definition = new Definition(AbstractAdapter::class);
+ $definition->setPublic(false);
+ $definition->setFactory([AbstractAdapter::class, 'createConnection']);
+ $definition->setArguments([$dsn, ['lazy' => true]]);
+ $container->setDefinition($name, $definition);
+ }
+ }
+
+ return $name;
+ }
+}
diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php
new file mode 100644
index 0000000..86a1906
--- /dev/null
+++ b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\DependencyInjection;
+
+use Symfony\Component\Cache\PruneableInterface;
+use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * @author Rob Frawley 2nd
+ *
+ * @deprecated Use Doctrine\Common\Cache\Psr6\DoctrineProvider instead
+ */
+class DoctrineProvider extends CacheProvider implements PruneableInterface, ResettableInterface
+{
+ private $pool;
+
+ public function __construct(CacheItemPoolInterface $pool)
+ {
+ trigger_deprecation('symfony/cache', '5.4', '"%s" is deprecated, use "Doctrine\Common\Cache\Psr6\DoctrineProvider" instead.', __CLASS__);
+
+ $this->pool = $pool;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prune()
+ {
+ return $this->pool instanceof PruneableInterface && $this->pool->prune();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset()
+ {
+ if ($this->pool instanceof ResetInterface) {
+ $this->pool->reset();
+ }
+ $this->setNamespace($this->getNamespace());
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return mixed
+ */
+ protected function doFetch($id)
+ {
+ $item = $this->pool->getItem(rawurlencode($id));
+
+ return $item->isHit() ? $item->get() : false;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ protected function doContains($id)
+ {
+ return $this->pool->hasItem(rawurlencode($id));
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ protected function doSave($id, $data, $lifeTime = 0)
+ {
+ $item = $this->pool->getItem(rawurlencode($id));
+
+ if (0 < $lifeTime) {
+ $item->expiresAfter($lifeTime);
+ }
+
+ return $this->pool->save($item->set($data));
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ protected function doDelete($id)
+ {
+ return $this->pool->deleteItem(rawurlencode($id));
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ protected function doFlush()
+ {
+ return $this->pool->clear();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return array|null
+ */
+ protected function doGetStats()
+ {
+ return null;
+ }
+}
diff --git a/vendor/symfony/cache/Exception/CacheException.php b/vendor/symfony/cache/Exception/CacheException.php
new file mode 100644
index 0000000..d2e975b
--- /dev/null
+++ b/vendor/symfony/cache/Exception/CacheException.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Exception;
+
+use Psr\Cache\CacheException as Psr6CacheInterface;
+use Psr\SimpleCache\CacheException as SimpleCacheInterface;
+
+if (interface_exists(SimpleCacheInterface::class)) {
+ class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface
+ {
+ }
+} else {
+ class CacheException extends \Exception implements Psr6CacheInterface
+ {
+ }
+}
diff --git a/vendor/symfony/cache/Exception/InvalidArgumentException.php b/vendor/symfony/cache/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..7f9584a
--- /dev/null
+++ b/vendor/symfony/cache/Exception/InvalidArgumentException.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Exception;
+
+use Psr\Cache\InvalidArgumentException as Psr6CacheInterface;
+use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface;
+
+if (interface_exists(SimpleCacheInterface::class)) {
+ class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface
+ {
+ }
+} else {
+ class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface
+ {
+ }
+}
diff --git a/vendor/symfony/cache/Exception/LogicException.php b/vendor/symfony/cache/Exception/LogicException.php
new file mode 100644
index 0000000..9ffa7ed
--- /dev/null
+++ b/vendor/symfony/cache/Exception/LogicException.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Exception;
+
+use Psr\Cache\CacheException as Psr6CacheInterface;
+use Psr\SimpleCache\CacheException as SimpleCacheInterface;
+
+if (interface_exists(SimpleCacheInterface::class)) {
+ class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface
+ {
+ }
+} else {
+ class LogicException extends \LogicException implements Psr6CacheInterface
+ {
+ }
+}
diff --git a/vendor/symfony/cache/LICENSE b/vendor/symfony/cache/LICENSE
new file mode 100644
index 0000000..0223acd
--- /dev/null
+++ b/vendor/symfony/cache/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2016-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/symfony/cache/LockRegistry.php b/vendor/symfony/cache/LockRegistry.php
new file mode 100644
index 0000000..d0c5fc5
--- /dev/null
+++ b/vendor/symfony/cache/LockRegistry.php
@@ -0,0 +1,165 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache;
+
+use Psr\Log\LoggerInterface;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\Cache\ItemInterface;
+
+/**
+ * LockRegistry is used internally by existing adapters to protect against cache stampede.
+ *
+ * It does so by wrapping the computation of items in a pool of locks.
+ * Foreach each apps, there can be at most 20 concurrent processes that
+ * compute items at the same time and only one per cache-key.
+ *
+ * @author Nicolas Grekas
+ */
+final class LockRegistry
+{
+ private static $openedFiles = [];
+ private static $lockedFiles;
+ private static $signalingException;
+ private static $signalingCallback;
+
+ /**
+ * The number of items in this list controls the max number of concurrent processes.
+ */
+ private static $files = [
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractTagAwareAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AdapterInterface.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ApcuAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ArrayAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ChainAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'CouchbaseBucketAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'CouchbaseCollectionAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'DoctrineAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'DoctrineDbalAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemTagAwareAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'MemcachedAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'NullAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ParameterNormalizer.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PdoAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpArrayAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpFilesAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ProxyAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'Psr16Adapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisTagAwareAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapterInterface.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableAdapter.php',
+ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableTagAwareAdapter.php',
+ ];
+
+ /**
+ * Defines a set of existing files that will be used as keys to acquire locks.
+ *
+ * @return array The previously defined set of files
+ */
+ public static function setFiles(array $files): array
+ {
+ $previousFiles = self::$files;
+ self::$files = $files;
+
+ foreach (self::$openedFiles as $file) {
+ if ($file) {
+ flock($file, \LOCK_UN);
+ fclose($file);
+ }
+ }
+ self::$openedFiles = self::$lockedFiles = [];
+
+ return $previousFiles;
+ }
+
+ public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, ?\Closure $setMetadata = null, ?LoggerInterface $logger = null)
+ {
+ if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) {
+ // disable locking on Windows by default
+ self::$files = self::$lockedFiles = [];
+ }
+
+ $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1;
+
+ if ($key < 0 || self::$lockedFiles || !$lock = self::open($key)) {
+ return $callback($item, $save);
+ }
+
+ self::$signalingException ?? self::$signalingException = unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}");
+ self::$signalingCallback ?? self::$signalingCallback = function () { throw self::$signalingException; };
+
+ while (true) {
+ try {
+ $locked = false;
+ // race to get the lock in non-blocking mode
+ $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock);
+
+ if ($locked || !$wouldBlock) {
+ $logger && $logger->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]);
+ self::$lockedFiles[$key] = true;
+
+ $value = $callback($item, $save);
+
+ if ($save) {
+ if ($setMetadata) {
+ $setMetadata($item);
+ }
+
+ $pool->save($item->set($value));
+ $save = false;
+ }
+
+ return $value;
+ }
+ // if we failed the race, retry locking in blocking mode to wait for the winner
+ $logger && $logger->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]);
+ flock($lock, \LOCK_SH);
+ } finally {
+ flock($lock, \LOCK_UN);
+ unset(self::$lockedFiles[$key]);
+ }
+
+ try {
+ $value = $pool->get($item->getKey(), self::$signalingCallback, 0);
+ $logger && $logger->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]);
+ $save = false;
+
+ return $value;
+ } catch (\Exception $e) {
+ if (self::$signalingException !== $e) {
+ throw $e;
+ }
+ $logger && $logger->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]);
+ }
+ }
+
+ return null;
+ }
+
+ private static function open(int $key)
+ {
+ if (null !== $h = self::$openedFiles[$key] ?? null) {
+ return $h;
+ }
+ set_error_handler(function () {});
+ try {
+ $h = fopen(self::$files[$key], 'r+');
+ } finally {
+ restore_error_handler();
+ }
+
+ return self::$openedFiles[$key] = $h ?: @fopen(self::$files[$key], 'r');
+ }
+}
diff --git a/vendor/symfony/cache/Marshaller/DefaultMarshaller.php b/vendor/symfony/cache/Marshaller/DefaultMarshaller.php
new file mode 100644
index 0000000..43f7e7e
--- /dev/null
+++ b/vendor/symfony/cache/Marshaller/DefaultMarshaller.php
@@ -0,0 +1,104 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Marshaller;
+
+use Symfony\Component\Cache\Exception\CacheException;
+
+/**
+ * Serializes/unserializes values using igbinary_serialize() if available, serialize() otherwise.
+ *
+ * @author Nicolas Grekas
+ */
+class DefaultMarshaller implements MarshallerInterface
+{
+ private $useIgbinarySerialize = true;
+ private $throwOnSerializationFailure;
+
+ public function __construct(?bool $useIgbinarySerialize = null, bool $throwOnSerializationFailure = false)
+ {
+ if (null === $useIgbinarySerialize) {
+ $useIgbinarySerialize = \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.6', phpversion('igbinary'), '<='));
+ } elseif ($useIgbinarySerialize && (!\extension_loaded('igbinary') || (\PHP_VERSION_ID >= 70400 && version_compare('3.1.6', phpversion('igbinary'), '>')))) {
+ throw new CacheException(\extension_loaded('igbinary') && \PHP_VERSION_ID >= 70400 ? 'Please upgrade the "igbinary" PHP extension to v3.1.6 or higher.' : 'The "igbinary" PHP extension is not loaded.');
+ }
+ $this->useIgbinarySerialize = $useIgbinarySerialize;
+ $this->throwOnSerializationFailure = $throwOnSerializationFailure;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function marshall(array $values, ?array &$failed): array
+ {
+ $serialized = $failed = [];
+
+ foreach ($values as $id => $value) {
+ try {
+ if ($this->useIgbinarySerialize) {
+ $serialized[$id] = igbinary_serialize($value);
+ } else {
+ $serialized[$id] = serialize($value);
+ }
+ } catch (\Exception $e) {
+ if ($this->throwOnSerializationFailure) {
+ throw new \ValueError($e->getMessage(), 0, $e);
+ }
+ $failed[] = $id;
+ }
+ }
+
+ return $serialized;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function unmarshall(string $value)
+ {
+ if ('b:0;' === $value) {
+ return false;
+ }
+ if ('N;' === $value) {
+ return null;
+ }
+ static $igbinaryNull;
+ if ($value === ($igbinaryNull ?? $igbinaryNull = \extension_loaded('igbinary') ? igbinary_serialize(null) : false)) {
+ return null;
+ }
+ $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
+ try {
+ if (':' === ($value[1] ?? ':')) {
+ if (false !== $value = unserialize($value)) {
+ return $value;
+ }
+ } elseif (false === $igbinaryNull) {
+ throw new \RuntimeException('Failed to unserialize values, did you forget to install the "igbinary" extension?');
+ } elseif (null !== $value = igbinary_unserialize($value)) {
+ return $value;
+ }
+
+ throw new \DomainException(error_get_last() ? error_get_last()['message'] : 'Failed to unserialize values.');
+ } catch (\Error $e) {
+ throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
+ } finally {
+ ini_set('unserialize_callback_func', $unserializeCallbackHandler);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public static function handleUnserializeCallback(string $class)
+ {
+ throw new \DomainException('Class not found: '.$class);
+ }
+}
diff --git a/vendor/symfony/cache/Marshaller/DeflateMarshaller.php b/vendor/symfony/cache/Marshaller/DeflateMarshaller.php
new file mode 100644
index 0000000..5544806
--- /dev/null
+++ b/vendor/symfony/cache/Marshaller/DeflateMarshaller.php
@@ -0,0 +1,53 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Marshaller;
+
+use Symfony\Component\Cache\Exception\CacheException;
+
+/**
+ * Compresses values using gzdeflate().
+ *
+ * @author Nicolas Grekas
+ */
+class DeflateMarshaller implements MarshallerInterface
+{
+ private $marshaller;
+
+ public function __construct(MarshallerInterface $marshaller)
+ {
+ if (!\function_exists('gzdeflate')) {
+ throw new CacheException('The "zlib" PHP extension is not loaded.');
+ }
+
+ $this->marshaller = $marshaller;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function marshall(array $values, ?array &$failed): array
+ {
+ return array_map('gzdeflate', $this->marshaller->marshall($values, $failed));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function unmarshall(string $value)
+ {
+ if (false !== $inflatedValue = @gzinflate($value)) {
+ $value = $inflatedValue;
+ }
+
+ return $this->marshaller->unmarshall($value);
+ }
+}
diff --git a/vendor/symfony/cache/Marshaller/MarshallerInterface.php b/vendor/symfony/cache/Marshaller/MarshallerInterface.php
new file mode 100644
index 0000000..cdd6c40
--- /dev/null
+++ b/vendor/symfony/cache/Marshaller/MarshallerInterface.php
@@ -0,0 +1,40 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Marshaller;
+
+/**
+ * Serializes/unserializes PHP values.
+ *
+ * Implementations of this interface MUST deal with errors carefully. They MUST
+ * also deal with forward and backward compatibility at the storage format level.
+ *
+ * @author Nicolas Grekas
+ */
+interface MarshallerInterface
+{
+ /**
+ * Serializes a list of values.
+ *
+ * When serialization fails for a specific value, no exception should be
+ * thrown. Instead, its key should be listed in $failed.
+ */
+ public function marshall(array $values, ?array &$failed): array;
+
+ /**
+ * Unserializes a single value and throws an exception if anything goes wrong.
+ *
+ * @return mixed
+ *
+ * @throws \Exception Whenever unserialization fails
+ */
+ public function unmarshall(string $value);
+}
diff --git a/vendor/symfony/cache/Marshaller/SodiumMarshaller.php b/vendor/symfony/cache/Marshaller/SodiumMarshaller.php
new file mode 100644
index 0000000..7895ef5
--- /dev/null
+++ b/vendor/symfony/cache/Marshaller/SodiumMarshaller.php
@@ -0,0 +1,80 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Marshaller;
+
+use Symfony\Component\Cache\Exception\CacheException;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+
+/**
+ * Encrypt/decrypt values using Libsodium.
+ *
+ * @author Ahmed TAILOULOUTE
+ */
+class TagAwareMarshaller implements MarshallerInterface
+{
+ private $marshaller;
+
+ public function __construct(?MarshallerInterface $marshaller = null)
+ {
+ $this->marshaller = $marshaller ?? new DefaultMarshaller();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function marshall(array $values, ?array &$failed): array
+ {
+ $failed = $notSerialized = $serialized = [];
+
+ foreach ($values as $id => $value) {
+ if (\is_array($value) && \is_array($value['tags'] ?? null) && \array_key_exists('value', $value) && \count($value) === 2 + (\is_string($value['meta'] ?? null) && 8 === \strlen($value['meta']))) {
+ // if the value is an array with keys "tags", "value" and "meta", use a compact serialization format
+ // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F allow detecting this format quickly in unmarshall()
+
+ $v = $this->marshaller->marshall($value, $f);
+
+ if ($f) {
+ $f = [];
+ $failed[] = $id;
+ } else {
+ if ([] === $value['tags']) {
+ $v['tags'] = '';
+ }
+
+ $serialized[$id] = "\x9D".($value['meta'] ?? "\0\0\0\0\0\0\0\0").pack('N', \strlen($v['tags'])).$v['tags'].$v['value'];
+ $serialized[$id][9] = "\x5F";
+ }
+ } else {
+ // other arbitrary values are serialized using the decorated marshaller below
+ $notSerialized[$id] = $value;
+ }
+ }
+
+ if ($notSerialized) {
+ $serialized += $this->marshaller->marshall($notSerialized, $f);
+ $failed = array_merge($failed, $f);
+ }
+
+ return $serialized;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function unmarshall(string $value)
+ {
+ // detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
+ if (13 >= \strlen($value) || "\x9D" !== $value[0] || "\0" !== $value[5] || "\x5F" !== $value[9]) {
+ return $this->marshaller->unmarshall($value);
+ }
+
+ // data consists of value, tags and metadata which we need to unpack
+ $meta = substr($value, 1, 12);
+ $meta[8] = "\0";
+ $tagLen = unpack('Nlen', $meta, 8)['len'];
+ $meta = substr($meta, 0, 8);
+
+ return [
+ 'value' => $this->marshaller->unmarshall(substr($value, 13 + $tagLen)),
+ 'tags' => $tagLen ? $this->marshaller->unmarshall(substr($value, 13, $tagLen)) : [],
+ 'meta' => "\0\0\0\0\0\0\0\0" === $meta ? null : $meta,
+ ];
+ }
+}
diff --git a/vendor/symfony/cache/Messenger/EarlyExpirationDispatcher.php b/vendor/symfony/cache/Messenger/EarlyExpirationDispatcher.php
new file mode 100644
index 0000000..e09e282
--- /dev/null
+++ b/vendor/symfony/cache/Messenger/EarlyExpirationDispatcher.php
@@ -0,0 +1,61 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Messenger;
+
+use Psr\Log\LoggerInterface;
+use Symfony\Component\Cache\Adapter\AdapterInterface;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\DependencyInjection\ReverseContainer;
+use Symfony\Component\Messenger\MessageBusInterface;
+use Symfony\Component\Messenger\Stamp\HandledStamp;
+
+/**
+ * Sends the computation of cached values to a message bus.
+ */
+class EarlyExpirationDispatcher
+{
+ private $bus;
+ private $reverseContainer;
+ private $callbackWrapper;
+
+ public function __construct(MessageBusInterface $bus, ReverseContainer $reverseContainer, ?callable $callbackWrapper = null)
+ {
+ $this->bus = $bus;
+ $this->reverseContainer = $reverseContainer;
+ $this->callbackWrapper = $callbackWrapper;
+ }
+
+ public function __invoke(callable $callback, CacheItem $item, bool &$save, AdapterInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger = null)
+ {
+ if (!$item->isHit() || null === $message = EarlyExpirationMessage::create($this->reverseContainer, $callback, $item, $pool)) {
+ // The item is stale or the callback cannot be reversed: we must compute the value now
+ $logger && $logger->info('Computing item "{key}" online: '.($item->isHit() ? 'callback cannot be reversed' : 'item is stale'), ['key' => $item->getKey()]);
+
+ return null !== $this->callbackWrapper ? ($this->callbackWrapper)($callback, $item, $save, $pool, $setMetadata, $logger) : $callback($item, $save);
+ }
+
+ $envelope = $this->bus->dispatch($message);
+
+ if ($logger) {
+ if ($envelope->last(HandledStamp::class)) {
+ $logger->info('Item "{key}" was computed online', ['key' => $item->getKey()]);
+ } else {
+ $logger->info('Item "{key}" sent for recomputation', ['key' => $item->getKey()]);
+ }
+ }
+
+ // The item's value is not stale, no need to write it to the backend
+ $save = false;
+
+ return $message->getItem()->get() ?? $item->get();
+ }
+}
diff --git a/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php b/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php
new file mode 100644
index 0000000..9e53f5d
--- /dev/null
+++ b/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Messenger;
+
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\DependencyInjection\ReverseContainer;
+use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
+
+/**
+ * Computes cached values sent to a message bus.
+ */
+class EarlyExpirationHandler implements MessageHandlerInterface
+{
+ private $reverseContainer;
+ private $processedNonces = [];
+
+ public function __construct(ReverseContainer $reverseContainer)
+ {
+ $this->reverseContainer = $reverseContainer;
+ }
+
+ public function __invoke(EarlyExpirationMessage $message)
+ {
+ $item = $message->getItem();
+ $metadata = $item->getMetadata();
+ $expiry = $metadata[CacheItem::METADATA_EXPIRY] ?? 0;
+ $ctime = $metadata[CacheItem::METADATA_CTIME] ?? 0;
+
+ if ($expiry && $ctime) {
+ // skip duplicate or expired messages
+
+ $processingNonce = [$expiry, $ctime];
+ $pool = $message->getPool();
+ $key = $item->getKey();
+
+ if (($this->processedNonces[$pool][$key] ?? null) === $processingNonce) {
+ return;
+ }
+
+ if (microtime(true) >= $expiry) {
+ return;
+ }
+
+ $this->processedNonces[$pool] = [$key => $processingNonce] + ($this->processedNonces[$pool] ?? []);
+
+ if (\count($this->processedNonces[$pool]) > 100) {
+ array_pop($this->processedNonces[$pool]);
+ }
+ }
+
+ static $setMetadata;
+
+ $setMetadata ?? $setMetadata = \Closure::bind(
+ function (CacheItem $item, float $startTime) {
+ if ($item->expiry > $endTime = microtime(true)) {
+ $item->newMetadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
+ $item->newMetadata[CacheItem::METADATA_CTIME] = (int) ceil(1000 * ($endTime - $startTime));
+ }
+ },
+ null,
+ CacheItem::class
+ );
+
+ $startTime = microtime(true);
+ $pool = $message->findPool($this->reverseContainer);
+ $callback = $message->findCallback($this->reverseContainer);
+ $save = true;
+ $value = $callback($item, $save);
+ $setMetadata($item, $startTime);
+ $pool->save($item->set($value));
+ }
+}
diff --git a/vendor/symfony/cache/Messenger/EarlyExpirationMessage.php b/vendor/symfony/cache/Messenger/EarlyExpirationMessage.php
new file mode 100644
index 0000000..e25c07e
--- /dev/null
+++ b/vendor/symfony/cache/Messenger/EarlyExpirationMessage.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Messenger;
+
+use Symfony\Component\Cache\Adapter\AdapterInterface;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\DependencyInjection\ReverseContainer;
+
+/**
+ * Conveys a cached value that needs to be computed.
+ */
+final class EarlyExpirationMessage
+{
+ private $item;
+ private $pool;
+ private $callback;
+
+ public static function create(ReverseContainer $reverseContainer, callable $callback, CacheItem $item, AdapterInterface $pool): ?self
+ {
+ try {
+ $item = clone $item;
+ $item->set(null);
+ } catch (\Exception $e) {
+ return null;
+ }
+
+ $pool = $reverseContainer->getId($pool);
+
+ if (\is_object($callback)) {
+ if (null === $id = $reverseContainer->getId($callback)) {
+ return null;
+ }
+
+ $callback = '@'.$id;
+ } elseif (!\is_array($callback)) {
+ $callback = (string) $callback;
+ } elseif (!\is_object($callback[0])) {
+ $callback = [(string) $callback[0], (string) $callback[1]];
+ } else {
+ if (null === $id = $reverseContainer->getId($callback[0])) {
+ return null;
+ }
+
+ $callback = ['@'.$id, (string) $callback[1]];
+ }
+
+ return new self($item, $pool, $callback);
+ }
+
+ public function getItem(): CacheItem
+ {
+ return $this->item;
+ }
+
+ public function getPool(): string
+ {
+ return $this->pool;
+ }
+
+ public function getCallback()
+ {
+ return $this->callback;
+ }
+
+ public function findPool(ReverseContainer $reverseContainer): AdapterInterface
+ {
+ return $reverseContainer->getService($this->pool);
+ }
+
+ public function findCallback(ReverseContainer $reverseContainer): callable
+ {
+ if (\is_string($callback = $this->callback)) {
+ return '@' === $callback[0] ? $reverseContainer->getService(substr($callback, 1)) : $callback;
+ }
+ if ('@' === $callback[0][0]) {
+ $callback[0] = $reverseContainer->getService(substr($callback[0], 1));
+ }
+
+ return $callback;
+ }
+
+ private function __construct(CacheItem $item, string $pool, $callback)
+ {
+ $this->item = $item;
+ $this->pool = $pool;
+ $this->callback = $callback;
+ }
+}
diff --git a/vendor/symfony/cache/PruneableInterface.php b/vendor/symfony/cache/PruneableInterface.php
new file mode 100644
index 0000000..4261525
--- /dev/null
+++ b/vendor/symfony/cache/PruneableInterface.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache;
+
+/**
+ * Interface extends psr-6 and psr-16 caches to allow for pruning (deletion) of all expired cache items.
+ */
+interface PruneableInterface
+{
+ /**
+ * @return bool
+ */
+ public function prune();
+}
diff --git a/vendor/symfony/cache/Psr16Cache.php b/vendor/symfony/cache/Psr16Cache.php
new file mode 100644
index 0000000..28c7de6
--- /dev/null
+++ b/vendor/symfony/cache/Psr16Cache.php
@@ -0,0 +1,289 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache;
+
+use Psr\Cache\CacheException as Psr6CacheException;
+use Psr\Cache\CacheItemPoolInterface;
+use Psr\SimpleCache\CacheException as SimpleCacheException;
+use Psr\SimpleCache\CacheInterface;
+use Symfony\Component\Cache\Adapter\AdapterInterface;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Traits\ProxyTrait;
+
+if (null !== (new \ReflectionMethod(CacheInterface::class, 'get'))->getReturnType()) {
+ throw new \LogicException('psr/simple-cache 3.0+ is not compatible with this version of symfony/cache. Please upgrade symfony/cache to 6.0+ or downgrade psr/simple-cache to 1.x or 2.x.');
+}
+
+/**
+ * Turns a PSR-6 cache into a PSR-16 one.
+ *
+ * @author Nicolas Grekas
+ */
+class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterface
+{
+ use ProxyTrait;
+
+ private const METADATA_EXPIRY_OFFSET = 1527506807;
+
+ private $createCacheItem;
+ private $cacheItemPrototype;
+
+ public function __construct(CacheItemPoolInterface $pool)
+ {
+ $this->pool = $pool;
+
+ if (!$pool instanceof AdapterInterface) {
+ return;
+ }
+ $cacheItemPrototype = &$this->cacheItemPrototype;
+ $createCacheItem = \Closure::bind(
+ static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) {
+ $item = clone $cacheItemPrototype;
+ $item->poolHash = $item->innerItem = null;
+ if ($allowInt && \is_int($key)) {
+ $item->key = (string) $key;
+ } else {
+ \assert('' !== CacheItem::validateKey($key));
+ $item->key = $key;
+ }
+ $item->value = $value;
+ $item->isHit = false;
+
+ return $item;
+ },
+ null,
+ CacheItem::class
+ );
+ $this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) {
+ if (null === $this->cacheItemPrototype) {
+ $this->get($allowInt && \is_int($key) ? (string) $key : $key);
+ }
+ $this->createCacheItem = $createCacheItem;
+
+ return $createCacheItem($key, null, $allowInt)->set($value);
+ };
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return mixed
+ */
+ public function get($key, $default = null)
+ {
+ try {
+ $item = $this->pool->getItem($key);
+ } catch (SimpleCacheException $e) {
+ throw $e;
+ } catch (Psr6CacheException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+ if (null === $this->cacheItemPrototype) {
+ $this->cacheItemPrototype = clone $item;
+ $this->cacheItemPrototype->set(null);
+ }
+
+ return $item->isHit() ? $item->get() : $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function set($key, $value, $ttl = null)
+ {
+ try {
+ if (null !== $f = $this->createCacheItem) {
+ $item = $f($key, $value);
+ } else {
+ $item = $this->pool->getItem($key)->set($value);
+ }
+ } catch (SimpleCacheException $e) {
+ throw $e;
+ } catch (Psr6CacheException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+ if (null !== $ttl) {
+ $item->expiresAfter($ttl);
+ }
+
+ return $this->pool->save($item);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function delete($key)
+ {
+ try {
+ return $this->pool->deleteItem($key);
+ } catch (SimpleCacheException $e) {
+ throw $e;
+ } catch (Psr6CacheException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function clear()
+ {
+ return $this->pool->clear();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return iterable
+ */
+ public function getMultiple($keys, $default = null)
+ {
+ if ($keys instanceof \Traversable) {
+ $keys = iterator_to_array($keys, false);
+ } elseif (!\is_array($keys)) {
+ throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', get_debug_type($keys)));
+ }
+
+ try {
+ $items = $this->pool->getItems($keys);
+ } catch (SimpleCacheException $e) {
+ throw $e;
+ } catch (Psr6CacheException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+ $values = [];
+
+ if (!$this->pool instanceof AdapterInterface) {
+ foreach ($items as $key => $item) {
+ $values[$key] = $item->isHit() ? $item->get() : $default;
+ }
+
+ return $values;
+ }
+
+ foreach ($items as $key => $item) {
+ if (!$item->isHit()) {
+ $values[$key] = $default;
+ continue;
+ }
+ $values[$key] = $item->get();
+
+ if (!$metadata = $item->getMetadata()) {
+ continue;
+ }
+ unset($metadata[CacheItem::METADATA_TAGS]);
+
+ if ($metadata) {
+ $values[$key] = ["\x9D".pack('VN', (int) (0.1 + $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]];
+ }
+ }
+
+ return $values;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function setMultiple($values, $ttl = null)
+ {
+ $valuesIsArray = \is_array($values);
+ if (!$valuesIsArray && !$values instanceof \Traversable) {
+ throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given.', get_debug_type($values)));
+ }
+ $items = [];
+
+ try {
+ if (null !== $f = $this->createCacheItem) {
+ $valuesIsArray = false;
+ foreach ($values as $key => $value) {
+ $items[$key] = $f($key, $value, true);
+ }
+ } elseif ($valuesIsArray) {
+ $items = [];
+ foreach ($values as $key => $value) {
+ $items[] = (string) $key;
+ }
+ $items = $this->pool->getItems($items);
+ } else {
+ foreach ($values as $key => $value) {
+ if (\is_int($key)) {
+ $key = (string) $key;
+ }
+ $items[$key] = $this->pool->getItem($key)->set($value);
+ }
+ }
+ } catch (SimpleCacheException $e) {
+ throw $e;
+ } catch (Psr6CacheException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+ $ok = true;
+
+ foreach ($items as $key => $item) {
+ if ($valuesIsArray) {
+ $item->set($values[$key]);
+ }
+ if (null !== $ttl) {
+ $item->expiresAfter($ttl);
+ }
+ $ok = $this->pool->saveDeferred($item) && $ok;
+ }
+
+ return $this->pool->commit() && $ok;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function deleteMultiple($keys)
+ {
+ if ($keys instanceof \Traversable) {
+ $keys = iterator_to_array($keys, false);
+ } elseif (!\is_array($keys)) {
+ throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', get_debug_type($keys)));
+ }
+
+ try {
+ return $this->pool->deleteItems($keys);
+ } catch (SimpleCacheException $e) {
+ throw $e;
+ } catch (Psr6CacheException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function has($key)
+ {
+ try {
+ return $this->pool->hasItem($key);
+ } catch (SimpleCacheException $e) {
+ throw $e;
+ } catch (Psr6CacheException $e) {
+ throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+}
diff --git a/vendor/symfony/cache/README.md b/vendor/symfony/cache/README.md
new file mode 100644
index 0000000..c466d57
--- /dev/null
+++ b/vendor/symfony/cache/README.md
@@ -0,0 +1,19 @@
+Symfony PSR-6 implementation for caching
+========================================
+
+The Cache component provides extended
+[PSR-6](https://www.php-fig.org/psr/psr-6/) implementations for adding cache to
+your applications. It is designed to have a low overhead so that caching is
+fastest. It ships with adapters for the most widespread caching backends.
+It also provides a [PSR-16](https://www.php-fig.org/psr/psr-16/) adapter,
+and implementations for [symfony/cache-contracts](https://github.com/symfony/cache-contracts)'
+`CacheInterface` and `TagAwareCacheInterface`.
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/cache.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/vendor/symfony/cache/ResettableInterface.php b/vendor/symfony/cache/ResettableInterface.php
new file mode 100644
index 0000000..7b0a853
--- /dev/null
+++ b/vendor/symfony/cache/ResettableInterface.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache;
+
+use Symfony\Contracts\Service\ResetInterface;
+
+/**
+ * Resets a pool's local state.
+ */
+interface ResettableInterface extends ResetInterface
+{
+}
diff --git a/vendor/symfony/cache/Traits/AbstractAdapterTrait.php b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php
new file mode 100644
index 0000000..32d78b1
--- /dev/null
+++ b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php
@@ -0,0 +1,427 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+use Psr\Cache\CacheItemInterface;
+use Psr\Log\LoggerAwareTrait;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+
+/**
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+trait AbstractAdapterTrait
+{
+ use LoggerAwareTrait;
+
+ /**
+ * @var \Closure needs to be set by class, signature is function(string
+ *
+ * @internal
+ */
+trait ContractsTrait
+{
+ use CacheTrait {
+ doGet as private contractsGet;
+ }
+
+ private $callbackWrapper;
+ private $computing = [];
+
+ /**
+ * Wraps the callback passed to ->get() in a callable.
+ *
+ * @return callable the previous callback wrapper
+ */
+ public function setCallbackWrapper(?callable $callbackWrapper): callable
+ {
+ if (!isset($this->callbackWrapper)) {
+ $this->callbackWrapper = \Closure::fromCallable([LockRegistry::class, 'compute']);
+
+ if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
+ $this->setCallbackWrapper(null);
+ }
+ }
+
+ $previousWrapper = $this->callbackWrapper;
+ $this->callbackWrapper = $callbackWrapper ?? static function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
+ return $callback($item, $save);
+ };
+
+ return $previousWrapper;
+ }
+
+ private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null)
+ {
+ if (0 > $beta = $beta ?? 1.0) {
+ throw new InvalidArgumentException(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta));
+ }
+
+ static $setMetadata;
+
+ $setMetadata ?? $setMetadata = \Closure::bind(
+ static function (CacheItem $item, float $startTime, ?array &$metadata) {
+ if ($item->expiry > $endTime = microtime(true)) {
+ $item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
+ $item->newMetadata[CacheItem::METADATA_CTIME] = $metadata[CacheItem::METADATA_CTIME] = (int) ceil(1000 * ($endTime - $startTime));
+ } else {
+ unset($metadata[CacheItem::METADATA_EXPIRY], $metadata[CacheItem::METADATA_CTIME]);
+ }
+ },
+ null,
+ CacheItem::class
+ );
+
+ return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) {
+ // don't wrap nor save recursive calls
+ if (isset($this->computing[$key])) {
+ $value = $callback($item, $save);
+ $save = false;
+
+ return $value;
+ }
+
+ $this->computing[$key] = $key;
+ $startTime = microtime(true);
+
+ if (!isset($this->callbackWrapper)) {
+ $this->setCallbackWrapper($this->setCallbackWrapper(null));
+ }
+
+ try {
+ $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
+ $setMetadata($item, $startTime, $metadata);
+ }, $this->logger ?? null);
+ $setMetadata($item, $startTime, $metadata);
+
+ return $value;
+ } finally {
+ unset($this->computing[$key]);
+ }
+ }, $beta, $metadata, $this->logger ?? null);
+ }
+}
diff --git a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php
new file mode 100644
index 0000000..ab7e7dd
--- /dev/null
+++ b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php
@@ -0,0 +1,210 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+
+/**
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+trait FilesystemCommonTrait
+{
+ private $directory;
+ private $tmp;
+
+ private function init(string $namespace, ?string $directory)
+ {
+ if (!isset($directory[0])) {
+ $directory = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'symfony-cache';
+ } else {
+ $directory = realpath($directory) ?: $directory;
+ }
+ if (isset($namespace[0])) {
+ if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
+ throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
+ }
+ $directory .= \DIRECTORY_SEPARATOR.$namespace;
+ } else {
+ $directory .= \DIRECTORY_SEPARATOR.'@';
+ }
+ if (!is_dir($directory)) {
+ @mkdir($directory, 0777, true);
+ }
+ $directory .= \DIRECTORY_SEPARATOR;
+ // On Windows the whole path is limited to 258 chars
+ if ('\\' === \DIRECTORY_SEPARATOR && \strlen($directory) > 234) {
+ throw new InvalidArgumentException(sprintf('Cache directory too long (%s).', $directory));
+ }
+
+ $this->directory = $directory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doClear(string $namespace)
+ {
+ $ok = true;
+
+ foreach ($this->scanHashDir($this->directory) as $file) {
+ if ('' !== $namespace && !str_starts_with($this->getFileKey($file), $namespace)) {
+ continue;
+ }
+
+ $ok = ($this->doUnlink($file) || !file_exists($file)) && $ok;
+ }
+
+ return $ok;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doDelete(array $ids)
+ {
+ $ok = true;
+
+ foreach ($ids as $id) {
+ $file = $this->getFile($id);
+ $ok = (!is_file($file) || $this->doUnlink($file) || !file_exists($file)) && $ok;
+ }
+
+ return $ok;
+ }
+
+ protected function doUnlink(string $file)
+ {
+ return @unlink($file);
+ }
+
+ private function write(string $file, string $data, ?int $expiresAt = null)
+ {
+ $unlink = false;
+ set_error_handler(__CLASS__.'::throwError');
+ try {
+ if (null === $this->tmp) {
+ $this->tmp = $this->directory.bin2hex(random_bytes(6));
+ }
+ try {
+ $h = fopen($this->tmp, 'x');
+ } catch (\ErrorException $e) {
+ if (!str_contains($e->getMessage(), 'File exists')) {
+ throw $e;
+ }
+
+ $this->tmp = $this->directory.bin2hex(random_bytes(6));
+ $h = fopen($this->tmp, 'x');
+ }
+ fwrite($h, $data);
+ fclose($h);
+ $unlink = true;
+
+ if (null !== $expiresAt) {
+ touch($this->tmp, $expiresAt ?: time() + 31556952); // 1 year in seconds
+ }
+
+ if ('\\' === \DIRECTORY_SEPARATOR) {
+ $success = copy($this->tmp, $file);
+ $unlink = true;
+ } else {
+ $success = rename($this->tmp, $file);
+ $unlink = !$success;
+ }
+
+ return $success;
+ } finally {
+ restore_error_handler();
+
+ if ($unlink) {
+ @unlink($this->tmp);
+ }
+ }
+ }
+
+ private function getFile(string $id, bool $mkdir = false, ?string $directory = null)
+ {
+ // Use MD5 to favor speed over security, which is not an issue here
+ $hash = str_replace('/', '-', base64_encode(hash('md5', static::class.$id, true)));
+ $dir = ($directory ?? $this->directory).strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR);
+
+ if ($mkdir && !is_dir($dir)) {
+ @mkdir($dir, 0777, true);
+ }
+
+ return $dir.substr($hash, 2, 20);
+ }
+
+ private function getFileKey(string $file): string
+ {
+ return '';
+ }
+
+ private function scanHashDir(string $directory): \Generator
+ {
+ if (!is_dir($directory)) {
+ return;
+ }
+
+ $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+
+ for ($i = 0; $i < 38; ++$i) {
+ if (!is_dir($directory.$chars[$i])) {
+ continue;
+ }
+
+ for ($j = 0; $j < 38; ++$j) {
+ if (!is_dir($dir = $directory.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) {
+ continue;
+ }
+
+ foreach (@scandir($dir, \SCANDIR_SORT_NONE) ?: [] as $file) {
+ if ('.' !== $file && '..' !== $file) {
+ yield $dir.\DIRECTORY_SEPARATOR.$file;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public static function throwError(int $type, string $message, string $file, int $line)
+ {
+ throw new \ErrorException($message, 0, $type, $file, $line);
+ }
+
+ /**
+ * @return array
+ */
+ public function __sleep()
+ {
+ throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
+ }
+
+ public function __wakeup()
+ {
+ throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
+ }
+
+ public function __destruct()
+ {
+ if (method_exists(parent::class, '__destruct')) {
+ parent::__destruct();
+ }
+ if (null !== $this->tmp && is_file($this->tmp)) {
+ unlink($this->tmp);
+ }
+ }
+}
diff --git a/vendor/symfony/cache/Traits/FilesystemTrait.php b/vendor/symfony/cache/Traits/FilesystemTrait.php
new file mode 100644
index 0000000..f2873d9
--- /dev/null
+++ b/vendor/symfony/cache/Traits/FilesystemTrait.php
@@ -0,0 +1,124 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+use Symfony\Component\Cache\Exception\CacheException;
+
+/**
+ * @author Nicolas Grekas
+ * @author Rob Frawley 2nd
+ *
+ * @internal
+ */
+trait ProxyTrait
+{
+ private $pool;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prune()
+ {
+ return $this->pool instanceof PruneableInterface && $this->pool->prune();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset()
+ {
+ if ($this->pool instanceof ResetInterface) {
+ $this->pool->reset();
+ }
+ }
+}
diff --git a/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php b/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php
new file mode 100644
index 0000000..deba74f
--- /dev/null
+++ b/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php
@@ -0,0 +1,53 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+/**
+ * This file acts as a wrapper to the \RedisCluster implementation so it can accept the same type of calls as
+ * individual \Redis objects.
+ *
+ * Calls are made to individual nodes via: RedisCluster->{method}($host, ...args)'
+ * according to https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#directed-node-commands
+ *
+ * @author Jack Thomas
+ *
+ * @internal
+ */
+class RedisProxy
+{
+ private $redis;
+ private $initializer;
+ private $ready = false;
+
+ public function __construct(\Redis $redis, \Closure $initializer)
+ {
+ $this->redis = $redis;
+ $this->initializer = $initializer;
+ }
+
+ public function __call(string $method, array $args)
+ {
+ $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
+
+ return $this->redis->{$method}(...$args);
+ }
+
+ public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
+ {
+ $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
+
+ return $this->redis->hscan($strKey, $iIterator, $strPattern, $iCount);
+ }
+
+ public function scan(&$iIterator, $strPattern = null, $iCount = null)
+ {
+ $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
+
+ return $this->redis->scan($iIterator, $strPattern, $iCount);
+ }
+
+ public function sscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
+ {
+ $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
+
+ return $this->redis->sscan($strKey, $iIterator, $strPattern, $iCount);
+ }
+
+ public function zscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
+ {
+ $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
+
+ return $this->redis->zscan($strKey, $iIterator, $strPattern, $iCount);
+ }
+}
diff --git a/vendor/symfony/cache/Traits/RedisTrait.php b/vendor/symfony/cache/Traits/RedisTrait.php
new file mode 100644
index 0000000..35695d5
--- /dev/null
+++ b/vendor/symfony/cache/Traits/RedisTrait.php
@@ -0,0 +1,660 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Traits;
+
+use Predis\Command\Redis\UNLINK;
+use Predis\Connection\Aggregate\ClusterInterface;
+use Predis\Connection\Aggregate\RedisCluster;
+use Predis\Connection\Aggregate\ReplicationInterface;
+use Predis\Connection\Cluster\ClusterInterface as Predis2ClusterInterface;
+use Predis\Connection\Cluster\RedisCluster as Predis2RedisCluster;
+use Predis\Response\ErrorInterface;
+use Predis\Response\Status;
+use Symfony\Component\Cache\Exception\CacheException;
+use Symfony\Component\Cache\Exception\InvalidArgumentException;
+use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+use Symfony\Component\Cache\Marshaller\MarshallerInterface;
+
+/**
+ * @author Aurimas Niekis
+ *
+ * @internal
+ */
+trait RedisTrait
+{
+ private static $defaultConnectionOptions = [
+ 'class' => null,
+ 'persistent' => 0,
+ 'persistent_id' => null,
+ 'timeout' => 30,
+ 'read_timeout' => 0,
+ 'retry_interval' => 0,
+ 'tcp_keepalive' => 0,
+ 'lazy' => null,
+ 'redis_cluster' => false,
+ 'redis_sentinel' => null,
+ 'dbindex' => 0,
+ 'failover' => 'none',
+ 'ssl' => null, // see https://php.net/context.ssl
+ ];
+ private $redis;
+ private $marshaller;
+
+ /**
+ * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis
+ */
+ private function init($redis, string $namespace, int $defaultLifetime, ?MarshallerInterface $marshaller)
+ {
+ parent::__construct($namespace, $defaultLifetime);
+
+ if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
+ throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
+ }
+
+ if (!$redis instanceof \Redis && !$redis instanceof \RedisArray && !$redis instanceof \RedisCluster && !$redis instanceof \Predis\ClientInterface && !$redis instanceof RedisProxy && !$redis instanceof RedisClusterProxy) {
+ throw new InvalidArgumentException(sprintf('"%s()" expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\ClientInterface, "%s" given.', __METHOD__, get_debug_type($redis)));
+ }
+
+ if ($redis instanceof \Predis\ClientInterface && $redis->getOptions()->exceptions) {
+ $options = clone $redis->getOptions();
+ \Closure::bind(function () { $this->options['exceptions'] = false; }, $options, $options)();
+ $redis = new $redis($redis->getConnection(), $options);
+ }
+
+ $this->redis = $redis;
+ $this->marshaller = $marshaller ?? new DefaultMarshaller();
+ }
+
+ /**
+ * Creates a Redis connection using a DSN configuration.
+ *
+ * Example DSN:
+ * - redis://localhost
+ * - redis://example.com:1234
+ * - redis://secret@example.com/13
+ * - redis:///var/run/redis.sock
+ * - redis://secret@/var/run/redis.sock/13
+ *
+ * @param array $options See self::$defaultConnectionOptions
+ *
+ * @return \Redis|\RedisArray|\RedisCluster|RedisClusterProxy|RedisProxy|\Predis\ClientInterface According to the "class" option
+ *
+ * @throws InvalidArgumentException when the DSN is invalid
+ */
+ public static function createConnection(string $dsn, array $options = [])
+ {
+ if (str_starts_with($dsn, 'redis:')) {
+ $scheme = 'redis';
+ } elseif (str_starts_with($dsn, 'rediss:')) {
+ $scheme = 'rediss';
+ } else {
+ throw new InvalidArgumentException('Invalid Redis DSN: it does not start with "redis[s]:".');
+ }
+
+ if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) {
+ throw new CacheException('Cannot find the "redis" extension nor the "predis/predis" package.');
+ }
+
+ $params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) {
+ if (isset($m[2])) {
+ $auth = rawurldecode($m[2]);
+
+ if ('' === $auth) {
+ $auth = null;
+ }
+ }
+
+ return 'file:'.($m[1] ?? '');
+ }, $dsn);
+
+ if (false === $params = parse_url($params)) {
+ throw new InvalidArgumentException('Invalid Redis DSN.');
+ }
+
+ $query = $hosts = [];
+
+ $tls = 'rediss' === $scheme;
+ $tcpScheme = $tls ? 'tls' : 'tcp';
+
+ if (isset($params['query'])) {
+ parse_str($params['query'], $query);
+
+ if (isset($query['host'])) {
+ if (!\is_array($hosts = $query['host'])) {
+ throw new InvalidArgumentException('Invalid Redis DSN: query parameter "host" must be an array.');
+ }
+ foreach ($hosts as $host => $parameters) {
+ if (\is_string($parameters)) {
+ parse_str($parameters, $parameters);
+ }
+ if (false === $i = strrpos($host, ':')) {
+ $hosts[$host] = ['scheme' => $tcpScheme, 'host' => $host, 'port' => 6379] + $parameters;
+ } elseif ($port = (int) substr($host, 1 + $i)) {
+ $hosts[$host] = ['scheme' => $tcpScheme, 'host' => substr($host, 0, $i), 'port' => $port] + $parameters;
+ } else {
+ $hosts[$host] = ['scheme' => 'unix', 'path' => substr($host, 0, $i)] + $parameters;
+ }
+ }
+ $hosts = array_values($hosts);
+ }
+ }
+
+ if (isset($params['host']) || isset($params['path'])) {
+ if (!isset($params['dbindex']) && isset($params['path'])) {
+ if (preg_match('#/(\d+)?$#', $params['path'], $m)) {
+ $params['dbindex'] = $m[1] ?? $query['dbindex'] ?? '0';
+ $params['path'] = substr($params['path'], 0, -\strlen($m[0]));
+ } elseif (isset($params['host'])) {
+ throw new InvalidArgumentException('Invalid Redis DSN: parameter "dbindex" must be a number.');
+ }
+ }
+
+ if (isset($params['host'])) {
+ array_unshift($hosts, ['scheme' => $tcpScheme, 'host' => $params['host'], 'port' => $params['port'] ?? 6379]);
+ } else {
+ array_unshift($hosts, ['scheme' => 'unix', 'path' => $params['path']]);
+ }
+ }
+
+ if (!$hosts) {
+ throw new InvalidArgumentException('Invalid Redis DSN: missing host.');
+ }
+
+ if (isset($params['dbindex'], $query['dbindex']) && $params['dbindex'] !== $query['dbindex']) {
+ throw new InvalidArgumentException('Invalid Redis DSN: path and query "dbindex" parameters mismatch.');
+ }
+
+ $params += $query + $options + self::$defaultConnectionOptions;
+
+ if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class) && !class_exists(\RedisSentinel::class)) {
+ throw new CacheException('Redis Sentinel support requires the "predis/predis" package or the "redis" extension v5.2 or higher.');
+ }
+
+ if (isset($params['lazy'])) {
+ $params['lazy'] = filter_var($params['lazy'], \FILTER_VALIDATE_BOOLEAN);
+ }
+ $params['redis_cluster'] = filter_var($params['redis_cluster'], \FILTER_VALIDATE_BOOLEAN);
+
+ if ($params['redis_cluster'] && isset($params['redis_sentinel'])) {
+ throw new InvalidArgumentException('Cannot use both "redis_cluster" and "redis_sentinel" at the same time.');
+ }
+
+ if (null === $params['class'] && \extension_loaded('redis')) {
+ $class = $params['redis_cluster'] ? \RedisCluster::class : (1 < \count($hosts) && !isset($params['redis_sentinel']) ? \RedisArray::class : \Redis::class);
+ } else {
+ $class = $params['class'] ?? \Predis\Client::class;
+
+ if (isset($params['redis_sentinel']) && !is_a($class, \Predis\Client::class, true) && !class_exists(\RedisSentinel::class)) {
+ throw new CacheException(sprintf('Cannot use Redis Sentinel: class "%s" does not extend "Predis\Client" and ext-redis >= 5.2 not found.', $class));
+ }
+ }
+
+ if (is_a($class, \Redis::class, true)) {
+ $connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect';
+ $redis = new $class();
+
+ $initializer = static function ($redis) use ($connect, $params, $auth, $hosts, $tls) {
+ $hostIndex = 0;
+ do {
+ $host = $hosts[$hostIndex]['host'] ?? $hosts[$hostIndex]['path'];
+ $port = $hosts[$hostIndex]['port'] ?? 0;
+ $passAuth = \defined('Redis::OPT_NULL_MULTIBULK_AS_NULL') && isset($params['auth']);
+ $address = false;
+
+ if (isset($hosts[$hostIndex]['host']) && $tls) {
+ $host = 'tls://'.$host;
+ }
+
+ if (!isset($params['redis_sentinel'])) {
+ break;
+ }
+
+ if (version_compare(phpversion('redis'), '6.0.0', '>=')) {
+ $options = [
+ 'host' => $host,
+ 'port' => $port,
+ 'connectTimeout' => (float) $params['timeout'],
+ 'persistent' => $params['persistent_id'],
+ 'retryInterval' => (int) $params['retry_interval'],
+ 'readTimeout' => (float) $params['read_timeout'],
+ ];
+
+ if ($passAuth) {
+ $options['auth'] = $params['auth'];
+ }
+
+ $sentinel = new \RedisSentinel($options);
+ } else {
+ $extra = $passAuth ? [$params['auth']] : [];
+
+ $sentinel = new \RedisSentinel($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...$extra);
+ }
+
+ try {
+ if ($address = $sentinel->getMasterAddrByName($params['redis_sentinel'])) {
+ [$host, $port] = $address;
+ }
+ } catch (\RedisException $e) {
+ }
+ } while (++$hostIndex < \count($hosts) && !$address);
+
+ if (isset($params['redis_sentinel']) && !$address) {
+ throw new InvalidArgumentException(sprintf('Failed to retrieve master information from sentinel "%s".', $params['redis_sentinel']));
+ }
+
+ try {
+ $extra = [
+ 'stream' => $params['ssl'] ?? null,
+ ];
+ $booleanStreamOptions = [
+ 'allow_self_signed',
+ 'capture_peer_cert',
+ 'capture_peer_cert_chain',
+ 'disable_compression',
+ 'SNI_enabled',
+ 'verify_peer',
+ 'verify_peer_name',
+ ];
+
+ foreach ($extra['stream'] ?? [] as $streamOption => $value) {
+ if (\in_array($streamOption, $booleanStreamOptions, true) && \is_string($value)) {
+ $extra['stream'][$streamOption] = filter_var($value, \FILTER_VALIDATE_BOOL);
+ }
+ }
+
+ if (isset($params['auth'])) {
+ $extra['auth'] = $params['auth'];
+ }
+ @$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::SCAN_PREFIX') ? [$extra] : []);
+
+ set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
+ try {
+ $isConnected = $redis->isConnected();
+ } finally {
+ restore_error_handler();
+ }
+ if (!$isConnected) {
+ $error = preg_match('/^Redis::p?connect\(\): (.*)/', $error ?? $redis->getLastError() ?? '', $error) ? sprintf(' (%s)', $error[1]) : '';
+ throw new InvalidArgumentException('Redis connection failed: '.$error.'.');
+ }
+
+ if ((null !== $auth && !$redis->auth($auth))
+ // Due to a bug in phpredis we must always select the dbindex if persistent pooling is enabled
+ // @see https://github.com/phpredis/phpredis/issues/1920
+ // @see https://github.com/symfony/symfony/issues/51578
+ || (($params['dbindex'] || ('pconnect' === $connect && '0' !== \ini_get('redis.pconnect.pooling_enabled'))) && !$redis->select($params['dbindex']))
+ ) {
+ $e = preg_replace('/^ERR /', '', $redis->getLastError());
+ throw new InvalidArgumentException('Redis connection failed: '.$e.'.');
+ }
+
+ if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
+ $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
+ }
+ } catch (\RedisException $e) {
+ throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage());
+ }
+
+ return true;
+ };
+
+ if ($params['lazy']) {
+ $redis = new RedisProxy($redis, $initializer);
+ } else {
+ $initializer($redis);
+ }
+ } elseif (is_a($class, \RedisArray::class, true)) {
+ foreach ($hosts as $i => $host) {
+ switch ($host['scheme']) {
+ case 'tcp': $hosts[$i] = $host['host'].':'.$host['port']; break;
+ case 'tls': $hosts[$i] = 'tls://'.$host['host'].':'.$host['port']; break;
+ default: $hosts[$i] = $host['path'];
+ }
+ }
+ $params['lazy_connect'] = $params['lazy'] ?? true;
+ $params['connect_timeout'] = $params['timeout'];
+
+ try {
+ $redis = new $class($hosts, $params);
+ } catch (\RedisClusterException $e) {
+ throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage());
+ }
+
+ if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
+ $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
+ }
+ } elseif (is_a($class, \RedisCluster::class, true)) {
+ $initializer = static function () use ($class, $params, $hosts) {
+ foreach ($hosts as $i => $host) {
+ switch ($host['scheme']) {
+ case 'tcp': $hosts[$i] = $host['host'].':'.$host['port']; break;
+ case 'tls': $hosts[$i] = 'tls://'.$host['host'].':'.$host['port']; break;
+ default: $hosts[$i] = $host['path'];
+ }
+ }
+
+ try {
+ $redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? '', ...\defined('Redis::SCAN_PREFIX') ? [$params['ssl'] ?? null] : []);
+ } catch (\RedisClusterException $e) {
+ throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage());
+ }
+
+ if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) {
+ $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']);
+ }
+ switch ($params['failover']) {
+ case 'error': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_ERROR); break;
+ case 'distribute': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_DISTRIBUTE); break;
+ case 'slaves': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES); break;
+ }
+
+ return $redis;
+ };
+
+ $redis = $params['lazy'] ? new RedisClusterProxy($initializer) : $initializer();
+ } elseif (is_a($class, \Predis\ClientInterface::class, true)) {
+ if ($params['redis_cluster']) {
+ $params['cluster'] = 'redis';
+ } elseif (isset($params['redis_sentinel'])) {
+ $params['replication'] = 'sentinel';
+ $params['service'] = $params['redis_sentinel'];
+ }
+ $params += ['parameters' => []];
+ $params['parameters'] += [
+ 'persistent' => $params['persistent'],
+ 'timeout' => $params['timeout'],
+ 'read_write_timeout' => $params['read_timeout'],
+ 'tcp_nodelay' => true,
+ ];
+ if ($params['dbindex']) {
+ $params['parameters']['database'] = $params['dbindex'];
+ }
+ if (null !== $auth) {
+ $params['parameters']['password'] = $auth;
+ }
+
+ if (isset($params['ssl'])) {
+ foreach ($hosts as $i => $host) {
+ if (!isset($host['ssl'])) {
+ $hosts[$i]['ssl'] = $params['ssl'];
+ }
+ }
+ }
+
+ if (1 === \count($hosts) && !($params['redis_cluster'] || $params['redis_sentinel'])) {
+ $hosts = $hosts[0];
+ } elseif (\in_array($params['failover'], ['slaves', 'distribute'], true) && !isset($params['replication'])) {
+ $params['replication'] = true;
+ $hosts[0] += ['alias' => 'master'];
+ }
+ $params['exceptions'] = false;
+
+ $redis = new $class($hosts, array_diff_key($params, self::$defaultConnectionOptions));
+ if (isset($params['redis_sentinel'])) {
+ $redis->getConnection()->setSentinelTimeout($params['timeout']);
+ }
+ } elseif (class_exists($class, false)) {
+ throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster" nor "Predis\ClientInterface".', $class));
+ } else {
+ throw new InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
+ }
+
+ return $redis;
+ }
+
+ protected function doFetch(array $ids)
+ {
+ if (!$ids) {
+ return [];
+ }
+
+ $result = [];
+
+ if ($this->redis instanceof \Predis\ClientInterface && ($this->redis->getConnection() instanceof ClusterInterface || $this->redis->getConnection() instanceof Predis2ClusterInterface)) {
+ $values = $this->pipeline(function () use ($ids) {
+ foreach ($ids as $id) {
+ yield 'get' => [$id];
+ }
+ });
+ } else {
+ $values = $this->redis->mget($ids);
+
+ if (!\is_array($values) || \count($values) !== \count($ids)) {
+ return [];
+ }
+
+ $values = array_combine($ids, $values);
+ }
+
+ foreach ($values as $id => $v) {
+ if ($v) {
+ $result[$id] = $this->marshaller->unmarshall($v);
+ }
+ }
+
+ return $result;
+ }
+
+ protected function doHave(string $id)
+ {
+ return (bool) $this->redis->exists($id);
+ }
+
+ protected function doClear(string $namespace)
+ {
+ if ($this->redis instanceof \Predis\ClientInterface) {
+ $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : '';
+ $prefixLen = \strlen($prefix ?? '');
+ }
+
+ $cleared = true;
+ $hosts = $this->getHosts();
+ $host = reset($hosts);
+ if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) {
+ // Predis supports info command only on the master in replication environments
+ $hosts = [$host->getClientFor('master')];
+ }
+
+ foreach ($hosts as $host) {
+ if (!isset($namespace[0])) {
+ $cleared = $host->flushDb() && $cleared;
+ continue;
+ }
+
+ $info = $host->info('Server');
+ $info = !$info instanceof ErrorInterface ? $info['Server'] ?? $info : ['redis_version' => '2.0'];
+
+ if (!$host instanceof \Predis\ClientInterface) {
+ $prefix = \defined('Redis::SCAN_PREFIX') && (\Redis::SCAN_PREFIX & $host->getOption(\Redis::OPT_SCAN)) ? '' : $host->getOption(\Redis::OPT_PREFIX);
+ $prefixLen = \strlen($host->getOption(\Redis::OPT_PREFIX) ?? '');
+ }
+ $pattern = $prefix.$namespace.'*';
+
+ if (!version_compare($info['redis_version'], '2.8', '>=')) {
+ // As documented in Redis documentation (http://redis.io/commands/keys) using KEYS
+ // can hang your server when it is executed against large databases (millions of items).
+ // Whenever you hit this scale, you should really consider upgrading to Redis 2.8 or above.
+ $unlink = version_compare($info['redis_version'], '4.0', '>=') ? 'UNLINK' : 'DEL';
+ $args = $this->redis instanceof \Predis\ClientInterface ? [0, $pattern] : [[$pattern], 0];
+ $cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]) for i=1,#keys,5000 do redis.call('$unlink',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $args[0], $args[1]) && $cleared;
+ continue;
+ }
+
+ $cursor = null;
+ do {
+ $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor ?? 0, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000);
+ if (isset($keys[1]) && \is_array($keys[1])) {
+ $cursor = $keys[0];
+ $keys = $keys[1];
+ }
+ if ($keys) {
+ if ($prefixLen) {
+ foreach ($keys as $i => $key) {
+ $keys[$i] = substr($key, $prefixLen);
+ }
+ }
+ $this->doDelete($keys);
+ }
+ } while ($cursor);
+ }
+
+ return $cleared;
+ }
+
+ protected function doDelete(array $ids)
+ {
+ if (!$ids) {
+ return true;
+ }
+
+ if ($this->redis instanceof \Predis\ClientInterface && ($this->redis->getConnection() instanceof ClusterInterface || $this->redis->getConnection() instanceof Predis2ClusterInterface)) {
+ static $del;
+ $del = $del ?? (class_exists(UNLINK::class) ? 'unlink' : 'del');
+
+ $this->pipeline(function () use ($ids, $del) {
+ foreach ($ids as $id) {
+ yield $del => [$id];
+ }
+ })->rewind();
+ } else {
+ static $unlink = true;
+
+ if ($unlink) {
+ try {
+ $unlink = false !== $this->redis->unlink($ids);
+ } catch (\Throwable $e) {
+ $unlink = false;
+ }
+ }
+
+ if (!$unlink) {
+ $this->redis->del($ids);
+ }
+ }
+
+ return true;
+ }
+
+ protected function doSave(array $values, int $lifetime)
+ {
+ if (!$values = $this->marshaller->marshall($values, $failed)) {
+ return $failed;
+ }
+
+ $results = $this->pipeline(function () use ($values, $lifetime) {
+ foreach ($values as $id => $value) {
+ if (0 >= $lifetime) {
+ yield 'set' => [$id, $value];
+ } else {
+ yield 'setEx' => [$id, $lifetime, $value];
+ }
+ }
+ });
+
+ foreach ($results as $id => $result) {
+ if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) {
+ $failed[] = $id;
+ }
+ }
+
+ return $failed;
+ }
+
+ private function pipeline(\Closure $generator, ?object $redis = null): \Generator
+ {
+ $ids = [];
+ $redis = $redis ?? $this->redis;
+
+ if ($redis instanceof RedisClusterProxy || $redis instanceof \RedisCluster || ($redis instanceof \Predis\ClientInterface && ($redis->getConnection() instanceof RedisCluster || $redis->getConnection() instanceof Predis2RedisCluster))) {
+ // phpredis & predis don't support pipelining with RedisCluster
+ // see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining
+ // see https://github.com/nrk/predis/issues/267#issuecomment-123781423
+ $results = [];
+ foreach ($generator() as $command => $args) {
+ $results[] = $redis->{$command}(...$args);
+ $ids[] = 'eval' === $command ? ($redis instanceof \Predis\ClientInterface ? $args[2] : $args[1][0]) : $args[0];
+ }
+ } elseif ($redis instanceof \Predis\ClientInterface) {
+ $results = $redis->pipeline(static function ($redis) use ($generator, &$ids) {
+ foreach ($generator() as $command => $args) {
+ $redis->{$command}(...$args);
+ $ids[] = 'eval' === $command ? $args[2] : $args[0];
+ }
+ });
+ } elseif ($redis instanceof \RedisArray) {
+ $connections = $results = $ids = [];
+ foreach ($generator() as $command => $args) {
+ $id = 'eval' === $command ? $args[1][0] : $args[0];
+ if (!isset($connections[$h = $redis->_target($id)])) {
+ $connections[$h] = [$redis->_instance($h), -1];
+ $connections[$h][0]->multi(\Redis::PIPELINE);
+ }
+ $connections[$h][0]->{$command}(...$args);
+ $results[] = [$h, ++$connections[$h][1]];
+ $ids[] = $id;
+ }
+ foreach ($connections as $h => $c) {
+ $connections[$h] = $c[0]->exec();
+ }
+ foreach ($results as $k => [$h, $c]) {
+ $results[$k] = $connections[$h][$c];
+ }
+ } else {
+ $redis->multi(\Redis::PIPELINE);
+ foreach ($generator() as $command => $args) {
+ $redis->{$command}(...$args);
+ $ids[] = 'eval' === $command ? $args[1][0] : $args[0];
+ }
+ $results = $redis->exec();
+ }
+
+ if (!$redis instanceof \Predis\ClientInterface && 'eval' === $command && $redis->getLastError()) {
+ $e = new \RedisException($redis->getLastError());
+ $results = array_map(function ($v) use ($e) { return false === $v ? $e : $v; }, (array) $results);
+ }
+
+ if (\is_bool($results)) {
+ return;
+ }
+
+ foreach ($ids as $k => $id) {
+ yield $id => $results[$k];
+ }
+ }
+
+ private function getHosts(): array
+ {
+ $hosts = [$this->redis];
+ if ($this->redis instanceof \Predis\ClientInterface) {
+ $connection = $this->redis->getConnection();
+ if (($connection instanceof ClusterInterface || $connection instanceof Predis2ClusterInterface) && $connection instanceof \Traversable) {
+ $hosts = [];
+ foreach ($connection as $c) {
+ $hosts[] = new \Predis\Client($c);
+ }
+ }
+ } elseif ($this->redis instanceof \RedisArray) {
+ $hosts = [];
+ foreach ($this->redis->_hosts() as $host) {
+ $hosts[] = $this->redis->_instance($host);
+ }
+ } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) {
+ $hosts = [];
+ foreach ($this->redis->_masters() as $host) {
+ $hosts[] = new RedisClusterNodeProxy($host, $this->redis);
+ }
+ }
+
+ return $hosts;
+ }
+}
diff --git a/vendor/symfony/cache/composer.json b/vendor/symfony/cache/composer.json
new file mode 100644
index 0000000..fdf794f
--- /dev/null
+++ b/vendor/symfony/cache/composer.json
@@ -0,0 +1,60 @@
+{
+ "name": "symfony/cache",
+ "type": "library",
+ "description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
+ "keywords": ["caching", "psr6"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "provide": {
+ "psr/cache-implementation": "1.0|2.0",
+ "psr/simple-cache-implementation": "1.0|2.0",
+ "symfony/cache-implementation": "1.0|2.0"
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "psr/cache": "^1.0|^2.0",
+ "psr/log": "^1.1|^2|^3",
+ "symfony/cache-contracts": "^1.1.7|^2",
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/polyfill-php73": "^1.9",
+ "symfony/polyfill-php80": "^1.16",
+ "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/var-exporter": "^4.4|^5.0|^6.0"
+ },
+ "require-dev": {
+ "cache/integration-tests": "dev-master",
+ "doctrine/cache": "^1.6|^2.0",
+ "doctrine/dbal": "^2.13.1|^3|^4",
+ "predis/predis": "^1.1|^2.0",
+ "psr/simple-cache": "^1.0|^2.0",
+ "symfony/config": "^4.4|^5.0|^6.0",
+ "symfony/dependency-injection": "^4.4|^5.0|^6.0",
+ "symfony/filesystem": "^4.4|^5.0|^6.0",
+ "symfony/http-kernel": "^4.4|^5.0|^6.0",
+ "symfony/messenger": "^4.4|^5.0|^6.0",
+ "symfony/var-dumper": "^4.4|^5.0|^6.0"
+ },
+ "conflict": {
+ "doctrine/dbal": "<2.13.1",
+ "symfony/dependency-injection": "<4.4",
+ "symfony/http-kernel": "<4.4",
+ "symfony/var-dumper": "<4.4"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\Cache\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/symfony/deprecation-contracts/CHANGELOG.md b/vendor/symfony/deprecation-contracts/CHANGELOG.md
new file mode 100644
index 0000000..7932e26
--- /dev/null
+++ b/vendor/symfony/deprecation-contracts/CHANGELOG.md
@@ -0,0 +1,5 @@
+CHANGELOG
+=========
+
+The changelog is maintained for all Symfony contracts at the following URL:
+https://github.com/symfony/contracts/blob/main/CHANGELOG.md
diff --git a/vendor/symfony/deprecation-contracts/LICENSE b/vendor/symfony/deprecation-contracts/LICENSE
new file mode 100644
index 0000000..0ed3a24
--- /dev/null
+++ b/vendor/symfony/deprecation-contracts/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2020-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/symfony/deprecation-contracts/README.md b/vendor/symfony/deprecation-contracts/README.md
new file mode 100644
index 0000000..4957933
--- /dev/null
+++ b/vendor/symfony/deprecation-contracts/README.md
@@ -0,0 +1,26 @@
+Symfony Deprecation Contracts
+=============================
+
+A generic function and convention to trigger deprecation notices.
+
+This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices.
+
+By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component,
+the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments.
+
+The function requires at least 3 arguments:
+ - the name of the Composer package that is triggering the deprecation
+ - the version of the package that introduced the deprecation
+ - the message of the deprecation
+ - more arguments can be provided: they will be inserted in the message using `printf()` formatting
+
+Example:
+```php
+trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin');
+```
+
+This will generate the following message:
+`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.`
+
+While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty
+`function trigger_deprecation() {}` in your application.
diff --git a/vendor/symfony/deprecation-contracts/composer.json b/vendor/symfony/deprecation-contracts/composer.json
new file mode 100644
index 0000000..cc7cc12
--- /dev/null
+++ b/vendor/symfony/deprecation-contracts/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "symfony/deprecation-contracts",
+ "type": "library",
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1"
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.5-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ }
+}
diff --git a/vendor/symfony/deprecation-contracts/function.php b/vendor/symfony/deprecation-contracts/function.php
new file mode 100644
index 0000000..d437150
--- /dev/null
+++ b/vendor/symfony/deprecation-contracts/function.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (!function_exists('trigger_deprecation')) {
+ /**
+ * Triggers a silenced deprecation notice.
+ *
+ * @param string $package The name of the Composer package that is triggering the deprecation
+ * @param string $version The version of the package that introduced the deprecation
+ * @param string $message The message of the deprecation
+ * @param mixed ...$args Values to insert in the message using printf() formatting
+ *
+ * @author Nicolas Grekas
+ */
+ function trigger_deprecation(string $package, string $version, string $message, ...$args): void
+ {
+ @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED);
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-idn/Idn.php b/vendor/symfony/polyfill-intl-idn/Idn.php
index 86710b9..334f8ee 100644
--- a/vendor/symfony/polyfill-intl-idn/Idn.php
+++ b/vendor/symfony/polyfill-intl-idn/Idn.php
@@ -11,8 +11,6 @@
namespace Symfony\Polyfill\Intl\Idn;
-use Exception;
-use Normalizer;
use Symfony\Polyfill\Intl\Idn\Resources\unidata\DisallowedRanges;
use Symfony\Polyfill\Intl\Idn\Resources\unidata\Regex;
@@ -147,7 +145,7 @@ final class Idn
*/
public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
{
- if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
+ if (self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
}
@@ -167,7 +165,7 @@ final class Idn
if (1 === preg_match('/[^\x00-\x7F]/', $label)) {
try {
$label = 'xn--'.self::punycodeEncode($label);
- } catch (Exception $e) {
+ } catch (\Exception $e) {
$info->errors |= self::ERROR_PUNYCODE;
}
@@ -200,7 +198,7 @@ final class Idn
*/
public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
{
- if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
+ if (self::INTL_IDNA_VARIANT_2003 === $variant) {
@trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
}
@@ -282,10 +280,6 @@ final class Idn
switch ($data['status']) {
case 'disallowed':
- $info->errors |= self::ERROR_DISALLOWED;
-
- // no break.
-
case 'valid':
$str .= mb_chr($codePoint, 'utf-8');
@@ -296,7 +290,7 @@ final class Idn
break;
case 'mapped':
- $str .= $data['mapping'];
+ $str .= $transitional && 0x1E9E === $codePoint ? 'ss' : $data['mapping'];
break;
@@ -335,8 +329,8 @@ final class Idn
$domain = self::mapCodePoints($domain, $options, $info);
// Step 2. Normalize the domain name string to Unicode Normalization Form C.
- if (!Normalizer::isNormalized($domain, Normalizer::FORM_C)) {
- $domain = Normalizer::normalize($domain, Normalizer::FORM_C);
+ if (!\Normalizer::isNormalized($domain, \Normalizer::FORM_C)) {
+ $domain = \Normalizer::normalize($domain, \Normalizer::FORM_C);
}
// Step 3. Break the string into labels at U+002E (.) FULL STOP.
@@ -348,9 +342,21 @@ final class Idn
$validationOptions = $options;
if ('xn--' === substr($label, 0, 4)) {
+ // Step 4.1. If the label contains any non-ASCII code point (i.e., a code point greater than U+007F),
+ // record that there was an error, and continue with the next label.
+ if (preg_match('/[^\x00-\x7F]/', $label)) {
+ $info->errors |= self::ERROR_PUNYCODE;
+
+ continue;
+ }
+
+ // Step 4.2. Attempt to convert the rest of the label to Unicode according to Punycode [RFC3492]. If
+ // that conversion fails, record that there was an error, and continue
+ // with the next label. Otherwise replace the original label in the string by the results of the
+ // conversion.
try {
$label = self::punycodeDecode(substr($label, 4));
- } catch (Exception $e) {
+ } catch (\Exception $e) {
$info->errors |= self::ERROR_PUNYCODE;
continue;
@@ -496,7 +502,7 @@ final class Idn
}
// Step 1. The label must be in Unicode Normalization Form C.
- if (!Normalizer::isNormalized($label, Normalizer::FORM_C)) {
+ if (!\Normalizer::isNormalized($label, \Normalizer::FORM_C)) {
$info->errors |= self::ERROR_INVALID_ACE_LABEL;
}
@@ -518,6 +524,8 @@ final class Idn
if ('-' === substr($label, -1, 1)) {
$info->errors |= self::ERROR_TRAILING_HYPHEN;
}
+ } elseif ('xn--' === substr($label, 0, 4)) {
+ $info->errors |= self::ERROR_PUNYCODE;
}
// Step 4. The label must not contain a U+002E (.) FULL STOP.
@@ -583,7 +591,7 @@ final class Idn
for ($j = 0; $j < $b; ++$j) {
if ($bytes[$j] > 0x7F) {
- throw new Exception('Invalid input');
+ throw new \Exception('Invalid input');
}
$output[$out++] = $input[$j];
@@ -599,17 +607,17 @@ final class Idn
for ($k = self::BASE; /* no condition */; $k += self::BASE) {
if ($in >= $inputLength) {
- throw new Exception('Invalid input');
+ throw new \Exception('Invalid input');
}
$digit = self::$basicToDigit[$bytes[$in++] & 0xFF];
if ($digit < 0) {
- throw new Exception('Invalid input');
+ throw new \Exception('Invalid input');
}
if ($digit > intdiv(self::MAX_INT - $i, $w)) {
- throw new Exception('Integer overflow');
+ throw new \Exception('Integer overflow');
}
$i += $digit * $w;
@@ -629,7 +637,7 @@ final class Idn
$baseMinusT = self::BASE - $t;
if ($w > intdiv(self::MAX_INT, $baseMinusT)) {
- throw new Exception('Integer overflow');
+ throw new \Exception('Integer overflow');
}
$w *= $baseMinusT;
@@ -639,7 +647,7 @@ final class Idn
$bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi);
if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) {
- throw new Exception('Integer overflow');
+ throw new \Exception('Integer overflow');
}
$n += intdiv($i, $outPlusOne);
@@ -694,7 +702,7 @@ final class Idn
}
if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) {
- throw new Exception('Integer overflow');
+ throw new \Exception('Integer overflow');
}
$delta += ($m - $n) * ($h + 1);
@@ -702,7 +710,7 @@ final class Idn
foreach ($iter as $codePoint) {
if ($codePoint < $n && 0 === ++$delta) {
- throw new Exception('Integer overflow');
+ throw new \Exception('Integer overflow');
}
if ($codePoint === $n) {
diff --git a/vendor/symfony/polyfill-intl-idn/LICENSE b/vendor/symfony/polyfill-intl-idn/LICENSE
index 03c5e25..fd0a062 100644
--- a/vendor/symfony/polyfill-intl-idn/LICENSE
+++ b/vendor/symfony/polyfill-intl-idn/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2018-2019 Fabien Potencier and Trevor Rowbotham
- * @author Dariusz Rumiński
+ */
+trait ServiceLocatorTrait
+{
+ private $factories;
+ private $loading = [];
+ private $providedTypes;
+
+ /**
+ * @param callable[] $factories
+ */
+ public function __construct(array $factories)
+ {
+ $this->factories = $factories;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return bool
+ */
+ public function has(string $id)
+ {
+ return isset($this->factories[$id]);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return mixed
+ */
+ public function get(string $id)
+ {
+ if (!isset($this->factories[$id])) {
+ throw $this->createNotFoundException($id);
+ }
+
+ if (isset($this->loading[$id])) {
+ $ids = array_values($this->loading);
+ $ids = \array_slice($this->loading, array_search($id, $ids));
+ $ids[] = $id;
+
+ throw $this->createCircularReferenceException($id, $ids);
+ }
+
+ $this->loading[$id] = $id;
+ try {
+ return $this->factories[$id]($this);
+ } finally {
+ unset($this->loading[$id]);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getProvidedServices(): array
+ {
+ if (null === $this->providedTypes) {
+ $this->providedTypes = [];
+
+ foreach ($this->factories as $name => $factory) {
+ if (!\is_callable($factory)) {
+ $this->providedTypes[$name] = '?';
+ } else {
+ $type = (new \ReflectionFunction($factory))->getReturnType();
+
+ $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?';
+ }
+ }
+ }
+
+ return $this->providedTypes;
+ }
+
+ private function createNotFoundException(string $id): NotFoundExceptionInterface
+ {
+ if (!$alternatives = array_keys($this->factories)) {
+ $message = 'is empty...';
+ } else {
+ $last = array_pop($alternatives);
+ if ($alternatives) {
+ $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last);
+ } else {
+ $message = sprintf('only knows about the "%s" service.', $last);
+ }
+ }
+
+ if ($this->loading) {
+ $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message);
+ } else {
+ $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message);
+ }
+
+ return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface {
+ };
+ }
+
+ private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface
+ {
+ return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface {
+ };
+ }
+}
diff --git a/vendor/symfony/service-contracts/ServiceProviderInterface.php b/vendor/symfony/service-contracts/ServiceProviderInterface.php
new file mode 100644
index 0000000..c60ad0b
--- /dev/null
+++ b/vendor/symfony/service-contracts/ServiceProviderInterface.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service;
+
+use Psr\Container\ContainerInterface;
+
+/**
+ * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container.
+ *
+ * @author Nicolas Grekas
+ * @author Mateusz Sip
+ */
+interface ServiceSubscriberInterface
+{
+ /**
+ * Returns an array of service types required by such instances, optionally keyed by the service names used internally.
+ *
+ * For mandatory dependencies:
+ *
+ * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name
+ * internally to fetch a service which must implement Psr\Log\LoggerInterface.
+ * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name
+ * internally to fetch an iterable of Psr\Log\LoggerInterface instances.
+ * * ['Psr\Log\LoggerInterface'] is a shortcut for
+ * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface']
+ *
+ * otherwise:
+ *
+ * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency
+ * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency
+ * * ['?Psr\Log\LoggerInterface'] is a shortcut for
+ * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface']
+ *
+ * @return string[] The required service types, optionally keyed by service names
+ */
+ public static function getSubscribedServices();
+}
diff --git a/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php
new file mode 100644
index 0000000..6c560a4
--- /dev/null
+++ b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php
@@ -0,0 +1,110 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\Service;
+
+use Psr\Container\ContainerInterface;
+use Symfony\Contracts\Service\Attribute\SubscribedService;
+
+/**
+ * Implementation of ServiceSubscriberInterface that determines subscribed services from
+ * method return types. Service ids are available as "ClassName::methodName".
+ *
+ * @author Kevin Bond
+ */
+final class Instantiator
+{
+ /**
+ * Creates an object and sets its properties without calling its constructor nor any other methods.
+ *
+ * For example:
+ *
+ * // creates an empty instance of Foo
+ * Instantiator::instantiate(Foo::class);
+ *
+ * // creates a Foo instance and sets one of its properties
+ * Instantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]);
+ *
+ * // creates a Foo instance and sets a private property defined on its parent Bar class
+ * Instantiator::instantiate(Foo::class, [], [
+ * Bar::class => ['privateBarProperty' => $propertyValue],
+ * ]);
+ *
+ * Instances of ArrayObject, ArrayIterator and SplObjectStorage can be created
+ * by using the special "\0" property name to define their internal value:
+ *
+ * // creates an SplObjectStorage where $info1 is attached to $obj1, etc.
+ * Instantiator::instantiate(SplObjectStorage::class, ["\0" => [$obj1, $info1, $obj2, $info2...]]);
+ *
+ * // creates an ArrayObject populated with $inputArray
+ * Instantiator::instantiate(ArrayObject::class, ["\0" => [$inputArray]]);
+ *
+ * @param string $class The class of the instance to create
+ * @param array $properties The properties to set on the instance
+ * @param array $privateProperties The private properties to set on the instance,
+ * keyed by their declaring class
+ *
+ * @throws ExceptionInterface When the instance cannot be created
+ */
+ public static function instantiate(string $class, array $properties = [], array $privateProperties = []): object
+ {
+ $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
+
+ if (Registry::$cloneable[$class]) {
+ $wrappedInstance = [clone Registry::$prototypes[$class]];
+ } elseif (Registry::$instantiableWithoutConstructor[$class]) {
+ $wrappedInstance = [$reflector->newInstanceWithoutConstructor()];
+ } elseif (null === Registry::$prototypes[$class]) {
+ throw new NotInstantiableTypeException($class);
+ } elseif ($reflector->implementsInterface('Serializable') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize'))) {
+ $wrappedInstance = [unserialize('C:'.\strlen($class).':"'.$class.'":0:{}')];
+ } else {
+ $wrappedInstance = [unserialize('O:'.\strlen($class).':"'.$class.'":0:{}')];
+ }
+
+ if ($properties) {
+ $privateProperties[$class] = isset($privateProperties[$class]) ? $properties + $privateProperties[$class] : $properties;
+ }
+
+ foreach ($privateProperties as $class => $properties) {
+ if (!$properties) {
+ continue;
+ }
+ foreach ($properties as $name => $value) {
+ // because they're also used for "unserialization", hydrators
+ // deal with array of instances, so we need to wrap values
+ $properties[$name] = [$value];
+ }
+ (Hydrator::$hydrators[$class] ?? Hydrator::getHydrator($class))($properties, $wrappedInstance);
+ }
+
+ return $wrappedInstance[0];
+ }
+}
diff --git a/vendor/symfony/var-exporter/Internal/Exporter.php b/vendor/symfony/var-exporter/Internal/Exporter.php
new file mode 100644
index 0000000..51c29e4
--- /dev/null
+++ b/vendor/symfony/var-exporter/Internal/Exporter.php
@@ -0,0 +1,417 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
+
+/**
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+class Exporter
+{
+ /**
+ * Prepares an array of values for VarExporter.
+ *
+ * For performance this method is public and has no type-hints.
+ *
+ * @param array &$values
+ * @param \SplObjectStorage $objectsPool
+ * @param array &$refsPool
+ * @param int &$objectsCount
+ * @param bool &$valuesAreStatic
+ *
+ * @throws NotInstantiableTypeException When a value cannot be serialized
+ */
+ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic): array
+ {
+ $refs = $values;
+ foreach ($values as $k => $value) {
+ if (\is_resource($value)) {
+ throw new NotInstantiableTypeException(get_resource_type($value).' resource');
+ }
+ $refs[$k] = $objectsPool;
+
+ if ($isRef = !$valueIsStatic = $values[$k] !== $objectsPool) {
+ $values[$k] = &$value; // Break hard references to make $values completely
+ unset($value); // independent from the original structure
+ $refs[$k] = $value = $values[$k];
+ if ($value instanceof Reference && 0 > $value->id) {
+ $valuesAreStatic = false;
+ ++$value->count;
+ continue;
+ }
+ $refsPool[] = [&$refs[$k], $value, &$value];
+ $refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value);
+ }
+
+ if (\is_array($value)) {
+ if ($value) {
+ $value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
+ }
+ goto handle_value;
+ } elseif (!\is_object($value) || $value instanceof \UnitEnum) {
+ goto handle_value;
+ }
+
+ $valueIsStatic = false;
+ if (isset($objectsPool[$value])) {
+ ++$objectsCount;
+ $value = new Reference($objectsPool[$value][0]);
+ goto handle_value;
+ }
+
+ $class = \get_class($value);
+ $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
+ $properties = [];
+
+ if ($reflector->hasMethod('__serialize')) {
+ if (!$reflector->getMethod('__serialize')->isPublic()) {
+ throw new \Error(sprintf('Call to %s method "%s::__serialize()".', $reflector->getMethod('__serialize')->isProtected() ? 'protected' : 'private', $class));
+ }
+
+ if (!\is_array($serializeProperties = $value->__serialize())) {
+ throw new \TypeError($class.'::__serialize() must return an array');
+ }
+
+ if ($reflector->hasMethod('__unserialize')) {
+ $properties = $serializeProperties;
+ } else {
+ foreach ($serializeProperties as $n => $v) {
+ $c = \PHP_VERSION_ID >= 80100 && $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass';
+ $properties[$c][$n] = $v;
+ }
+ }
+
+ goto prepare_value;
+ }
+
+ $sleep = null;
+ $proto = Registry::$prototypes[$class];
+
+ if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) {
+ // ArrayIterator and ArrayObject need special care because their "flags"
+ // option changes the behavior of the (array) casting operator.
+ [$arrayValue, $properties] = self::getArrayObjectProperties($value, $proto);
+
+ // populates Registry::$prototypes[$class] with a new instance
+ Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]);
+ } elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) {
+ // By implementing Serializable, SplObjectStorage breaks
+ // internal references; let's deal with it on our own.
+ foreach (clone $value as $v) {
+ $properties[] = $v;
+ $properties[] = $value[$v];
+ }
+ $properties = ['SplObjectStorage' => ["\0" => $properties]];
+ $arrayValue = (array) $value;
+ } elseif ($value instanceof \Serializable
+ || $value instanceof \__PHP_Incomplete_Class
+ || \PHP_VERSION_ID < 80200 && $value instanceof \DatePeriod
+ ) {
+ ++$objectsCount;
+ $objectsPool[$value] = [$id = \count($objectsPool), serialize($value), [], 0];
+ $value = new Reference($id);
+ goto handle_value;
+ } else {
+ if (method_exists($class, '__sleep')) {
+ if (!\is_array($sleep = $value->__sleep())) {
+ trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE);
+ $value = null;
+ goto handle_value;
+ }
+ $sleep = array_flip($sleep);
+ }
+
+ $arrayValue = (array) $value;
+ }
+
+ $proto = (array) $proto;
+
+ foreach ($arrayValue as $name => $v) {
+ $i = 0;
+ $n = (string) $name;
+ if ('' === $n || "\0" !== $n[0]) {
+ $c = \PHP_VERSION_ID >= 80100 && $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass';
+ } elseif ('*' === $n[1]) {
+ $n = substr($n, 3);
+ $c = $reflector->getProperty($n)->class;
+ if ('Error' === $c) {
+ $c = 'TypeError';
+ } elseif ('Exception' === $c) {
+ $c = 'ErrorException';
+ }
+ } else {
+ $i = strpos($n, "\0", 2);
+ $c = substr($n, 1, $i - 1);
+ $n = substr($n, 1 + $i);
+ }
+ if (null !== $sleep) {
+ if (!isset($sleep[$name]) && (!isset($sleep[$n]) || ($i && $c !== $class))) {
+ unset($arrayValue[$name]);
+ continue;
+ }
+ unset($sleep[$name], $sleep[$n]);
+ }
+ if (!\array_key_exists($name, $proto) || $proto[$name] !== $v || "\x00Error\x00trace" === $name || "\x00Exception\x00trace" === $name) {
+ $properties[$c][$n] = $v;
+ }
+ }
+ if ($sleep) {
+ foreach ($sleep as $n => $v) {
+ trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), \E_USER_NOTICE);
+ }
+ }
+ if (method_exists($class, '__unserialize')) {
+ $properties = $arrayValue;
+ }
+
+ prepare_value:
+ $objectsPool[$value] = [$id = \count($objectsPool)];
+ $properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
+ ++$objectsCount;
+ $objectsPool[$value] = [$id, $class, $properties, method_exists($class, '__unserialize') ? -$objectsCount : (method_exists($class, '__wakeup') ? $objectsCount : 0)];
+
+ $value = new Reference($id);
+
+ handle_value:
+ if ($isRef) {
+ unset($value); // Break the hard reference created above
+ } elseif (!$valueIsStatic) {
+ $values[$k] = $value;
+ }
+ $valuesAreStatic = $valueIsStatic && $valuesAreStatic;
+ }
+
+ return $values;
+ }
+
+ public static function export($value, string $indent = '')
+ {
+ switch (true) {
+ case \is_int($value) || \is_float($value): return var_export($value, true);
+ case [] === $value: return '[]';
+ case false === $value: return 'false';
+ case true === $value: return 'true';
+ case null === $value: return 'null';
+ case '' === $value: return "''";
+ case $value instanceof \UnitEnum: return '\\'.ltrim(var_export($value, true), '\\');
+ }
+
+ if ($value instanceof Reference) {
+ if (0 <= $value->id) {
+ return '$o['.$value->id.']';
+ }
+ if (!$value->count) {
+ return self::export($value->value, $indent);
+ }
+ $value = -$value->id;
+
+ return '&$r['.$value.']';
+ }
+ $subIndent = $indent.' ';
+
+ if (\is_string($value)) {
+ $code = sprintf("'%s'", addcslashes($value, "'\\"));
+
+ $code = preg_replace_callback("/((?:[\\0\\r\\n]|\u{202A}|\u{202B}|\u{202D}|\u{202E}|\u{2066}|\u{2067}|\u{2068}|\u{202C}|\u{2069})++)(.)/", function ($m) use ($subIndent) {
+ $m[1] = sprintf('\'."%s".\'', str_replace(
+ ["\0", "\r", "\n", "\u{202A}", "\u{202B}", "\u{202D}", "\u{202E}", "\u{2066}", "\u{2067}", "\u{2068}", "\u{202C}", "\u{2069}", '\n\\'],
+ ['\0', '\r', '\n', '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', '\u{2069}', '\n"'."\n".$subIndent.'."\\'],
+ $m[1]
+ ));
+
+ if ("'" === $m[2]) {
+ return substr($m[1], 0, -2);
+ }
+
+ if ('n".\'' === substr($m[1], -4)) {
+ return substr_replace($m[1], "\n".$subIndent.".'".$m[2], -2);
+ }
+
+ return $m[1].$m[2];
+ }, $code, -1, $count);
+
+ if ($count && str_starts_with($code, "''.")) {
+ $code = substr($code, 3);
+ }
+
+ return $code;
+ }
+
+ if (\is_array($value)) {
+ $j = -1;
+ $code = '';
+ foreach ($value as $k => $v) {
+ $code .= $subIndent;
+ if (!\is_int($k) || 1 !== $k - $j) {
+ $code .= self::export($k, $subIndent).' => ';
+ }
+ if (\is_int($k) && $k > $j) {
+ $j = $k;
+ }
+ $code .= self::export($v, $subIndent).",\n";
+ }
+
+ return "[\n".$code.$indent.']';
+ }
+
+ if ($value instanceof Values) {
+ $code = $subIndent."\$r = [],\n";
+ foreach ($value->values as $k => $v) {
+ $code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n";
+ }
+
+ return "[\n".$code.$indent.']';
+ }
+
+ if ($value instanceof Registry) {
+ return self::exportRegistry($value, $indent, $subIndent);
+ }
+
+ if ($value instanceof Hydrator) {
+ return self::exportHydrator($value, $indent, $subIndent);
+ }
+
+ throw new \UnexpectedValueException(sprintf('Cannot export value of type "%s".', get_debug_type($value)));
+ }
+
+ private static function exportRegistry(Registry $value, string $indent, string $subIndent): string
+ {
+ $code = '';
+ $serializables = [];
+ $seen = [];
+ $prototypesAccess = 0;
+ $factoriesAccess = 0;
+ $r = '\\'.Registry::class;
+ $j = -1;
+
+ foreach ($value->classes as $k => $class) {
+ if (':' === ($class[1] ?? null)) {
+ $serializables[$k] = $class;
+ continue;
+ }
+ if (!Registry::$instantiableWithoutConstructor[$class]) {
+ if (is_subclass_of($class, 'Serializable') && !method_exists($class, '__unserialize')) {
+ $serializables[$k] = 'C:'.\strlen($class).':"'.$class.'":0:{}';
+ } else {
+ $serializables[$k] = 'O:'.\strlen($class).':"'.$class.'":0:{}';
+ }
+ if (is_subclass_of($class, 'Throwable')) {
+ $eol = is_subclass_of($class, 'Error') ? "\0Error\0" : "\0Exception\0";
+ $serializables[$k] = substr_replace($serializables[$k], '1:{s:'.(5 + \strlen($eol)).':"'.$eol.'trace";a:0:{}}', -4);
+ }
+ continue;
+ }
+ $code .= $subIndent.(1 !== $k - $j ? $k.' => ' : '');
+ $j = $k;
+ $eol = ",\n";
+ $c = '['.self::export($class).']';
+
+ if ($seen[$class] ?? false) {
+ if (Registry::$cloneable[$class]) {
+ ++$prototypesAccess;
+ $code .= 'clone $p'.$c;
+ } else {
+ ++$factoriesAccess;
+ $code .= '$f'.$c.'()';
+ }
+ } else {
+ $seen[$class] = true;
+ if (Registry::$cloneable[$class]) {
+ $code .= 'clone ('.($prototypesAccess++ ? '$p' : '($p = &'.$r.'::$prototypes)').$c.' ?? '.$r.'::p';
+ } else {
+ $code .= '('.($factoriesAccess++ ? '$f' : '($f = &'.$r.'::$factories)').$c.' ?? '.$r.'::f';
+ $eol = '()'.$eol;
+ }
+ $code .= '('.substr($c, 1, -1).'))';
+ }
+ $code .= $eol;
+ }
+
+ if (1 === $prototypesAccess) {
+ $code = str_replace('($p = &'.$r.'::$prototypes)', $r.'::$prototypes', $code);
+ }
+ if (1 === $factoriesAccess) {
+ $code = str_replace('($f = &'.$r.'::$factories)', $r.'::$factories', $code);
+ }
+ if ('' !== $code) {
+ $code = "\n".$code.$indent;
+ }
+
+ if ($serializables) {
+ $code = $r.'::unserialize(['.$code.'], '.self::export($serializables, $indent).')';
+ } else {
+ $code = '['.$code.']';
+ }
+
+ return '$o = '.$code;
+ }
+
+ private static function exportHydrator(Hydrator $value, string $indent, string $subIndent): string
+ {
+ $code = '';
+ foreach ($value->properties as $class => $properties) {
+ $code .= $subIndent.' '.self::export($class).' => '.self::export($properties, $subIndent.' ').",\n";
+ }
+
+ $code = [
+ self::export($value->registry, $subIndent),
+ self::export($value->values, $subIndent),
+ '' !== $code ? "[\n".$code.$subIndent.']' : '[]',
+ self::export($value->value, $subIndent),
+ self::export($value->wakeups, $subIndent),
+ ];
+
+ return '\\'.\get_class($value)."::hydrate(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')';
+ }
+
+ /**
+ * @param \ArrayIterator|\ArrayObject $value
+ * @param \ArrayIterator|\ArrayObject $proto
+ */
+ private static function getArrayObjectProperties($value, $proto): array
+ {
+ $reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject';
+ $reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector);
+
+ $properties = [
+ $arrayValue = (array) $value,
+ $reflector->getMethod('getFlags')->invoke($value),
+ $value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator',
+ ];
+
+ $reflector = $reflector->getMethod('setFlags');
+ $reflector->invoke($proto, \ArrayObject::STD_PROP_LIST);
+
+ if ($properties[1] & \ArrayObject::STD_PROP_LIST) {
+ $reflector->invoke($value, 0);
+ $properties[0] = (array) $value;
+ } else {
+ $reflector->invoke($value, \ArrayObject::STD_PROP_LIST);
+ $arrayValue = (array) $value;
+ }
+ $reflector->invoke($value, $properties[1]);
+
+ if ([[], 0, 'ArrayIterator'] === $properties) {
+ $properties = [];
+ } else {
+ if ('ArrayIterator' === $properties[2]) {
+ unset($properties[2]);
+ }
+ $properties = [$reflector->class => ["\0" => $properties]];
+ }
+
+ return [$arrayValue, $properties];
+ }
+}
diff --git a/vendor/symfony/var-exporter/Internal/Hydrator.php b/vendor/symfony/var-exporter/Internal/Hydrator.php
new file mode 100644
index 0000000..5ed6bdc
--- /dev/null
+++ b/vendor/symfony/var-exporter/Internal/Hydrator.php
@@ -0,0 +1,152 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+use Symfony\Component\VarExporter\Exception\ClassNotFoundException;
+
+/**
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+class Hydrator
+{
+ public static $hydrators = [];
+
+ public $registry;
+ public $values;
+ public $properties;
+ public $value;
+ public $wakeups;
+
+ public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups)
+ {
+ $this->registry = $registry;
+ $this->values = $values;
+ $this->properties = $properties;
+ $this->value = $value;
+ $this->wakeups = $wakeups;
+ }
+
+ public static function hydrate($objects, $values, $properties, $value, $wakeups)
+ {
+ foreach ($properties as $class => $vars) {
+ (self::$hydrators[$class] ?? self::getHydrator($class))($vars, $objects);
+ }
+ foreach ($wakeups as $k => $v) {
+ if (\is_array($v)) {
+ $objects[-$k]->__unserialize($v);
+ } else {
+ $objects[$v]->__wakeup();
+ }
+ }
+
+ return $value;
+ }
+
+ public static function getHydrator($class)
+ {
+ switch ($class) {
+ case 'stdClass':
+ return self::$hydrators[$class] = static function ($properties, $objects) {
+ foreach ($properties as $name => $values) {
+ foreach ($values as $i => $v) {
+ $objects[$i]->$name = $v;
+ }
+ }
+ };
+
+ case 'ErrorException':
+ return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \ErrorException {
+ });
+
+ case 'TypeError':
+ return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \Error {
+ });
+
+ case 'SplObjectStorage':
+ return self::$hydrators[$class] = static function ($properties, $objects) {
+ foreach ($properties as $name => $values) {
+ if ("\0" === $name) {
+ foreach ($values as $i => $v) {
+ for ($j = 0; $j < \count($v); ++$j) {
+ $objects[$i]->attach($v[$j], $v[++$j]);
+ }
+ }
+ continue;
+ }
+ foreach ($values as $i => $v) {
+ $objects[$i]->$name = $v;
+ }
+ }
+ };
+ }
+
+ if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) {
+ throw new ClassNotFoundException($class);
+ }
+ $classReflector = new \ReflectionClass($class);
+
+ switch ($class) {
+ case 'ArrayIterator':
+ case 'ArrayObject':
+ $constructor = \Closure::fromCallable([$classReflector->getConstructor(), 'invokeArgs']);
+
+ return self::$hydrators[$class] = static function ($properties, $objects) use ($constructor) {
+ foreach ($properties as $name => $values) {
+ if ("\0" !== $name) {
+ foreach ($values as $i => $v) {
+ $objects[$i]->$name = $v;
+ }
+ }
+ }
+ foreach ($properties["\0"] ?? [] as $i => $v) {
+ $constructor($objects[$i], $v);
+ }
+ };
+ }
+
+ if (!$classReflector->isInternal()) {
+ return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, $class);
+ }
+
+ if ($classReflector->name !== $class) {
+ return self::$hydrators[$classReflector->name] ?? self::getHydrator($classReflector->name);
+ }
+
+ $propertySetters = [];
+ foreach ($classReflector->getProperties() as $propertyReflector) {
+ if (!$propertyReflector->isStatic()) {
+ $propertyReflector->setAccessible(true);
+ $propertySetters[$propertyReflector->name] = \Closure::fromCallable([$propertyReflector, 'setValue']);
+ }
+ }
+
+ if (!$propertySetters) {
+ return self::$hydrators[$class] = self::$hydrators['stdClass'] ?? self::getHydrator('stdClass');
+ }
+
+ return self::$hydrators[$class] = static function ($properties, $objects) use ($propertySetters) {
+ foreach ($properties as $name => $values) {
+ if ($setValue = $propertySetters[$name] ?? null) {
+ foreach ($values as $i => $v) {
+ $setValue($objects[$i], $v);
+ }
+ continue;
+ }
+ foreach ($values as $i => $v) {
+ $objects[$i]->$name = $v;
+ }
+ }
+ };
+ }
+}
diff --git a/vendor/symfony/var-exporter/Internal/Reference.php b/vendor/symfony/var-exporter/Internal/Reference.php
new file mode 100644
index 0000000..e371c07
--- /dev/null
+++ b/vendor/symfony/var-exporter/Internal/Reference.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+/**
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+class Reference
+{
+ public $id;
+ public $value;
+ public $count = 0;
+
+ public function __construct(int $id, $value = null)
+ {
+ $this->id = $id;
+ $this->value = $value;
+ }
+}
diff --git a/vendor/symfony/var-exporter/Internal/Registry.php b/vendor/symfony/var-exporter/Internal/Registry.php
new file mode 100644
index 0000000..24b77b9
--- /dev/null
+++ b/vendor/symfony/var-exporter/Internal/Registry.php
@@ -0,0 +1,146 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+use Symfony\Component\VarExporter\Exception\ClassNotFoundException;
+use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
+
+/**
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+class Registry
+{
+ public static $reflectors = [];
+ public static $prototypes = [];
+ public static $factories = [];
+ public static $cloneable = [];
+ public static $instantiableWithoutConstructor = [];
+
+ public $classes = [];
+
+ public function __construct(array $classes)
+ {
+ $this->classes = $classes;
+ }
+
+ public static function unserialize($objects, $serializables)
+ {
+ $unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector');
+
+ try {
+ foreach ($serializables as $k => $v) {
+ $objects[$k] = unserialize($v);
+ }
+ } finally {
+ ini_set('unserialize_callback_func', $unserializeCallback);
+ }
+
+ return $objects;
+ }
+
+ public static function p($class)
+ {
+ self::getClassReflector($class, true, true);
+
+ return self::$prototypes[$class];
+ }
+
+ public static function f($class)
+ {
+ $reflector = self::$reflectors[$class] ?? self::getClassReflector($class, true, false);
+
+ return self::$factories[$class] = \Closure::fromCallable([$reflector, 'newInstanceWithoutConstructor']);
+ }
+
+ public static function getClassReflector($class, $instantiableWithoutConstructor = false, $cloneable = null)
+ {
+ if (!($isClass = class_exists($class)) && !interface_exists($class, false) && !trait_exists($class, false)) {
+ throw new ClassNotFoundException($class);
+ }
+ $reflector = new \ReflectionClass($class);
+
+ if ($instantiableWithoutConstructor) {
+ $proto = $reflector->newInstanceWithoutConstructor();
+ } elseif (!$isClass || $reflector->isAbstract()) {
+ throw new NotInstantiableTypeException($class);
+ } elseif ($reflector->name !== $class) {
+ $reflector = self::$reflectors[$name = $reflector->name] ?? self::getClassReflector($name, false, $cloneable);
+ self::$cloneable[$class] = self::$cloneable[$name];
+ self::$instantiableWithoutConstructor[$class] = self::$instantiableWithoutConstructor[$name];
+ self::$prototypes[$class] = self::$prototypes[$name];
+
+ return self::$reflectors[$class] = $reflector;
+ } else {
+ try {
+ $proto = $reflector->newInstanceWithoutConstructor();
+ $instantiableWithoutConstructor = true;
+ } catch (\ReflectionException $e) {
+ $proto = $reflector->implementsInterface('Serializable') && !method_exists($class, '__unserialize') ? 'C:' : 'O:';
+ if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) {
+ $proto = null;
+ } else {
+ try {
+ $proto = @unserialize($proto.\strlen($class).':"'.$class.'":0:{}');
+ } catch (\Exception $e) {
+ if (__FILE__ !== $e->getFile()) {
+ throw $e;
+ }
+ throw new NotInstantiableTypeException($class, $e);
+ }
+ if (false === $proto) {
+ throw new NotInstantiableTypeException($class);
+ }
+ }
+ }
+ if (null !== $proto && !$proto instanceof \Throwable && !$proto instanceof \Serializable && !method_exists($class, '__sleep') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__serialize'))) {
+ try {
+ serialize($proto);
+ } catch (\Exception $e) {
+ throw new NotInstantiableTypeException($class, $e);
+ }
+ }
+ }
+
+ if (null === $cloneable) {
+ if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !method_exists($proto, '__wakeup') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize')))) {
+ throw new NotInstantiableTypeException($class);
+ }
+
+ $cloneable = $reflector->isCloneable() && !$reflector->hasMethod('__clone');
+ }
+
+ self::$cloneable[$class] = $cloneable;
+ self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor;
+ self::$prototypes[$class] = $proto;
+
+ if ($proto instanceof \Throwable) {
+ static $setTrace;
+
+ if (null === $setTrace) {
+ $setTrace = [
+ new \ReflectionProperty(\Error::class, 'trace'),
+ new \ReflectionProperty(\Exception::class, 'trace'),
+ ];
+ $setTrace[0]->setAccessible(true);
+ $setTrace[1]->setAccessible(true);
+ $setTrace[0] = \Closure::fromCallable([$setTrace[0], 'setValue']);
+ $setTrace[1] = \Closure::fromCallable([$setTrace[1], 'setValue']);
+ }
+
+ $setTrace[$proto instanceof \Exception]($proto, []);
+ }
+
+ return self::$reflectors[$class] = $reflector;
+ }
+}
diff --git a/vendor/symfony/var-exporter/Internal/Values.php b/vendor/symfony/var-exporter/Internal/Values.php
new file mode 100644
index 0000000..21ae04e
--- /dev/null
+++ b/vendor/symfony/var-exporter/Internal/Values.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter\Internal;
+
+/**
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+class Values
+{
+ public $values;
+
+ public function __construct(array $values)
+ {
+ $this->values = $values;
+ }
+}
diff --git a/vendor/symfony/var-exporter/LICENSE b/vendor/symfony/var-exporter/LICENSE
new file mode 100644
index 0000000..7536cae
--- /dev/null
+++ b/vendor/symfony/var-exporter/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/symfony/var-exporter/README.md b/vendor/symfony/var-exporter/README.md
new file mode 100644
index 0000000..a34e4c2
--- /dev/null
+++ b/vendor/symfony/var-exporter/README.md
@@ -0,0 +1,38 @@
+VarExporter Component
+=====================
+
+The VarExporter component allows exporting any serializable PHP data structure to
+plain PHP code. While doing so, it preserves all the semantics associated with
+the serialization mechanism of PHP (`__wakeup`, `__sleep`, `Serializable`,
+`__serialize`, `__unserialize`).
+
+It also provides an instantiator that allows creating and populating objects
+without calling their constructor nor any other methods.
+
+The reason to use this component *vs* `serialize()` or
+[igbinary](https://github.com/igbinary/igbinary) is performance: thanks to
+OPcache, the resulting code is significantly faster and more memory efficient
+than using `unserialize()` or `igbinary_unserialize()`.
+
+Unlike `var_export()`, this works on any serializable PHP value.
+
+It also provides a few improvements over `var_export()`/`serialize()`:
+
+ * the output is PSR-2 compatible;
+ * the output can be re-indented without messing up with `\r` or `\n` in the data
+ * missing classes throw a `ClassNotFoundException` instead of being unserialized to
+ `PHP_Incomplete_Class` objects;
+ * references involving `SplObjectStorage`, `ArrayObject` or `ArrayIterator`
+ instances are preserved;
+ * `Reflection*`, `IteratorIterator` and `RecursiveIteratorIterator` classes
+ throw an exception when being serialized (their unserialized version is broken
+ anyway, see https://bugs.php.net/76737).
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/var_exporter.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/vendor/symfony/var-exporter/VarExporter.php b/vendor/symfony/var-exporter/VarExporter.php
new file mode 100644
index 0000000..d4c0809
--- /dev/null
+++ b/vendor/symfony/var-exporter/VarExporter.php
@@ -0,0 +1,115 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarExporter;
+
+use Symfony\Component\VarExporter\Exception\ExceptionInterface;
+use Symfony\Component\VarExporter\Internal\Exporter;
+use Symfony\Component\VarExporter\Internal\Hydrator;
+use Symfony\Component\VarExporter\Internal\Registry;
+use Symfony\Component\VarExporter\Internal\Values;
+
+/**
+ * Exports serializable PHP values to PHP code.
+ *
+ * VarExporter allows serializing PHP data structures to plain PHP code (like var_export())
+ * while preserving all the semantics associated with serialize() (unlike var_export()).
+ *
+ * By leveraging OPcache, the generated PHP code is faster than doing the same with unserialize().
+ *
+ * @author Nicolas Grekas
+ */
+final class VarExporter
+{
+ /**
+ * Exports a serializable PHP value to PHP code.
+ *
+ * @param mixed $value The value to export
+ * @param bool &$isStaticValue Set to true after execution if the provided value is static, false otherwise
+ * @param array &$foundClasses Classes found in the value are added to this list as both keys and values
+ *
+ * @throws ExceptionInterface When the provided value cannot be serialized
+ */
+ public static function export($value, ?bool &$isStaticValue = null, array &$foundClasses = []): string
+ {
+ $isStaticValue = true;
+
+ if (!\is_object($value) && !(\is_array($value) && $value) && !\is_resource($value) || $value instanceof \UnitEnum) {
+ return Exporter::export($value);
+ }
+
+ $objectsPool = new \SplObjectStorage();
+ $refsPool = [];
+ $objectsCount = 0;
+
+ try {
+ $value = Exporter::prepare([$value], $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0];
+ } finally {
+ $references = [];
+ foreach ($refsPool as $i => $v) {
+ if ($v[0]->count) {
+ $references[1 + $i] = $v[2];
+ }
+ $v[0] = $v[1];
+ }
+ }
+
+ if ($isStaticValue) {
+ return Exporter::export($value);
+ }
+
+ $classes = [];
+ $values = [];
+ $states = [];
+ foreach ($objectsPool as $i => $v) {
+ [, $class, $values[], $wakeup] = $objectsPool[$v];
+ $foundClasses[$class] = $classes[] = $class;
+
+ if (0 < $wakeup) {
+ $states[$wakeup] = $i;
+ } elseif (0 > $wakeup) {
+ $states[-$wakeup] = [$i, array_pop($values)];
+ $values[] = [];
+ }
+ }
+ ksort($states);
+
+ $wakeups = [null];
+ foreach ($states as $v) {
+ if (\is_array($v)) {
+ $wakeups[-$v[0]] = $v[1];
+ } else {
+ $wakeups[] = $v;
+ }
+ }
+
+ if (null === $wakeups[0]) {
+ unset($wakeups[0]);
+ }
+
+ $properties = [];
+ foreach ($values as $i => $vars) {
+ foreach ($vars as $class => $values) {
+ foreach ($values as $name => $v) {
+ $properties[$class][$name][$i] = $v;
+ }
+ }
+ }
+
+ if ($classes || $references) {
+ $value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups);
+ } else {
+ $isStaticValue = true;
+ }
+
+ return Exporter::export($value);
+ }
+}
diff --git a/vendor/symfony/var-exporter/composer.json b/vendor/symfony/var-exporter/composer.json
new file mode 100644
index 0000000..29d4901
--- /dev/null
+++ b/vendor/symfony/var-exporter/composer.json
@@ -0,0 +1,32 @@
+{
+ "name": "symfony/var-exporter",
+ "type": "library",
+ "description": "Allows exporting any serializable PHP data structure to plain PHP code",
+ "keywords": ["export", "serialize", "instantiate", "hydrate", "construct", "clone"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.2.5",
+ "symfony/polyfill-php80": "^1.16"
+ },
+ "require-dev": {
+ "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\VarExporter\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/topthink/think-helper/src/Collection.php b/vendor/topthink/think-helper/src/Collection.php
index 5b19ffc..9403711 100644
--- a/vendor/topthink/think-helper/src/Collection.php
+++ b/vendor/topthink/think-helper/src/Collection.php
@@ -24,6 +24,12 @@ use Traversable;
/**
* 数据集管理类
+ *
+ * @template TKey of array-key
+ * @template-covariant TValue
+ *
+ * @implements ArrayAccess