phpunit
This commit is contained in:
1
.phpunit-cache/test-results
Normal file
1
.phpunit-cache/test-results
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":2,"defects":[],"times":{"IndexTest::testHello":0.001}}
|
||||||
5
composer.json
Normal file
5
composer.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"symfony/http-foundation": "^8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
179
composer.lock
generated
Normal file
179
composer.lock
generated
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "1222a9af69e0a2f38e6b12506a7c3ad3",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "symfony/http-foundation",
|
||||||
|
"version": "v8.0.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/http-foundation.git",
|
||||||
|
"reference": "514ec3aa7982f296b0ad0825f75b6be5779ae9e7"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/514ec3aa7982f296b0ad0825f75b6be5779ae9e7",
|
||||||
|
"reference": "514ec3aa7982f296b0ad0825f75b6be5779ae9e7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.4",
|
||||||
|
"symfony/polyfill-mbstring": "^1.1"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/dbal": "<4.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/dbal": "^4.3",
|
||||||
|
"predis/predis": "^1.1|^2.0",
|
||||||
|
"symfony/cache": "^7.4|^8.0",
|
||||||
|
"symfony/clock": "^7.4|^8.0",
|
||||||
|
"symfony/dependency-injection": "^7.4|^8.0",
|
||||||
|
"symfony/expression-language": "^7.4|^8.0",
|
||||||
|
"symfony/http-kernel": "^7.4|^8.0",
|
||||||
|
"symfony/mime": "^7.4|^8.0",
|
||||||
|
"symfony/rate-limiter": "^7.4|^8.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\HttpFoundation\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/http-foundation/tree/v8.0.3"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-12-23T14:52:06+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-mbstring",
|
||||||
|
"version": "v1.31.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
|
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||||
|
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"ext-mbstring": "*"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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 for the Mbstring extension",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"mbstring",
|
||||||
|
"polyfill",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": {},
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": {},
|
||||||
|
"platform-dev": {},
|
||||||
|
"plugin-api-version": "2.9.0"
|
||||||
|
}
|
||||||
4
phpunit.xml
Normal file
4
phpunit.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<phpunit
|
||||||
|
cacheDirectory=".phpunit-cache"
|
||||||
|
>
|
||||||
|
</phpunit>
|
||||||
17
test.php
Normal file
17
test.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class IndexTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testHello(): void
|
||||||
|
{
|
||||||
|
$_GET['name'] = 'Poopiebutt';
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
include 'index.php';
|
||||||
|
$content = ob_get_clean();
|
||||||
|
|
||||||
|
$this->assertEquals('Hello Poopiebutt', $content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
22
vendor/autoload.php
vendored
Normal file
22
vendor/autoload.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 50600) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, $err);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo $err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException($err);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInitefde9833fcaa12ff1811e00a7a077255::getLoader();
|
||||||
579
vendor/composer/ClassLoader.php
vendored
Normal file
579
vendor/composer/ClassLoader.php
vendored
Normal file
@ -0,0 +1,579 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see https://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see https://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
/** @var \Closure(string):void */
|
||||||
|
private static $includeFile;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
|
// PSR-4
|
||||||
|
/**
|
||||||
|
* @var array<string, array<string, int>>
|
||||||
|
*/
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var array<string, list<string>>
|
||||||
|
*/
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
/**
|
||||||
|
* List of PSR-0 prefixes
|
||||||
|
*
|
||||||
|
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||||
|
*
|
||||||
|
* @var array<string, array<string, list<string>>>
|
||||||
|
*/
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $useIncludePath = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
private $classMap = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, bool>
|
||||||
|
*/
|
||||||
|
private $missingClasses = array();
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, self>
|
||||||
|
*/
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $vendorDir
|
||||||
|
*/
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
self::initializeIncludeClosure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string> Array of classname => path
|
||||||
|
*/
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, string> $classMap Class to filename map
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 base directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return true|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
$includeFile = self::$includeFile;
|
||||||
|
$includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return array<string, self>
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @param string $ext
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function initializeIncludeClosure()
|
||||||
|
{
|
||||||
|
if (self::$includeFile !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
self::$includeFile = \Closure::bind(static function($file) {
|
||||||
|
include $file;
|
||||||
|
}, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
396
vendor/composer/InstalledVersions.php
vendored
Normal file
396
vendor/composer/InstalledVersions.php
vendored
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
|
use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is copied in every Composer installed project and available to all
|
||||||
|
*
|
||||||
|
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||||
|
*
|
||||||
|
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||||
|
*
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class InstalledVersions
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private static $selfDir = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var mixed[]|null
|
||||||
|
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||||
|
*/
|
||||||
|
private static $installed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private static $installedIsLocalDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
|
private static $canGetVendors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
$packages[] = array_keys($installed['versions']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 === \count($packages)) {
|
||||||
|
return $packages[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names with a specific type e.g. 'library'
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackagesByType($type)
|
||||||
|
{
|
||||||
|
$packagesByType = array();
|
||||||
|
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
foreach ($installed['versions'] as $name => $package) {
|
||||||
|
if (isset($package['type']) && $package['type'] === $type) {
|
||||||
|
$packagesByType[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packagesByType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package is installed
|
||||||
|
*
|
||||||
|
* This also returns true if the package name is provided or replaced by another package
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @param bool $includeDevRequirements
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (isset($installed['versions'][$packageName])) {
|
||||||
|
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package satisfies a version constraint
|
||||||
|
*
|
||||||
|
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||||
|
*
|
||||||
|
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||||
|
*
|
||||||
|
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||||
|
* @param string $packageName
|
||||||
|
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||||
|
{
|
||||||
|
$constraint = $parser->parseConstraints((string) $constraint);
|
||||||
|
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||||
|
|
||||||
|
return $provided->matches($constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||||
|
*
|
||||||
|
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||||
|
* whether a given version of a package is installed, and not just whether it exists
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string Version constraint usable with composer/semver
|
||||||
|
*/
|
||||||
|
public static function getVersionRanges($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ranges = array();
|
||||||
|
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' || ', $ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getPrettyVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||||
|
*/
|
||||||
|
public static function getReference($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['reference'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||||
|
*/
|
||||||
|
public static function getInstallPath($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||||
|
*/
|
||||||
|
public static function getRootPackage()
|
||||||
|
{
|
||||||
|
$installed = self::getInstalled();
|
||||||
|
|
||||||
|
return $installed[0]['root'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw installed.php data for custom implementations
|
||||||
|
*
|
||||||
|
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||||
|
*/
|
||||||
|
public static function getRawData()
|
||||||
|
{
|
||||||
|
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
self::$installed = include __DIR__ . '/installed.php';
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||||
|
*
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
public static function getAllRawData()
|
||||||
|
{
|
||||||
|
return self::getInstalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets you reload the static array from another file
|
||||||
|
*
|
||||||
|
* This is only useful for complex integrations in which a project needs to use
|
||||||
|
* this class but then also needs to execute another project's autoloader in process,
|
||||||
|
* and wants to ensure both projects have access to their version of installed.php.
|
||||||
|
*
|
||||||
|
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||||
|
* the data it needs from this class, then call reload() with
|
||||||
|
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||||
|
* the project in which it runs can then also use this class safely, without
|
||||||
|
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||||
|
*
|
||||||
|
* @param array[] $data A vendor/composer/installed.php data set
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||||
|
*/
|
||||||
|
public static function reload($data)
|
||||||
|
{
|
||||||
|
self::$installed = $data;
|
||||||
|
self::$installedByVendor = array();
|
||||||
|
|
||||||
|
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||||
|
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||||
|
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||||
|
// all installed packages for example
|
||||||
|
self::$installedIsLocalDir = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function getSelfDir()
|
||||||
|
{
|
||||||
|
if (self::$selfDir === null) {
|
||||||
|
self::$selfDir = strtr(__DIR__, '\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$selfDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static function getInstalled()
|
||||||
|
{
|
||||||
|
if (null === self::$canGetVendors) {
|
||||||
|
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = array();
|
||||||
|
$copiedLocalDir = false;
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
$selfDir = self::getSelfDir();
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||||
|
$required = require $vendorDir.'/composer/installed.php';
|
||||||
|
self::$installedByVendor[$vendorDir] = $required;
|
||||||
|
$installed[] = $required;
|
||||||
|
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||||
|
self::$installed = $required;
|
||||||
|
self::$installedIsLocalDir = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||||
|
$copiedLocalDir = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||||
|
$required = require __DIR__ . '/installed.php';
|
||||||
|
self::$installed = $required;
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||||
|
$installed[] = self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
vendor/composer/LICENSE
vendored
Normal file
21
vendor/composer/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
10
vendor/composer/autoload_classmap.php
vendored
Normal file
10
vendor/composer/autoload_classmap.php
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
);
|
||||||
10
vendor/composer/autoload_files.php
vendored
Normal file
10
vendor/composer/autoload_files.php
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_files.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||||
|
);
|
||||||
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
||||||
11
vendor/composer/autoload_psr4.php
vendored
Normal file
11
vendor/composer/autoload_psr4.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
||||||
|
'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
|
||||||
|
);
|
||||||
50
vendor/composer/autoload_real.php
vendored
Normal file
50
vendor/composer/autoload_real.php
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInitefde9833fcaa12ff1811e00a7a077255
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Composer\Autoload\ClassLoader
|
||||||
|
*/
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
require __DIR__ . '/platform_check.php';
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInitefde9833fcaa12ff1811e00a7a077255', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInitefde9833fcaa12ff1811e00a7a077255', 'loadClassLoader'));
|
||||||
|
|
||||||
|
require __DIR__ . '/autoload_static.php';
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInitefde9833fcaa12ff1811e00a7a077255::getInitializer($loader));
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
$filesToLoad = \Composer\Autoload\ComposerStaticInitefde9833fcaa12ff1811e00a7a077255::$files;
|
||||||
|
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||||
|
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||||
|
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||||
|
|
||||||
|
require $file;
|
||||||
|
}
|
||||||
|
}, null, null);
|
||||||
|
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||||
|
$requireFile($fileIdentifier, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
vendor/composer/autoload_static.php
vendored
Normal file
45
vendor/composer/autoload_static.php
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInitefde9833fcaa12ff1811e00a7a077255
|
||||||
|
{
|
||||||
|
public static $files = array (
|
||||||
|
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'S' =>
|
||||||
|
array (
|
||||||
|
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
||||||
|
'Symfony\\Component\\HttpFoundation\\' => 33,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'Symfony\\Polyfill\\Mbstring\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
||||||
|
),
|
||||||
|
'Symfony\\Component\\HttpFoundation\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/http-foundation',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $classMap = array (
|
||||||
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInitefde9833fcaa12ff1811e00a7a077255::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInitefde9833fcaa12ff1811e00a7a077255::$prefixDirsPsr4;
|
||||||
|
$loader->classMap = ComposerStaticInitefde9833fcaa12ff1811e00a7a077255::$classMap;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
172
vendor/composer/installed.json
vendored
Normal file
172
vendor/composer/installed.json
vendored
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
{
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "symfony/http-foundation",
|
||||||
|
"version": "v8.0.3",
|
||||||
|
"version_normalized": "8.0.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/http-foundation.git",
|
||||||
|
"reference": "514ec3aa7982f296b0ad0825f75b6be5779ae9e7"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/514ec3aa7982f296b0ad0825f75b6be5779ae9e7",
|
||||||
|
"reference": "514ec3aa7982f296b0ad0825f75b6be5779ae9e7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.4",
|
||||||
|
"symfony/polyfill-mbstring": "^1.1"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/dbal": "<4.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/dbal": "^4.3",
|
||||||
|
"predis/predis": "^1.1|^2.0",
|
||||||
|
"symfony/cache": "^7.4|^8.0",
|
||||||
|
"symfony/clock": "^7.4|^8.0",
|
||||||
|
"symfony/dependency-injection": "^7.4|^8.0",
|
||||||
|
"symfony/expression-language": "^7.4|^8.0",
|
||||||
|
"symfony/http-kernel": "^7.4|^8.0",
|
||||||
|
"symfony/mime": "^7.4|^8.0",
|
||||||
|
"symfony/rate-limiter": "^7.4|^8.0"
|
||||||
|
},
|
||||||
|
"time": "2025-12-23T14:52:06+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\HttpFoundation\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/http-foundation/tree/v8.0.3"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"install-path": "../symfony/http-foundation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-mbstring",
|
||||||
|
"version": "v1.31.0",
|
||||||
|
"version_normalized": "1.31.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
|
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||||
|
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"ext-mbstring": "*"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "For best performance"
|
||||||
|
},
|
||||||
|
"time": "2024-09-09T11:45:10+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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 for the Mbstring extension",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"mbstring",
|
||||||
|
"polyfill",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"dev-package-names": []
|
||||||
|
}
|
||||||
41
vendor/composer/installed.php
vendored
Normal file
41
vendor/composer/installed.php
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php return array(
|
||||||
|
'root' => array(
|
||||||
|
'name' => '__root__',
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'reference' => '24b4960fc8f133d1fb2527058501884ee3391395',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev' => true,
|
||||||
|
),
|
||||||
|
'versions' => array(
|
||||||
|
'__root__' => array(
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'reference' => '24b4960fc8f133d1fb2527058501884ee3391395',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'symfony/http-foundation' => array(
|
||||||
|
'pretty_version' => 'v8.0.3',
|
||||||
|
'version' => '8.0.3.0',
|
||||||
|
'reference' => '514ec3aa7982f296b0ad0825f75b6be5779ae9e7',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/http-foundation',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'symfony/polyfill-mbstring' => array(
|
||||||
|
'pretty_version' => 'v1.31.0',
|
||||||
|
'version' => '1.31.0.0',
|
||||||
|
'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
25
vendor/composer/platform_check.php
vendored
Normal file
25
vendor/composer/platform_check.php
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// platform_check.php @generated by Composer
|
||||||
|
|
||||||
|
$issues = array();
|
||||||
|
|
||||||
|
if (!(PHP_VERSION_ID >= 80400)) {
|
||||||
|
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.4.0". You are running ' . PHP_VERSION . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($issues) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \RuntimeException(
|
||||||
|
'Composer detected issues in your platform: ' . implode(' ', $issues)
|
||||||
|
);
|
||||||
|
}
|
||||||
304
vendor/symfony/http-foundation/AcceptHeader.php
vendored
Normal file
304
vendor/symfony/http-foundation/AcceptHeader.php
vendored
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
// Help opcache.preload discover always-needed symbols
|
||||||
|
class_exists(AcceptHeaderItem::class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an Accept-* header.
|
||||||
|
*
|
||||||
|
* An accept header is compound with a list of items,
|
||||||
|
* sorted by descending quality.
|
||||||
|
*
|
||||||
|
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||||
|
*/
|
||||||
|
class AcceptHeader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array<string, AcceptHeaderItem>
|
||||||
|
*/
|
||||||
|
private array $items = [];
|
||||||
|
|
||||||
|
private bool $sorted = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AcceptHeaderItem[] $items
|
||||||
|
*/
|
||||||
|
public function __construct(array $items)
|
||||||
|
{
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$this->add($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an AcceptHeader instance from a string.
|
||||||
|
*/
|
||||||
|
public static function fromString(?string $headerValue): self
|
||||||
|
{
|
||||||
|
$items = [];
|
||||||
|
foreach (HeaderUtils::split($headerValue ?? '', ',;=') as $i => $parts) {
|
||||||
|
$part = array_shift($parts);
|
||||||
|
$item = new AcceptHeaderItem($part[0], HeaderUtils::combine($parts));
|
||||||
|
|
||||||
|
$items[] = $item->setIndex($i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self($items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns header value's string representation.
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return implode(',', $this->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if header has given value.
|
||||||
|
*/
|
||||||
|
public function has(string $value): bool
|
||||||
|
{
|
||||||
|
$canonicalKey = $this->getCanonicalKey(AcceptHeaderItem::fromString($value));
|
||||||
|
|
||||||
|
return isset($this->items[$canonicalKey]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns given value's item, if exists.
|
||||||
|
*/
|
||||||
|
public function get(string $value): ?AcceptHeaderItem
|
||||||
|
{
|
||||||
|
$queryItem = AcceptHeaderItem::fromString($value.';q=1');
|
||||||
|
$canonicalKey = $this->getCanonicalKey($queryItem);
|
||||||
|
|
||||||
|
if (isset($this->items[$canonicalKey])) {
|
||||||
|
return $this->items[$canonicalKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect and filter matching candidates
|
||||||
|
if (!$candidates = array_filter($this->items, fn (AcceptHeaderItem $item) => $this->matches($item, $queryItem))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
usort(
|
||||||
|
$candidates,
|
||||||
|
fn ($a, $b) => $this->getSpecificity($b, $queryItem) <=> $this->getSpecificity($a, $queryItem) // Descending specificity
|
||||||
|
?: $b->getQuality() <=> $a->getQuality() // Descending quality
|
||||||
|
?: $a->getIndex() <=> $b->getIndex() // Ascending index (stability)
|
||||||
|
);
|
||||||
|
|
||||||
|
return reset($candidates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an item.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function add(AcceptHeaderItem $item): static
|
||||||
|
{
|
||||||
|
$this->items[$this->getCanonicalKey($item)] = $item;
|
||||||
|
$this->sorted = false;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all items.
|
||||||
|
*
|
||||||
|
* @return AcceptHeaderItem[]
|
||||||
|
*/
|
||||||
|
public function all(): array
|
||||||
|
{
|
||||||
|
$this->sort();
|
||||||
|
|
||||||
|
return $this->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters items on their value using given regex.
|
||||||
|
*/
|
||||||
|
public function filter(string $pattern): self
|
||||||
|
{
|
||||||
|
return new self(array_filter($this->items, static fn ($item) => preg_match($pattern, $item->getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns first item.
|
||||||
|
*/
|
||||||
|
public function first(): ?AcceptHeaderItem
|
||||||
|
{
|
||||||
|
$this->sort();
|
||||||
|
|
||||||
|
return $this->items ? reset($this->items) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts items by descending quality.
|
||||||
|
*/
|
||||||
|
private function sort(): void
|
||||||
|
{
|
||||||
|
if (!$this->sorted) {
|
||||||
|
uasort($this->items, static fn ($a, $b) => $b->getQuality() <=> $a->getQuality() ?: $a->getIndex() <=> $b->getIndex());
|
||||||
|
|
||||||
|
$this->sorted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the canonical key for storing/retrieving an item.
|
||||||
|
*/
|
||||||
|
private function getCanonicalKey(AcceptHeaderItem $item): string
|
||||||
|
{
|
||||||
|
$parts = [];
|
||||||
|
|
||||||
|
// Normalize and sort attributes for consistent key generation
|
||||||
|
$attributes = $this->getMediaParams($item);
|
||||||
|
ksort($attributes);
|
||||||
|
|
||||||
|
foreach ($attributes as $name => $value) {
|
||||||
|
if (null === $value) {
|
||||||
|
$parts[] = $name; // Flag parameter (e.g., "flowed")
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quote values containing spaces, commas, semicolons, or equals per RFC 9110
|
||||||
|
// This handles cases like 'format="value with space"' or similar.
|
||||||
|
$quotedValue = \is_string($value) && preg_match('/[\s;,=]/', $value) ? '"'.addcslashes($value, '"\\').'"' : $value;
|
||||||
|
|
||||||
|
$parts[] = $name.'='.$quotedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $item->getValue().($parts ? ';'.implode(';', $parts) : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given header item (range) matches a queried item (value).
|
||||||
|
*
|
||||||
|
* @param AcceptHeaderItem $rangeItem The item from the Accept header (e.g., text/*;format=flowed)
|
||||||
|
* @param AcceptHeaderItem $queryItem The item being queried (e.g., text/plain;format=flowed;charset=utf-8)
|
||||||
|
*/
|
||||||
|
private function matches(AcceptHeaderItem $rangeItem, AcceptHeaderItem $queryItem): bool
|
||||||
|
{
|
||||||
|
$rangeValue = strtolower($rangeItem->getValue());
|
||||||
|
$queryValue = strtolower($queryItem->getValue());
|
||||||
|
|
||||||
|
// Handle universal wildcard ranges
|
||||||
|
if ('*' === $rangeValue || '*/*' === $rangeValue) {
|
||||||
|
return $this->rangeParametersMatch($rangeItem, $queryItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queries for '*' only match wildcard ranges (handled above)
|
||||||
|
if ('*' === $queryValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure media vs. non-media consistency
|
||||||
|
$isQueryMedia = str_contains($queryValue, '/');
|
||||||
|
$isRangeMedia = str_contains($rangeValue, '/');
|
||||||
|
|
||||||
|
if ($isQueryMedia !== $isRangeMedia) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-media: exact match only (wildcards handled above)
|
||||||
|
if (!$isQueryMedia) {
|
||||||
|
return $rangeValue === $queryValue && $this->rangeParametersMatch($rangeItem, $queryItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Media type: type/subtype with wildcards
|
||||||
|
[$queryType, $querySubtype] = explode('/', $queryValue, 2);
|
||||||
|
[$rangeType, $rangeSubtype] = explode('/', $rangeValue, 2) + [1 => '*'];
|
||||||
|
|
||||||
|
if ('*' !== $rangeType && $rangeType !== $queryType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('*' !== $rangeSubtype && $rangeSubtype !== $querySubtype) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameters must match
|
||||||
|
return $this->rangeParametersMatch($rangeItem, $queryItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the parameters of a range item are satisfied by the query item.
|
||||||
|
*
|
||||||
|
* Parameters are case-insensitive; range params must be a subset of query params.
|
||||||
|
*/
|
||||||
|
private function rangeParametersMatch(AcceptHeaderItem $rangeItem, AcceptHeaderItem $queryItem): bool
|
||||||
|
{
|
||||||
|
$queryAttributes = $this->getMediaParams($queryItem);
|
||||||
|
$rangeAttributes = $this->getMediaParams($rangeItem);
|
||||||
|
|
||||||
|
foreach ($rangeAttributes as $name => $rangeValue) {
|
||||||
|
if (!\array_key_exists($name, $queryAttributes)) {
|
||||||
|
return false; // Missing required param
|
||||||
|
}
|
||||||
|
|
||||||
|
$queryValue = $queryAttributes[$name];
|
||||||
|
|
||||||
|
if (null === $rangeValue) {
|
||||||
|
return null === $queryValue; // Both flags or neither
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $queryValue || strtolower($queryValue) !== strtolower($rangeValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a specificity score for sorting: media precision + param count.
|
||||||
|
*/
|
||||||
|
private function getSpecificity(AcceptHeaderItem $item, AcceptHeaderItem $queryItem): int
|
||||||
|
{
|
||||||
|
$rangeValue = strtolower($item->getValue());
|
||||||
|
$queryValue = strtolower($queryItem->getValue());
|
||||||
|
|
||||||
|
$paramCount = \count($this->getMediaParams($item));
|
||||||
|
|
||||||
|
$isQueryMedia = str_contains($queryValue, '/');
|
||||||
|
$isRangeMedia = str_contains($rangeValue, '/');
|
||||||
|
|
||||||
|
if (!$isQueryMedia && !$isRangeMedia) {
|
||||||
|
return ('*' !== $rangeValue ? 2000 : 1000) + $paramCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$rangeType, $rangeSubtype] = explode('/', $rangeValue, 2) + [1 => '*'];
|
||||||
|
|
||||||
|
$specificity = match (true) {
|
||||||
|
'*' !== $rangeSubtype => 3000, // Exact subtype (text/plain)
|
||||||
|
'*' !== $rangeType => 2000, // Type wildcard (text/*)
|
||||||
|
default => 1000, // Full wildcard (*/* or *)
|
||||||
|
};
|
||||||
|
|
||||||
|
return $specificity + $paramCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns normalized attributes: keys lowercased, excluding 'q'.
|
||||||
|
*/
|
||||||
|
private function getMediaParams(AcceptHeaderItem $item): array
|
||||||
|
{
|
||||||
|
$attributes = array_change_key_case($item->getAttributes(), \CASE_LOWER);
|
||||||
|
unset($attributes['q']);
|
||||||
|
|
||||||
|
return $attributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
159
vendor/symfony/http-foundation/AcceptHeaderItem.php
vendored
Normal file
159
vendor/symfony/http-foundation/AcceptHeaderItem.php
vendored
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an Accept-* header item.
|
||||||
|
*
|
||||||
|
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||||
|
*/
|
||||||
|
class AcceptHeaderItem
|
||||||
|
{
|
||||||
|
private float $quality = 1.0;
|
||||||
|
private int $index = 0;
|
||||||
|
private array $attributes = [];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private string $value,
|
||||||
|
array $attributes = [],
|
||||||
|
) {
|
||||||
|
foreach ($attributes as $name => $value) {
|
||||||
|
$this->setAttribute($name, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an AcceptHeaderInstance instance from a string.
|
||||||
|
*/
|
||||||
|
public static function fromString(?string $itemValue): self
|
||||||
|
{
|
||||||
|
$parts = HeaderUtils::split($itemValue ?? '', ';=');
|
||||||
|
|
||||||
|
$part = array_shift($parts);
|
||||||
|
$attributes = HeaderUtils::combine($parts);
|
||||||
|
|
||||||
|
return new self($part[0], $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns header value's string representation.
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
$string = $this->value.($this->quality < 1 ? ';q='.$this->quality : '');
|
||||||
|
if (\count($this->attributes) > 0) {
|
||||||
|
$string .= '; '.HeaderUtils::toString($this->attributes, ';');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the item value.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setValue(string $value): static
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item value.
|
||||||
|
*/
|
||||||
|
public function getValue(): string
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the item quality.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setQuality(float $quality): static
|
||||||
|
{
|
||||||
|
$this->quality = $quality;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item quality.
|
||||||
|
*/
|
||||||
|
public function getQuality(): float
|
||||||
|
{
|
||||||
|
return $this->quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the item index.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setIndex(int $index): static
|
||||||
|
{
|
||||||
|
$this->index = $index;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item index.
|
||||||
|
*/
|
||||||
|
public function getIndex(): int
|
||||||
|
{
|
||||||
|
return $this->index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if an attribute exists.
|
||||||
|
*/
|
||||||
|
public function hasAttribute(string $name): bool
|
||||||
|
{
|
||||||
|
return isset($this->attributes[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an attribute by its name.
|
||||||
|
*/
|
||||||
|
public function getAttribute(string $name, mixed $default = null): mixed
|
||||||
|
{
|
||||||
|
return $this->attributes[$name] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all attributes.
|
||||||
|
*/
|
||||||
|
public function getAttributes(): array
|
||||||
|
{
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an attribute.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setAttribute(string $name, string $value): static
|
||||||
|
{
|
||||||
|
if ('q' === $name) {
|
||||||
|
$this->quality = (float) $value;
|
||||||
|
} else {
|
||||||
|
$this->attributes[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
396
vendor/symfony/http-foundation/BinaryFileResponse.php
vendored
Normal file
396
vendor/symfony/http-foundation/BinaryFileResponse.php
vendored
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BinaryFileResponse represents an HTTP response delivering a file.
|
||||||
|
*
|
||||||
|
* @author Niklas Fiekas <niklas.fiekas@tu-clausthal.de>
|
||||||
|
* @author stealth35 <stealth35-php@live.fr>
|
||||||
|
* @author Igor Wiedler <igor@wiedler.ch>
|
||||||
|
* @author Jordan Alliot <jordan.alliot@gmail.com>
|
||||||
|
* @author Sergey Linnik <linniksa@gmail.com>
|
||||||
|
*/
|
||||||
|
class BinaryFileResponse extends Response
|
||||||
|
{
|
||||||
|
protected static bool $trustXSendfileTypeHeader = false;
|
||||||
|
|
||||||
|
protected File $file;
|
||||||
|
protected ?\SplTempFileObject $tempFileObject = null;
|
||||||
|
protected int $offset = 0;
|
||||||
|
protected int $maxlen = -1;
|
||||||
|
protected bool $deleteFileAfterSend = false;
|
||||||
|
protected int $chunkSize = 16 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SplFileInfo|string $file The file to stream
|
||||||
|
* @param int $status The response status code (200 "OK" by default)
|
||||||
|
* @param array $headers An array of response headers
|
||||||
|
* @param bool $public Files are public by default
|
||||||
|
* @param string|null $contentDisposition The type of Content-Disposition to set automatically with the filename
|
||||||
|
* @param bool $autoEtag Whether the ETag header should be automatically set
|
||||||
|
* @param bool $autoLastModified Whether the Last-Modified header should be automatically set
|
||||||
|
*/
|
||||||
|
public function __construct(\SplFileInfo|string $file, int $status = 200, array $headers = [], bool $public = true, ?string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
|
||||||
|
{
|
||||||
|
parent::__construct(null, $status, $headers);
|
||||||
|
|
||||||
|
$this->setFile($file, $contentDisposition, $autoEtag, $autoLastModified);
|
||||||
|
|
||||||
|
if ($public) {
|
||||||
|
$this->setPublic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the file to stream.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws FileException
|
||||||
|
*/
|
||||||
|
public function setFile(\SplFileInfo|string $file, ?string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true): static
|
||||||
|
{
|
||||||
|
$isTemporaryFile = $file instanceof \SplTempFileObject;
|
||||||
|
$this->tempFileObject = $isTemporaryFile ? $file : null;
|
||||||
|
|
||||||
|
if (!$file instanceof File) {
|
||||||
|
if ($file instanceof \SplFileInfo) {
|
||||||
|
$file = new File($file->getPathname(), !$isTemporaryFile);
|
||||||
|
} else {
|
||||||
|
$file = new File($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$file->isReadable() && !$isTemporaryFile) {
|
||||||
|
throw new FileException('File must be readable.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->file = $file;
|
||||||
|
|
||||||
|
if ($autoEtag) {
|
||||||
|
$this->setAutoEtag();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($autoLastModified && !$isTemporaryFile) {
|
||||||
|
$this->setAutoLastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($contentDisposition) {
|
||||||
|
$this->setContentDisposition($contentDisposition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the file.
|
||||||
|
*/
|
||||||
|
public function getFile(): File
|
||||||
|
{
|
||||||
|
return $this->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the response stream chunk size.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setChunkSize(int $chunkSize): static
|
||||||
|
{
|
||||||
|
if ($chunkSize < 1) {
|
||||||
|
throw new \InvalidArgumentException('The chunk size of a BinaryFileResponse cannot be less than 1.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->chunkSize = $chunkSize;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically sets the Last-Modified header according the file modification date.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setAutoLastModified(): static
|
||||||
|
{
|
||||||
|
$this->setLastModified(\DateTimeImmutable::createFromFormat('U', $this->tempFileObject ? time() : $this->file->getMTime()));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically sets the ETag header according to the checksum of the file.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setAutoEtag(): static
|
||||||
|
{
|
||||||
|
$this->setEtag(base64_encode(hash_file('xxh128', $this->file->getPathname(), true)));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Content-Disposition header with the given filename.
|
||||||
|
*
|
||||||
|
* @param string $disposition ResponseHeaderBag::DISPOSITION_INLINE or ResponseHeaderBag::DISPOSITION_ATTACHMENT
|
||||||
|
* @param string $filename Optionally use this UTF-8 encoded filename instead of the real name of the file
|
||||||
|
* @param string $filenameFallback A fallback filename, containing only ASCII characters. Defaults to an automatically encoded filename
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setContentDisposition(string $disposition, string $filename = '', string $filenameFallback = ''): static
|
||||||
|
{
|
||||||
|
if ('' === $filename) {
|
||||||
|
$filename = $this->file->getFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || str_contains($filename, '%'))) {
|
||||||
|
$encoding = mb_detect_encoding($filename, null, true) ?: '8bit';
|
||||||
|
|
||||||
|
for ($i = 0, $filenameLength = mb_strlen($filename, $encoding); $i < $filenameLength; ++$i) {
|
||||||
|
$char = mb_substr($filename, $i, 1, $encoding);
|
||||||
|
|
||||||
|
if ('%' === $char || \ord($char[0]) < 32 || \ord($char[0]) > 126) {
|
||||||
|
$filenameFallback .= '_';
|
||||||
|
} else {
|
||||||
|
$filenameFallback .= $char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback);
|
||||||
|
$this->headers->set('Content-Disposition', $dispositionHeader);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepare(Request $request): static
|
||||||
|
{
|
||||||
|
if ($this->isInformational() || $this->isEmpty()) {
|
||||||
|
parent::prepare($request);
|
||||||
|
|
||||||
|
$this->maxlen = 0;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->headers->has('Content-Type')) {
|
||||||
|
$mimeType = null;
|
||||||
|
if (!$this->tempFileObject) {
|
||||||
|
$mimeType = $this->file->getMimeType();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::prepare($request);
|
||||||
|
|
||||||
|
$this->offset = 0;
|
||||||
|
$this->maxlen = -1;
|
||||||
|
|
||||||
|
if ($this->tempFileObject) {
|
||||||
|
$fileSize = $this->tempFileObject->fstat()['size'];
|
||||||
|
} elseif (false === $fileSize = $this->file->getSize()) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
$this->headers->remove('Transfer-Encoding');
|
||||||
|
$this->headers->set('Content-Length', $fileSize);
|
||||||
|
|
||||||
|
if (!$this->headers->has('Accept-Ranges')) {
|
||||||
|
// Only accept ranges on safe HTTP methods
|
||||||
|
$this->headers->set('Accept-Ranges', $request->isMethodSafe() ? 'bytes' : 'none');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) {
|
||||||
|
// Use X-Sendfile, do not send any content.
|
||||||
|
$type = $request->headers->get('X-Sendfile-Type');
|
||||||
|
$path = $this->file->getRealPath();
|
||||||
|
// Fall back to scheme://path for stream wrapped locations.
|
||||||
|
if (false === $path) {
|
||||||
|
$path = $this->file->getPathname();
|
||||||
|
}
|
||||||
|
if ('x-accel-redirect' === strtolower($type)) {
|
||||||
|
// Do X-Accel-Mapping substitutions.
|
||||||
|
// @link https://github.com/rack/rack/blob/main/lib/rack/sendfile.rb
|
||||||
|
// @link https://mattbrictson.com/blog/accelerated-rails-downloads
|
||||||
|
if (!$request->headers->has('X-Accel-Mapping')) {
|
||||||
|
throw new \LogicException('The "X-Accel-Mapping" header must be set when "X-Sendfile-Type" is set to "X-Accel-Redirect".');
|
||||||
|
}
|
||||||
|
$parts = HeaderUtils::split($request->headers->get('X-Accel-Mapping'), ',=');
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
[$pathPrefix, $location] = $part;
|
||||||
|
if (str_starts_with($path, $pathPrefix)) {
|
||||||
|
$path = $location.substr($path, \strlen($pathPrefix));
|
||||||
|
// Only set X-Accel-Redirect header if a valid URI can be produced
|
||||||
|
// as nginx does not serve arbitrary file paths.
|
||||||
|
$this->headers->set($type, rawurlencode($path));
|
||||||
|
$this->maxlen = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->headers->set($type, $path);
|
||||||
|
$this->maxlen = 0;
|
||||||
|
}
|
||||||
|
} elseif ($request->headers->has('Range') && $request->isMethod('GET')) {
|
||||||
|
// Process the range headers.
|
||||||
|
if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) {
|
||||||
|
$range = $request->headers->get('Range');
|
||||||
|
|
||||||
|
if (str_starts_with($range, 'bytes=')) {
|
||||||
|
[$start, $end] = explode('-', substr($range, 6), 2) + [1 => 0];
|
||||||
|
|
||||||
|
$end = ('' === $end) ? $fileSize - 1 : (int) $end;
|
||||||
|
|
||||||
|
if ('' === $start) {
|
||||||
|
$start = $fileSize - $end;
|
||||||
|
$end = $fileSize - 1;
|
||||||
|
} else {
|
||||||
|
$start = (int) $start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($start <= $end) {
|
||||||
|
$end = min($end, $fileSize - 1);
|
||||||
|
if ($start < 0 || $start > $end) {
|
||||||
|
$this->setStatusCode(416);
|
||||||
|
$this->headers->set('Content-Range', \sprintf('bytes */%s', $fileSize));
|
||||||
|
} elseif ($end - $start < $fileSize - 1) {
|
||||||
|
$this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
|
||||||
|
$this->offset = $start;
|
||||||
|
|
||||||
|
$this->setStatusCode(206);
|
||||||
|
$this->headers->set('Content-Range', \sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
|
||||||
|
$this->headers->set('Content-Length', $end - $start + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->isMethod('HEAD')) {
|
||||||
|
$this->maxlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasValidIfRangeHeader(?string $header): bool
|
||||||
|
{
|
||||||
|
if ($this->getEtag() === $header) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $lastModified = $this->getLastModified()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lastModified->format('D, d M Y H:i:s').' GMT' === $header;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendContent(): static
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (!$this->isSuccessful()) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === $this->maxlen) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = fopen('php://output', 'w');
|
||||||
|
|
||||||
|
if ($this->tempFileObject) {
|
||||||
|
$file = $this->tempFileObject;
|
||||||
|
$file->rewind();
|
||||||
|
} else {
|
||||||
|
$file = new \SplFileObject($this->file->getPathname(), 'r');
|
||||||
|
}
|
||||||
|
|
||||||
|
ignore_user_abort(true);
|
||||||
|
|
||||||
|
if (0 !== $this->offset) {
|
||||||
|
$file->fseek($this->offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
$length = $this->maxlen;
|
||||||
|
while ($length && !$file->eof()) {
|
||||||
|
$read = $length > $this->chunkSize || 0 > $length ? $this->chunkSize : $length;
|
||||||
|
|
||||||
|
if (false === $data = $file->fread($read)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while ('' !== $data) {
|
||||||
|
$read = fwrite($out, $data);
|
||||||
|
if (false === $read || connection_aborted()) {
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
if (0 < $length) {
|
||||||
|
$length -= $read;
|
||||||
|
}
|
||||||
|
$data = substr($data, $read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($out);
|
||||||
|
} finally {
|
||||||
|
if (null === $this->tempFileObject && $this->deleteFileAfterSend && is_file($this->file->getPathname())) {
|
||||||
|
unlink($this->file->getPathname());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \LogicException when the content is not null
|
||||||
|
*/
|
||||||
|
public function setContent(?string $content): static
|
||||||
|
{
|
||||||
|
if (null !== $content) {
|
||||||
|
throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent(): string|false
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trust X-Sendfile-Type header.
|
||||||
|
*/
|
||||||
|
public static function trustXSendfileTypeHeader(): void
|
||||||
|
{
|
||||||
|
self::$trustXSendfileTypeHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this is set to true, the file will be unlinked after the request is sent
|
||||||
|
* Note: If the X-Sendfile header is used, the deleteFileAfterSend setting will not be used.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function deleteFileAfterSend(bool $shouldDelete = true): static
|
||||||
|
{
|
||||||
|
$this->deleteFileAfterSend = $shouldDelete;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
422
vendor/symfony/http-foundation/CHANGELOG.md
vendored
Normal file
422
vendor/symfony/http-foundation/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
CHANGELOG
|
||||||
|
=========
|
||||||
|
|
||||||
|
8.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* Drop HTTP method override support for methods GET, HEAD, CONNECT and TRACE
|
||||||
|
* Add argument `$subtypeFallback` to `Request::getFormat()`
|
||||||
|
* Remove the following deprecated session options from `NativeSessionStorage`: `referer_check`, `use_only_cookies`, `use_trans_sid`, `sid_length`, `sid_bits_per_character`, `trans_sid_hosts`, `trans_sid_tags`
|
||||||
|
* Trigger PHP warning when using `Request::sendHeaders()` after headers have already been sent; use a `StreamedResponse` instead
|
||||||
|
* Add arguments `$v4Bytes` and `$v6Bytes` to `IpUtils::anonymize()`
|
||||||
|
* Add argument `$partitioned` to `ResponseHeaderBag::clearCookie()`
|
||||||
|
* Add argument `$expiration` to `UriSigner::sign()`
|
||||||
|
* Remove `Request::get()`, use properties `->attributes`, `query` or `request` directly instead
|
||||||
|
* Remove accepting null `$format` argument to `Request::setFormat()`
|
||||||
|
|
||||||
|
7.4
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add `#[WithHttpStatus]` to define status codes: 404 for `SignedUriException` and 403 for `ExpiredSignedUriException`
|
||||||
|
* Add support for the `QUERY` HTTP method
|
||||||
|
* Add support for structured MIME suffix
|
||||||
|
* Add `Request::set/getAllowedHttpMethodOverride()` to list which HTTP methods can be overridden
|
||||||
|
* Deprecate using `Request::sendHeaders()` after headers have already been sent; use a `StreamedResponse` instead
|
||||||
|
* Deprecate method `Request::get()`, use properties `->attributes`, `query` or `request` directly instead
|
||||||
|
* Make `Request::createFromGlobals()` parse the body of PUT, DELETE, PATCH and QUERY requests
|
||||||
|
* Deprecate HTTP method override for methods GET, HEAD, CONNECT and TRACE; it will be ignored in Symfony 8.0
|
||||||
|
* Deprecate accepting null `$format` argument to `Request::setFormat()`
|
||||||
|
|
||||||
|
7.3
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add support for iterable of string in `StreamedResponse`
|
||||||
|
* Add `EventStreamResponse` and `ServerEvent` classes to streamline server event streaming
|
||||||
|
* Add support for `valkey:` / `valkeys:` schemes for sessions
|
||||||
|
* `Request::getPreferredLanguage()` now favors a more preferred language above exactly matching a locale
|
||||||
|
* Allow `UriSigner` to use a `ClockInterface`
|
||||||
|
* Add `UriSigner::verify()`
|
||||||
|
|
||||||
|
7.2
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add optional `$requests` parameter to `RequestStack::__construct()`
|
||||||
|
* Add optional `$v4Bytes` and `$v6Bytes` parameters to `IpUtils::anonymize()`
|
||||||
|
* Add `PRIVATE_SUBNETS` as a shortcut for private IP address ranges to `Request::setTrustedProxies()`
|
||||||
|
* Deprecate passing `referer_check`, `use_only_cookies`, `use_trans_sid`, `trans_sid_hosts`, `trans_sid_tags`, `sid_bits_per_character` and `sid_length` options to `NativeSessionStorage`
|
||||||
|
|
||||||
|
7.1
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add optional `$expirationParameter` argument to `UriSigner::__construct()`
|
||||||
|
* Add optional `$expiration` argument to `UriSigner::sign()`
|
||||||
|
* Rename `$parameter` argument of `UriSigner::__construct()` to `$hashParameter`
|
||||||
|
* Add `UploadedFile::getClientOriginalPath()`
|
||||||
|
* Add `QueryParameterRequestMatcher`
|
||||||
|
* Add `HeaderRequestMatcher`
|
||||||
|
* Add support for `\SplTempFileObject` in `BinaryFileResponse`
|
||||||
|
* Add `verbose` argument to response test constraints
|
||||||
|
|
||||||
|
7.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* Calling `ParameterBag::filter()` throws an `UnexpectedValueException` on invalid value, unless flag `FILTER_NULL_ON_FAILURE` is set
|
||||||
|
* Calling `ParameterBag::getInt()` and `ParameterBag::getBool()` throws an `UnexpectedValueException` on invalid value
|
||||||
|
* Remove classes `RequestMatcher` and `ExpressionRequestMatcher`
|
||||||
|
* Remove `Request::getContentType()`, use `Request::getContentTypeFormat()` instead
|
||||||
|
* Throw an `InvalidArgumentException` when calling `Request::create()` with a malformed URI
|
||||||
|
* Require explicit argument when calling `JsonResponse::setCallback()`, `Response::setExpires/setLastModified/setEtag()`, `MockArraySessionStorage/NativeSessionStorage::setMetadataBag()`, `NativeSessionStorage::setSaveHandler()`
|
||||||
|
* Add argument `$statusCode` to `Response::sendHeaders()` and `StreamedResponse::sendHeaders()`
|
||||||
|
|
||||||
|
6.4
|
||||||
|
---
|
||||||
|
|
||||||
|
* Make `HeaderBag::getDate()`, `Response::getDate()`, `getExpires()` and `getLastModified()` return a `DateTimeImmutable`
|
||||||
|
* Support root-level `Generator` in `StreamedJsonResponse`
|
||||||
|
* Add `UriSigner` from the HttpKernel component
|
||||||
|
* Add `partitioned` flag to `Cookie` (CHIPS Cookie)
|
||||||
|
* Add argument `bool $flush = true` to `Response::send()`
|
||||||
|
* Make `MongoDbSessionHandler` instantiable with the mongodb extension directly
|
||||||
|
|
||||||
|
6.3
|
||||||
|
---
|
||||||
|
|
||||||
|
* Calling `ParameterBag::getDigit()`, `getAlnum()`, `getAlpha()` on an `array` throws a `UnexpectedValueException` instead of a `TypeError`
|
||||||
|
* Add `ParameterBag::getString()` to convert a parameter into string and throw an exception if the value is invalid
|
||||||
|
* Add `ParameterBag::getEnum()`
|
||||||
|
* Create migration for session table when pdo handler is used
|
||||||
|
* Add support for Relay PHP extension for Redis
|
||||||
|
* The `Response::sendHeaders()` method now takes an optional HTTP status code as parameter, allowing to send informational responses such as Early Hints responses (103 status code)
|
||||||
|
* Add `IpUtils::isPrivateIp()`
|
||||||
|
* Add `Request::getPayload(): InputBag`
|
||||||
|
* Deprecate conversion of invalid values in `ParameterBag::getInt()` and `ParameterBag::getBoolean()`,
|
||||||
|
* Deprecate ignoring invalid values when using `ParameterBag::filter()`, unless flag `FILTER_NULL_ON_FAILURE` is set
|
||||||
|
|
||||||
|
6.2
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add `StreamedJsonResponse` class for efficient JSON streaming
|
||||||
|
* The HTTP cache store uses the `xxh128` algorithm
|
||||||
|
* Deprecate calling `JsonResponse::setCallback()`, `Response::setExpires/setLastModified/setEtag()`, `MockArraySessionStorage/NativeSessionStorage::setMetadataBag()`, `NativeSessionStorage::setSaveHandler()` without arguments
|
||||||
|
* Add request matchers under the `Symfony\Component\HttpFoundation\RequestMatcher` namespace
|
||||||
|
* Deprecate `RequestMatcher` in favor of `ChainRequestMatcher`
|
||||||
|
* Deprecate `Symfony\Component\HttpFoundation\ExpressionRequestMatcher` in favor of `Symfony\Component\HttpFoundation\RequestMatcher\ExpressionRequestMatcher`
|
||||||
|
|
||||||
|
6.1
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add stale while revalidate and stale if error cache header
|
||||||
|
* Allow dynamic session "ttl" when using a remote storage
|
||||||
|
* Deprecate `Request::getContentType()`, use `Request::getContentTypeFormat()` instead
|
||||||
|
|
||||||
|
6.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* Remove the `NamespacedAttributeBag` class
|
||||||
|
* Removed `Response::create()`, `JsonResponse::create()`,
|
||||||
|
`RedirectResponse::create()`, `StreamedResponse::create()` and
|
||||||
|
`BinaryFileResponse::create()` methods (use `__construct()` instead)
|
||||||
|
* Not passing a `Closure` together with `FILTER_CALLBACK` to `ParameterBag::filter()` throws an `\InvalidArgumentException`; wrap your filter in a closure instead
|
||||||
|
* Not passing a `Closure` together with `FILTER_CALLBACK` to `InputBag::filter()` throws an `\InvalidArgumentException`; wrap your filter in a closure instead
|
||||||
|
* Removed the `Request::HEADER_X_FORWARDED_ALL` constant, use either `Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO` or `Request::HEADER_X_FORWARDED_AWS_ELB` or `Request::HEADER_X_FORWARDED_TRAEFIK`constants instead
|
||||||
|
* Rename `RequestStack::getMasterRequest()` to `getMainRequest()`
|
||||||
|
* Not passing `FILTER_REQUIRE_ARRAY` or `FILTER_FORCE_ARRAY` flags to `InputBag::filter()` when filtering an array will throw `BadRequestException`
|
||||||
|
* Removed the `Request::HEADER_X_FORWARDED_ALL` constant
|
||||||
|
* Retrieving non-scalar values using `InputBag::get()` will throw `BadRequestException` (use `InputBad::all()` instead to retrieve an array)
|
||||||
|
* Passing non-scalar default value as the second argument `InputBag::get()` will throw `\InvalidArgumentException`
|
||||||
|
* Passing non-scalar, non-array value as the second argument `InputBag::set()` will throw `\InvalidArgumentException`
|
||||||
|
* Passing `null` as `$requestIp` to `IpUtils::__checkIp()`, `IpUtils::__checkIp4()` or `IpUtils::__checkIp6()` is not supported anymore.
|
||||||
|
|
||||||
|
5.4
|
||||||
|
---
|
||||||
|
|
||||||
|
* Deprecate passing `null` as `$requestIp` to `IpUtils::__checkIp()`, `IpUtils::__checkIp4()` or `IpUtils::__checkIp6()`, pass an empty string instead.
|
||||||
|
* Add the `litespeed_finish_request` method to work with Litespeed
|
||||||
|
* Deprecate `upload_progress.*` and `url_rewriter.tags` session options
|
||||||
|
* Allow setting session options via DSN
|
||||||
|
|
||||||
|
5.3
|
||||||
|
---
|
||||||
|
|
||||||
|
* Add the `SessionFactory`, `NativeSessionStorageFactory`, `PhpBridgeSessionStorageFactory` and `MockFileSessionStorageFactory` classes
|
||||||
|
* Calling `Request::getSession()` when there is no available session throws a `SessionNotFoundException`
|
||||||
|
* Add the `RequestStack::getSession` method
|
||||||
|
* Deprecate the `NamespacedAttributeBag` class
|
||||||
|
* Add `ResponseFormatSame` PHPUnit constraint
|
||||||
|
* Deprecate the `RequestStack::getMasterRequest()` method and add `getMainRequest()` as replacement
|
||||||
|
|
||||||
|
5.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added support for `X-Forwarded-Prefix` header
|
||||||
|
* added `HeaderUtils::parseQuery()`: it does the same as `parse_str()` but preserves dots in variable names
|
||||||
|
* added `File::getContent()`
|
||||||
|
* added ability to use comma separated ip addresses for `RequestMatcher::matchIps()`
|
||||||
|
* added `Request::toArray()` to parse a JSON request body to an array
|
||||||
|
* added `RateLimiter\RequestRateLimiterInterface` and `RateLimiter\AbstractRequestRateLimiter`
|
||||||
|
* deprecated not passing a `Closure` together with `FILTER_CALLBACK` to `ParameterBag::filter()`; wrap your filter in a closure instead.
|
||||||
|
* Deprecated the `Request::HEADER_X_FORWARDED_ALL` constant, use either `HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO` or `HEADER_X_FORWARDED_AWS_ELB` or `HEADER_X_FORWARDED_TRAEFIK` constants instead.
|
||||||
|
* Deprecated `BinaryFileResponse::create()`, use `__construct()` instead
|
||||||
|
|
||||||
|
5.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added `Cookie::withValue`, `Cookie::withDomain`, `Cookie::withExpires`,
|
||||||
|
`Cookie::withPath`, `Cookie::withSecure`, `Cookie::withHttpOnly`,
|
||||||
|
`Cookie::withRaw`, `Cookie::withSameSite`
|
||||||
|
* Deprecate `Response::create()`, `JsonResponse::create()`,
|
||||||
|
`RedirectResponse::create()`, and `StreamedResponse::create()` methods (use
|
||||||
|
`__construct()` instead)
|
||||||
|
* added `Request::preferSafeContent()` and `Response::setContentSafe()` to handle "safe" HTTP preference
|
||||||
|
according to [RFC 8674](https://tools.ietf.org/html/rfc8674)
|
||||||
|
* made the Mime component an optional dependency
|
||||||
|
* added `MarshallingSessionHandler`, `IdentityMarshaller`
|
||||||
|
* made `Session` accept a callback to report when the session is being used
|
||||||
|
* Add support for all core cache control directives
|
||||||
|
* Added `Symfony\Component\HttpFoundation\InputBag`
|
||||||
|
* Deprecated retrieving non-string values using `InputBag::get()`, use `InputBag::all()` if you need access to the collection of values
|
||||||
|
|
||||||
|
5.0.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* made `Cookie` auto-secure and lax by default
|
||||||
|
* removed classes in the `MimeType` namespace, use the Symfony Mime component instead
|
||||||
|
* removed method `UploadedFile::getClientSize()` and the related constructor argument
|
||||||
|
* made `Request::getSession()` throw if the session has not been set before
|
||||||
|
* removed `Response::HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL`
|
||||||
|
* passing a null url when instantiating a `RedirectResponse` is not allowed
|
||||||
|
|
||||||
|
4.4.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* passing arguments to `Request::isMethodSafe()` is deprecated.
|
||||||
|
* `ApacheRequest` is deprecated, use the `Request` class instead.
|
||||||
|
* passing a third argument to `HeaderBag::get()` is deprecated, use method `all()` instead
|
||||||
|
* [BC BREAK] `PdoSessionHandler` with MySQL changed the type of the lifetime column,
|
||||||
|
make sure to run `ALTER TABLE sessions MODIFY sess_lifetime INTEGER UNSIGNED NOT NULL` to
|
||||||
|
update your database.
|
||||||
|
* `PdoSessionHandler` now precalculates the expiry timestamp in the lifetime column,
|
||||||
|
make sure to run `CREATE INDEX expiry ON sessions (sess_lifetime)` to update your database
|
||||||
|
to speed up garbage collection of expired sessions.
|
||||||
|
* added `SessionHandlerFactory` to create session handlers with a DSN
|
||||||
|
* added `IpUtils::anonymize()` to help with GDPR compliance.
|
||||||
|
|
||||||
|
4.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added PHPUnit constraints: `RequestAttributeValueSame`, `ResponseCookieValueSame`, `ResponseHasCookie`,
|
||||||
|
`ResponseHasHeader`, `ResponseHeaderSame`, `ResponseIsRedirected`, `ResponseIsSuccessful`, and `ResponseStatusCodeSame`
|
||||||
|
* deprecated `MimeTypeGuesserInterface` and `ExtensionGuesserInterface` in favor of `Symfony\Component\Mime\MimeTypesInterface`.
|
||||||
|
* deprecated `MimeType` and `MimeTypeExtensionGuesser` in favor of `Symfony\Component\Mime\MimeTypes`.
|
||||||
|
* deprecated `FileBinaryMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileBinaryMimeTypeGuesser`.
|
||||||
|
* deprecated `FileinfoMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileinfoMimeTypeGuesser`.
|
||||||
|
* added `UrlHelper` that allows to get an absolute URL and a relative path for a given path
|
||||||
|
|
||||||
|
4.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* the default value of the "$secure" and "$samesite" arguments of Cookie's constructor
|
||||||
|
will respectively change from "false" to "null" and from "null" to "lax" in Symfony
|
||||||
|
5.0, you should define their values explicitly or use "Cookie::create()" instead.
|
||||||
|
* added `matchPort()` in RequestMatcher
|
||||||
|
|
||||||
|
4.1.3
|
||||||
|
-----
|
||||||
|
|
||||||
|
* [BC BREAK] Support for the IIS-only `X_ORIGINAL_URL` and `X_REWRITE_URL`
|
||||||
|
HTTP headers has been dropped for security reasons.
|
||||||
|
|
||||||
|
4.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Query string normalization uses `parse_str()` instead of custom parsing logic.
|
||||||
|
* Passing the file size to the constructor of the `UploadedFile` class is deprecated.
|
||||||
|
* The `getClientSize()` method of the `UploadedFile` class is deprecated. Use `getSize()` instead.
|
||||||
|
* added `RedisSessionHandler` to use Redis as a session storage
|
||||||
|
* The `get()` method of the `AcceptHeader` class now takes into account the
|
||||||
|
`*` and `*/*` default values (if they are present in the Accept HTTP header)
|
||||||
|
when looking for items.
|
||||||
|
* deprecated `Request::getSession()` when no session has been set. Use `Request::hasSession()` instead.
|
||||||
|
* added `CannotWriteFileException`, `ExtensionFileException`, `FormSizeFileException`,
|
||||||
|
`IniSizeFileException`, `NoFileException`, `NoTmpDirFileException`, `PartialFileException` to
|
||||||
|
handle failed `UploadedFile`.
|
||||||
|
* added `MigratingSessionHandler` for migrating between two session handlers without losing sessions
|
||||||
|
* added `HeaderUtils`.
|
||||||
|
|
||||||
|
4.0.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()`
|
||||||
|
methods have been removed
|
||||||
|
* the `Request::HEADER_CLIENT_IP` constant has been removed, use
|
||||||
|
`Request::HEADER_X_FORWARDED_FOR` instead
|
||||||
|
* the `Request::HEADER_CLIENT_HOST` constant has been removed, use
|
||||||
|
`Request::HEADER_X_FORWARDED_HOST` instead
|
||||||
|
* the `Request::HEADER_CLIENT_PROTO` constant has been removed, use
|
||||||
|
`Request::HEADER_X_FORWARDED_PROTO` instead
|
||||||
|
* the `Request::HEADER_CLIENT_PORT` constant has been removed, use
|
||||||
|
`Request::HEADER_X_FORWARDED_PORT` instead
|
||||||
|
* checking for cacheable HTTP methods using the `Request::isMethodSafe()`
|
||||||
|
method (by not passing `false` as its argument) is not supported anymore and
|
||||||
|
throws a `\BadMethodCallException`
|
||||||
|
* the `WriteCheckSessionHandler`, `NativeSessionHandler` and `NativeProxy` classes have been removed
|
||||||
|
* setting session save handlers that do not implement `\SessionHandlerInterface` in
|
||||||
|
`NativeSessionStorage::setSaveHandler()` is not supported anymore and throws a
|
||||||
|
`\TypeError`
|
||||||
|
|
||||||
|
3.4.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* implemented PHP 7.0's `SessionUpdateTimestampHandlerInterface` with a new
|
||||||
|
`AbstractSessionHandler` base class and a new `StrictSessionHandler` wrapper
|
||||||
|
* deprecated the `WriteCheckSessionHandler`, `NativeSessionHandler` and `NativeProxy` classes
|
||||||
|
* deprecated setting session save handlers that do not implement `\SessionHandlerInterface` in `NativeSessionStorage::setSaveHandler()`
|
||||||
|
* deprecated using `MongoDbSessionHandler` with the legacy mongo extension; use it with the mongodb/mongodb package and ext-mongodb instead
|
||||||
|
* deprecated `MemcacheSessionHandler`; use `MemcachedSessionHandler` instead
|
||||||
|
|
||||||
|
3.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* the `Request::setTrustedProxies()` method takes a new `$trustedHeaderSet` argument,
|
||||||
|
see https://symfony.com/doc/current/deployment/proxies.html for more info,
|
||||||
|
* deprecated the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()` methods,
|
||||||
|
* added `File\Stream`, to be passed to `BinaryFileResponse` when the size of the served file is unknown,
|
||||||
|
disabling `Range` and `Content-Length` handling, switching to chunked encoding instead
|
||||||
|
* added the `Cookie::fromString()` method that allows to create a cookie from a
|
||||||
|
raw header string
|
||||||
|
|
||||||
|
3.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Added support for creating `JsonResponse` with a string of JSON data
|
||||||
|
|
||||||
|
3.0.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* The precedence of parameters returned from `Request::get()` changed from "GET, PATH, BODY" to "PATH, GET, BODY"
|
||||||
|
|
||||||
|
2.8.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Finding deep items in `ParameterBag::get()` is deprecated since version 2.8 and
|
||||||
|
will be removed in 3.0.
|
||||||
|
|
||||||
|
2.6.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* PdoSessionHandler changes
|
||||||
|
- implemented different session locking strategies to prevent loss of data by concurrent access to the same session
|
||||||
|
- [BC BREAK] save session data in a binary column without base64_encode
|
||||||
|
- [BC BREAK] added lifetime column to the session table which allows to have different lifetimes for each session
|
||||||
|
- implemented lazy connections that are only opened when a session is used by either passing a dsn string
|
||||||
|
explicitly or falling back to session.save_path ini setting
|
||||||
|
- added a createTable method that initializes a correctly defined table depending on the database vendor
|
||||||
|
|
||||||
|
2.5.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added `JsonResponse::setEncodingOptions()` & `JsonResponse::getEncodingOptions()` for easier manipulation
|
||||||
|
of the options used while encoding data to JSON format.
|
||||||
|
|
||||||
|
2.4.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added RequestStack
|
||||||
|
* added Request::getEncodings()
|
||||||
|
* added accessors methods to session handlers
|
||||||
|
|
||||||
|
2.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added support for ranges of IPs in trusted proxies
|
||||||
|
* `UploadedFile::isValid` now returns false if the file was not uploaded via HTTP (in a non-test mode)
|
||||||
|
* Improved error-handling of `\Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler`
|
||||||
|
to ensure the supplied PDO handler throws Exceptions on error (as the class expects). Added related test cases
|
||||||
|
to verify that Exceptions are properly thrown when the PDO queries fail.
|
||||||
|
|
||||||
|
2.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* fixed the Request::create() precedence (URI information always take precedence now)
|
||||||
|
* added Request::getTrustedProxies()
|
||||||
|
* deprecated Request::isProxyTrusted()
|
||||||
|
* [BC BREAK] JsonResponse does not turn a top level empty array to an object anymore, use an ArrayObject to enforce objects
|
||||||
|
* added a IpUtils class to check if an IP belongs to a CIDR
|
||||||
|
* added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method)
|
||||||
|
* disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to
|
||||||
|
enable it, and Request::getHttpMethodParameterOverride() to check if it is supported)
|
||||||
|
* Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3
|
||||||
|
* Deprecated Flashbag::count() and \Countable interface, will be removed in 2.3
|
||||||
|
|
||||||
|
2.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added Request::getSchemeAndHttpHost() and Request::getUserInfo()
|
||||||
|
* added a fluent interface to the Response class
|
||||||
|
* added Request::isProxyTrusted()
|
||||||
|
* added JsonResponse
|
||||||
|
* added a getTargetUrl method to RedirectResponse
|
||||||
|
* added support for streamed responses
|
||||||
|
* made Response::prepare() method the place to enforce HTTP specification
|
||||||
|
* [BC BREAK] moved management of the locale from the Session class to the Request class
|
||||||
|
* added a generic access to the PHP built-in filter mechanism: ParameterBag::filter()
|
||||||
|
* made FileBinaryMimeTypeGuesser command configurable
|
||||||
|
* added Request::getUser() and Request::getPassword()
|
||||||
|
* added support for the PATCH method in Request
|
||||||
|
* removed the ContentTypeMimeTypeGuesser class as it is deprecated and never used on PHP 5.3
|
||||||
|
* added ResponseHeaderBag::makeDisposition() (implements RFC 6266)
|
||||||
|
* made mimetype to extension conversion configurable
|
||||||
|
* [BC BREAK] Moved all session related classes and interfaces into own namespace, as
|
||||||
|
`Symfony\Component\HttpFoundation\Session` and renamed classes accordingly.
|
||||||
|
Session handlers are located in the subnamespace `Symfony\Component\HttpFoundation\Session\Handler`.
|
||||||
|
* SessionHandlers must implement `\SessionHandlerInterface` or extend from the
|
||||||
|
`Symfony\Component\HttpFoundation\Storage\Handler\NativeSessionHandler` base class.
|
||||||
|
* Added internal storage driver proxy mechanism for forward compatibility with
|
||||||
|
PHP 5.4 `\SessionHandler` class.
|
||||||
|
* Added session handlers for custom Memcache, Memcached and Null session save handlers.
|
||||||
|
* [BC BREAK] Removed `NativeSessionStorage` and replaced with `NativeFileSessionHandler`.
|
||||||
|
* [BC BREAK] `SessionStorageInterface` methods removed: `write()`, `read()` and
|
||||||
|
`remove()`. Added `getBag()`, `registerBag()`. The `NativeSessionStorage` class
|
||||||
|
is a mediator for the session storage internals including the session handlers
|
||||||
|
which do the real work of participating in the internal PHP session workflow.
|
||||||
|
* [BC BREAK] Introduced mock implementations of `SessionStorage` to enable unit
|
||||||
|
and functional testing without starting real PHP sessions. Removed
|
||||||
|
`ArraySessionStorage`, and replaced with `MockArraySessionStorage` for unit
|
||||||
|
tests; removed `FilesystemSessionStorage`, and replaced with`MockFileSessionStorage`
|
||||||
|
for functional tests. These do not interact with global session ini
|
||||||
|
configuration values, session functions or `$_SESSION` superglobal. This means
|
||||||
|
they can be configured directly allowing multiple instances to work without
|
||||||
|
conflicting in the same PHP process.
|
||||||
|
* [BC BREAK] Removed the `close()` method from the `Session` class, as this is
|
||||||
|
now redundant.
|
||||||
|
* Deprecated the following methods from the Session class: `setFlash()`, `setFlashes()`
|
||||||
|
`getFlash()`, `hasFlash()`, and `removeFlash()`. Use `getFlashBag()` instead
|
||||||
|
which returns a `FlashBagInterface`.
|
||||||
|
* `Session->clear()` now only clears session attributes as before it cleared
|
||||||
|
flash messages and attributes. `Session->getFlashBag()->all()` clears flashes now.
|
||||||
|
* Session data is now managed by `SessionBagInterface` to better encapsulate
|
||||||
|
session data.
|
||||||
|
* Refactored session attribute and flash messages system to their own
|
||||||
|
`SessionBagInterface` implementations.
|
||||||
|
* Added `FlashBag`. Flashes expire when retrieved by `get()` or `all()`. This
|
||||||
|
implementation is ESI compatible.
|
||||||
|
* Added `AutoExpireFlashBag` (default) to replicate Symfony 2.0.x auto expire
|
||||||
|
behavior of messages auto expiring after one page page load. Messages must
|
||||||
|
be retrieved by `get()` or `all()`.
|
||||||
|
* Added `Symfony\Component\HttpFoundation\Attribute\AttributeBag` to replicate
|
||||||
|
attributes storage behavior from 2.0.x (default).
|
||||||
|
* Added `Symfony\Component\HttpFoundation\Attribute\NamespacedAttributeBag` for
|
||||||
|
namespace session attributes.
|
||||||
|
* Flash API can stores messages in an array so there may be multiple messages
|
||||||
|
per flash type. The old `Session` class API remains without BC break as it
|
||||||
|
will allow single messages as before.
|
||||||
|
* Added basic session meta-data to the session to record session create time,
|
||||||
|
last updated time, and the lifetime of the session cookie that was provided
|
||||||
|
to the client.
|
||||||
|
* Request::getClientIp() method doesn't take a parameter anymore but bases
|
||||||
|
itself on the trustProxy parameter.
|
||||||
|
* Added isMethod() to Request object.
|
||||||
|
* [BC BREAK] The methods `getPathInfo()`, `getBaseUrl()` and `getBasePath()` of
|
||||||
|
a `Request` now all return a raw value (vs a urldecoded value before). Any call
|
||||||
|
to one of these methods must be checked and wrapped in a `rawurldecode()` if
|
||||||
|
needed.
|
||||||
38
vendor/symfony/http-foundation/ChainRequestMatcher.php
vendored
Normal file
38
vendor/symfony/http-foundation/ChainRequestMatcher.php
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ChainRequestMatcher verifies that all checks match against a Request instance.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class ChainRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param iterable<RequestMatcherInterface> $matchers
|
||||||
|
*/
|
||||||
|
public function __construct(private iterable $matchers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
foreach ($this->matchers as $matcher) {
|
||||||
|
if (!$matcher->matches($request)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
405
vendor/symfony/http-foundation/Cookie.php
vendored
Normal file
405
vendor/symfony/http-foundation/Cookie.php
vendored
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a cookie.
|
||||||
|
*
|
||||||
|
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||||
|
*/
|
||||||
|
class Cookie
|
||||||
|
{
|
||||||
|
public const SAMESITE_NONE = 'none';
|
||||||
|
public const SAMESITE_LAX = 'lax';
|
||||||
|
public const SAMESITE_STRICT = 'strict';
|
||||||
|
|
||||||
|
protected int $expire;
|
||||||
|
protected string $path;
|
||||||
|
|
||||||
|
private ?string $sameSite = null;
|
||||||
|
private bool $secureDefault = false;
|
||||||
|
|
||||||
|
private const RESERVED_CHARS_LIST = "=,; \t\r\n\v\f";
|
||||||
|
private const RESERVED_CHARS_FROM = ['=', ',', ';', ' ', "\t", "\r", "\n", "\v", "\f"];
|
||||||
|
private const RESERVED_CHARS_TO = ['%3D', '%2C', '%3B', '%20', '%09', '%0D', '%0A', '%0B', '%0C'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates cookie from raw header string.
|
||||||
|
*/
|
||||||
|
public static function fromString(string $cookie, bool $decode = false): static
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'expires' => 0,
|
||||||
|
'path' => '/',
|
||||||
|
'domain' => null,
|
||||||
|
'secure' => false,
|
||||||
|
'httponly' => false,
|
||||||
|
'raw' => !$decode,
|
||||||
|
'samesite' => null,
|
||||||
|
'partitioned' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$parts = HeaderUtils::split($cookie, ';=');
|
||||||
|
$part = array_shift($parts);
|
||||||
|
|
||||||
|
$name = $decode ? urldecode($part[0]) : $part[0];
|
||||||
|
$value = isset($part[1]) ? ($decode ? urldecode($part[1]) : $part[1]) : null;
|
||||||
|
|
||||||
|
$data = HeaderUtils::combine($parts) + $data;
|
||||||
|
$data['expires'] = self::expiresTimestamp($data['expires']);
|
||||||
|
|
||||||
|
if (isset($data['max-age']) && ($data['max-age'] > 0 || $data['expires'] > time())) {
|
||||||
|
$data['expires'] = time() + (int) $data['max-age'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite'], $data['partitioned']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see self::__construct
|
||||||
|
*
|
||||||
|
* @param self::SAMESITE_*|''|null $sameSite
|
||||||
|
*/
|
||||||
|
public static function create(string $name, ?string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', ?string $domain = null, ?bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX, bool $partitioned = false): self
|
||||||
|
{
|
||||||
|
return new self($name, $value, $expire, $path, $domain, $secure, $httpOnly, $raw, $sameSite, $partitioned);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name The name of the cookie
|
||||||
|
* @param string|null $value The value of the cookie
|
||||||
|
* @param int|string|\DateTimeInterface $expire The time the cookie expires
|
||||||
|
* @param string|null $path The path on the server in which the cookie will be available on
|
||||||
|
* @param string|null $domain The domain that the cookie is available to
|
||||||
|
* @param bool|null $secure Whether the client should send back the cookie only over HTTPS or null to auto-enable this when the request is already using HTTPS
|
||||||
|
* @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
|
||||||
|
* @param bool $raw Whether the cookie value should be sent with no url encoding
|
||||||
|
* @param self::SAMESITE_*|''|null $sameSite Whether the cookie will be available for cross-site requests
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
protected string $name,
|
||||||
|
protected ?string $value = null,
|
||||||
|
int|string|\DateTimeInterface $expire = 0,
|
||||||
|
?string $path = '/',
|
||||||
|
protected ?string $domain = null,
|
||||||
|
protected ?bool $secure = null,
|
||||||
|
protected bool $httpOnly = true,
|
||||||
|
private bool $raw = false,
|
||||||
|
?string $sameSite = self::SAMESITE_LAX,
|
||||||
|
private bool $partitioned = false,
|
||||||
|
) {
|
||||||
|
// from PHP source code
|
||||||
|
if ($raw && false !== strpbrk($name, self::RESERVED_CHARS_LIST)) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('The cookie name "%s" contains invalid characters.', $name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$name) {
|
||||||
|
throw new \InvalidArgumentException('The cookie name cannot be empty.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->expire = self::expiresTimestamp($expire);
|
||||||
|
$this->path = $path ?: '/';
|
||||||
|
$this->sameSite = $this->withSameSite($sameSite)->sameSite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy with a new value.
|
||||||
|
*/
|
||||||
|
public function withValue(?string $value): static
|
||||||
|
{
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->value = $value;
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy with a new domain that the cookie is available to.
|
||||||
|
*/
|
||||||
|
public function withDomain(?string $domain): static
|
||||||
|
{
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->domain = $domain;
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy with a new time the cookie expires.
|
||||||
|
*/
|
||||||
|
public function withExpires(int|string|\DateTimeInterface $expire = 0): static
|
||||||
|
{
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->expire = self::expiresTimestamp($expire);
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts expires formats to a unix timestamp.
|
||||||
|
*/
|
||||||
|
private static function expiresTimestamp(int|string|\DateTimeInterface $expire = 0): int
|
||||||
|
{
|
||||||
|
// convert expiration time to a Unix timestamp
|
||||||
|
if ($expire instanceof \DateTimeInterface) {
|
||||||
|
$expire = $expire->format('U');
|
||||||
|
} elseif (!is_numeric($expire)) {
|
||||||
|
$expire = strtotime($expire);
|
||||||
|
|
||||||
|
if (false === $expire) {
|
||||||
|
throw new \InvalidArgumentException('The cookie expiration time is not valid.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 < $expire ? (int) $expire : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy with a new path on the server in which the cookie will be available on.
|
||||||
|
*/
|
||||||
|
public function withPath(string $path): static
|
||||||
|
{
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->path = '' === $path ? '/' : $path;
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy that only be transmitted over a secure HTTPS connection from the client.
|
||||||
|
*/
|
||||||
|
public function withSecure(bool $secure = true): static
|
||||||
|
{
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->secure = $secure;
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy that be accessible only through the HTTP protocol.
|
||||||
|
*/
|
||||||
|
public function withHttpOnly(bool $httpOnly = true): static
|
||||||
|
{
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->httpOnly = $httpOnly;
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy that uses no url encoding.
|
||||||
|
*/
|
||||||
|
public function withRaw(bool $raw = true): static
|
||||||
|
{
|
||||||
|
if ($raw && false !== strpbrk($this->name, self::RESERVED_CHARS_LIST)) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('The cookie name "%s" contains invalid characters.', $this->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->raw = $raw;
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy with SameSite attribute.
|
||||||
|
*
|
||||||
|
* @param self::SAMESITE_*|''|null $sameSite
|
||||||
|
*/
|
||||||
|
public function withSameSite(?string $sameSite): static
|
||||||
|
{
|
||||||
|
if ('' === $sameSite) {
|
||||||
|
$sameSite = null;
|
||||||
|
} elseif (null !== $sameSite) {
|
||||||
|
$sameSite = strtolower($sameSite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\in_array($sameSite, [self::SAMESITE_LAX, self::SAMESITE_STRICT, self::SAMESITE_NONE, null], true)) {
|
||||||
|
throw new \InvalidArgumentException('The "sameSite" parameter value is not valid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->sameSite = $sameSite;
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cookie copy that is tied to the top-level site in cross-site context.
|
||||||
|
*/
|
||||||
|
public function withPartitioned(bool $partitioned = true): static
|
||||||
|
{
|
||||||
|
$cookie = clone $this;
|
||||||
|
$cookie->partitioned = $partitioned;
|
||||||
|
|
||||||
|
return $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cookie as a string.
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
if ($this->isRaw()) {
|
||||||
|
$str = $this->getName();
|
||||||
|
} else {
|
||||||
|
$str = str_replace(self::RESERVED_CHARS_FROM, self::RESERVED_CHARS_TO, $this->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
$str .= '=';
|
||||||
|
|
||||||
|
if ('' === (string) $this->getValue()) {
|
||||||
|
$str .= 'deleted; expires='.gmdate('D, d M Y H:i:s T', time() - 31536001).'; Max-Age=0';
|
||||||
|
} else {
|
||||||
|
$str .= $this->isRaw() ? $this->getValue() : rawurlencode($this->getValue());
|
||||||
|
|
||||||
|
if (0 !== $this->getExpiresTime()) {
|
||||||
|
$str .= '; expires='.gmdate('D, d M Y H:i:s T', $this->getExpiresTime()).'; Max-Age='.$this->getMaxAge();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getPath()) {
|
||||||
|
$str .= '; path='.$this->getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getDomain()) {
|
||||||
|
$str .= '; domain='.$this->getDomain();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isSecure()) {
|
||||||
|
$str .= '; secure';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isHttpOnly()) {
|
||||||
|
$str .= '; httponly';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->getSameSite()) {
|
||||||
|
$str .= '; samesite='.$this->getSameSite();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isPartitioned()) {
|
||||||
|
$str .= '; partitioned';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the cookie.
|
||||||
|
*/
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the cookie.
|
||||||
|
*/
|
||||||
|
public function getValue(): ?string
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the domain that the cookie is available to.
|
||||||
|
*/
|
||||||
|
public function getDomain(): ?string
|
||||||
|
{
|
||||||
|
return $this->domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the time the cookie expires.
|
||||||
|
*/
|
||||||
|
public function getExpiresTime(): int
|
||||||
|
{
|
||||||
|
return $this->expire;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the max-age attribute.
|
||||||
|
*/
|
||||||
|
public function getMaxAge(): int
|
||||||
|
{
|
||||||
|
$maxAge = $this->expire - time();
|
||||||
|
|
||||||
|
return max(0, $maxAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the path on the server in which the cookie will be available on.
|
||||||
|
*/
|
||||||
|
public function getPath(): string
|
||||||
|
{
|
||||||
|
return $this->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client.
|
||||||
|
*/
|
||||||
|
public function isSecure(): bool
|
||||||
|
{
|
||||||
|
return $this->secure ?? $this->secureDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the cookie will be made accessible only through the HTTP protocol.
|
||||||
|
*/
|
||||||
|
public function isHttpOnly(): bool
|
||||||
|
{
|
||||||
|
return $this->httpOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this cookie is about to be cleared.
|
||||||
|
*/
|
||||||
|
public function isCleared(): bool
|
||||||
|
{
|
||||||
|
return 0 !== $this->expire && $this->expire < time();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the cookie value should be sent with no url encoding.
|
||||||
|
*/
|
||||||
|
public function isRaw(): bool
|
||||||
|
{
|
||||||
|
return $this->raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the cookie should be tied to the top-level site in cross-site context.
|
||||||
|
*/
|
||||||
|
public function isPartitioned(): bool
|
||||||
|
{
|
||||||
|
return $this->partitioned;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self::SAMESITE_*|null
|
||||||
|
*/
|
||||||
|
public function getSameSite(): ?string
|
||||||
|
{
|
||||||
|
return $this->sameSite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $default The default value of the "secure" flag when it is set to null
|
||||||
|
*/
|
||||||
|
public function setSecureDefault(bool $default): void
|
||||||
|
{
|
||||||
|
$this->secureDefault = $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
110
vendor/symfony/http-foundation/EventStreamResponse.php
vendored
Normal file
110
vendor/symfony/http-foundation/EventStreamResponse.php
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a streaming HTTP response for sending server events
|
||||||
|
* as part of the Server-Sent Events (SSE) streaming technique.
|
||||||
|
*
|
||||||
|
* To broadcast events to multiple users at once, for long-running
|
||||||
|
* connections and for high-traffic websites, prefer using the Mercure
|
||||||
|
* Symfony Component, which relies on Software designed for these use
|
||||||
|
* cases: https://symfony.com/doc/current/mercure.html
|
||||||
|
*
|
||||||
|
* @see ServerEvent
|
||||||
|
*
|
||||||
|
* @author Yonel Ceruto <open@yceruto.dev>
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* return new EventStreamResponse(function () {
|
||||||
|
* yield new ServerEvent(time());
|
||||||
|
*
|
||||||
|
* sleep(1);
|
||||||
|
*
|
||||||
|
* yield new ServerEvent(time());
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
class EventStreamResponse extends StreamedResponse
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param int|null $retry The number of milliseconds the client should wait
|
||||||
|
* before reconnecting in case of network failure
|
||||||
|
*/
|
||||||
|
public function __construct(?callable $callback = null, int $status = 200, array $headers = [], private ?int $retry = null)
|
||||||
|
{
|
||||||
|
$headers += [
|
||||||
|
'Connection' => 'keep-alive',
|
||||||
|
'Content-Type' => 'text/event-stream',
|
||||||
|
'Cache-Control' => 'private, no-cache, no-store, must-revalidate, max-age=0',
|
||||||
|
'X-Accel-Buffering' => 'no',
|
||||||
|
'Pragma' => 'no-cache',
|
||||||
|
'Expires' => '0',
|
||||||
|
];
|
||||||
|
|
||||||
|
parent::__construct($callback, $status, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCallback(callable $callback): static
|
||||||
|
{
|
||||||
|
if ($this->callback) {
|
||||||
|
return parent::setCallback($callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->callback = function () use ($callback) {
|
||||||
|
if (is_iterable($events = $callback($this))) {
|
||||||
|
foreach ($events as $event) {
|
||||||
|
$this->sendEvent($event);
|
||||||
|
|
||||||
|
if (connection_aborted()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a server event to the client.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function sendEvent(ServerEvent $event): static
|
||||||
|
{
|
||||||
|
if ($this->retry > 0 && !$event->getRetry()) {
|
||||||
|
$event->setRetry($this->retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($event as $part) {
|
||||||
|
echo $part;
|
||||||
|
|
||||||
|
if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
|
||||||
|
static::closeOutputBuffers(0, true);
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRetry(): ?int
|
||||||
|
{
|
||||||
|
return $this->retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRetry(int $retry): void
|
||||||
|
{
|
||||||
|
$this->retry = $retry;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
vendor/symfony/http-foundation/Exception/BadRequestException.php
vendored
Normal file
19
vendor/symfony/http-foundation/Exception/BadRequestException.php
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when a user sends a malformed request.
|
||||||
|
*/
|
||||||
|
class BadRequestException extends UnexpectedValueException implements RequestExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php
vendored
Normal file
21
vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HTTP request contains headers with conflicting information.
|
||||||
|
*
|
||||||
|
* @author Magnus Nordlander <magnus@fervo.se>
|
||||||
|
*/
|
||||||
|
class ConflictingHeadersException extends UnexpectedValueException implements RequestExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
16
vendor/symfony/http-foundation/Exception/ExceptionInterface.php
vendored
Normal file
16
vendor/symfony/http-foundation/Exception/ExceptionInterface.php
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
interface ExceptionInterface extends \Throwable
|
||||||
|
{
|
||||||
|
}
|
||||||
29
vendor/symfony/http-foundation/Exception/ExpiredSignedUriException.php
vendored
Normal file
29
vendor/symfony/http-foundation/Exception/ExpiredSignedUriException.php
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kevin Bond <kevinbond@gmail.com>
|
||||||
|
*/
|
||||||
|
#[WithHttpStatus(403)]
|
||||||
|
final class ExpiredSignedUriException extends SignedUriException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct('The URI has expired.');
|
||||||
|
}
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/Exception/JsonException.php
vendored
Normal file
21
vendor/symfony/http-foundation/Exception/JsonException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown by Request::toArray() when the content cannot be JSON-decoded.
|
||||||
|
*
|
||||||
|
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||||
|
*/
|
||||||
|
final class JsonException extends UnexpectedValueException implements RequestExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
19
vendor/symfony/http-foundation/Exception/LogicException.php
vendored
Normal file
19
vendor/symfony/http-foundation/Exception/LogicException.php
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base LogicException for Http Foundation component.
|
||||||
|
*/
|
||||||
|
class LogicException extends \LogicException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/Exception/RequestExceptionInterface.php
vendored
Normal file
21
vendor/symfony/http-foundation/Exception/RequestExceptionInterface.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for Request exceptions.
|
||||||
|
*
|
||||||
|
* Exceptions implementing this interface should trigger an HTTP 400 response in the application code.
|
||||||
|
*/
|
||||||
|
interface RequestExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
27
vendor/symfony/http-foundation/Exception/SessionNotFoundException.php
vendored
Normal file
27
vendor/symfony/http-foundation/Exception/SessionNotFoundException.php
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when a session does not exist. This happens in the following cases:
|
||||||
|
* - the session is not enabled
|
||||||
|
* - attempt to read a session outside a request context (ie. cli script).
|
||||||
|
*
|
||||||
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
|
*/
|
||||||
|
class SessionNotFoundException extends \LogicException implements RequestExceptionInterface
|
||||||
|
{
|
||||||
|
public function __construct(string $message = 'There is currently no session available.', int $code = 0, ?\Throwable $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
vendor/symfony/http-foundation/Exception/SignedUriException.php
vendored
Normal file
22
vendor/symfony/http-foundation/Exception/SignedUriException.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kevin Bond <kevinbond@gmail.com>
|
||||||
|
*/
|
||||||
|
#[WithHttpStatus(404)]
|
||||||
|
abstract class SignedUriException extends \RuntimeException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
20
vendor/symfony/http-foundation/Exception/SuspiciousOperationException.php
vendored
Normal file
20
vendor/symfony/http-foundation/Exception/SuspiciousOperationException.php
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when a user has performed an operation that should be considered
|
||||||
|
* suspicious from a security perspective.
|
||||||
|
*/
|
||||||
|
class SuspiciousOperationException extends UnexpectedValueException implements RequestExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
16
vendor/symfony/http-foundation/Exception/UnexpectedValueException.php
vendored
Normal file
16
vendor/symfony/http-foundation/Exception/UnexpectedValueException.php
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
class UnexpectedValueException extends \UnexpectedValueException
|
||||||
|
{
|
||||||
|
}
|
||||||
26
vendor/symfony/http-foundation/Exception/UnsignedUriException.php
vendored
Normal file
26
vendor/symfony/http-foundation/Exception/UnsignedUriException.php
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kevin Bond <kevinbond@gmail.com>
|
||||||
|
*/
|
||||||
|
final class UnsignedUriException extends SignedUriException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct('The URI is not signed.');
|
||||||
|
}
|
||||||
|
}
|
||||||
26
vendor/symfony/http-foundation/Exception/UnverifiedSignedUriException.php
vendored
Normal file
26
vendor/symfony/http-foundation/Exception/UnverifiedSignedUriException.php
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kevin Bond <kevinbond@gmail.com>
|
||||||
|
*/
|
||||||
|
final class UnverifiedSignedUriException extends SignedUriException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct('The URI signature is invalid.');
|
||||||
|
}
|
||||||
|
}
|
||||||
25
vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php
vendored
Normal file
25
vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when the access on a file was denied.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class AccessDeniedException extends FileException
|
||||||
|
{
|
||||||
|
public function __construct(string $path)
|
||||||
|
{
|
||||||
|
parent::__construct(\sprintf('The file %s could not be accessed', $path));
|
||||||
|
}
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an UPLOAD_ERR_CANT_WRITE error occurred with UploadedFile.
|
||||||
|
*
|
||||||
|
* @author Florent Mata <florentmata@gmail.com>
|
||||||
|
*/
|
||||||
|
class CannotWriteFileException extends FileException
|
||||||
|
{
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an UPLOAD_ERR_EXTENSION error occurred with UploadedFile.
|
||||||
|
*
|
||||||
|
* @author Florent Mata <florentmata@gmail.com>
|
||||||
|
*/
|
||||||
|
class ExtensionFileException extends FileException
|
||||||
|
{
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/FileException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/FileException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an error occurred in the component File.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class FileException extends \RuntimeException
|
||||||
|
{
|
||||||
|
}
|
||||||
25
vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php
vendored
Normal file
25
vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when a file was not found.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class FileNotFoundException extends FileException
|
||||||
|
{
|
||||||
|
public function __construct(string $path)
|
||||||
|
{
|
||||||
|
parent::__construct(\sprintf('The file "%s" does not exist', $path));
|
||||||
|
}
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an UPLOAD_ERR_FORM_SIZE error occurred with UploadedFile.
|
||||||
|
*
|
||||||
|
* @author Florent Mata <florentmata@gmail.com>
|
||||||
|
*/
|
||||||
|
class FormSizeFileException extends FileException
|
||||||
|
{
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an UPLOAD_ERR_INI_SIZE error occurred with UploadedFile.
|
||||||
|
*
|
||||||
|
* @author Florent Mata <florentmata@gmail.com>
|
||||||
|
*/
|
||||||
|
class IniSizeFileException extends FileException
|
||||||
|
{
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/NoFileException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/NoFileException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an UPLOAD_ERR_NO_FILE error occurred with UploadedFile.
|
||||||
|
*
|
||||||
|
* @author Florent Mata <florentmata@gmail.com>
|
||||||
|
*/
|
||||||
|
class NoFileException extends FileException
|
||||||
|
{
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an UPLOAD_ERR_NO_TMP_DIR error occurred with UploadedFile.
|
||||||
|
*
|
||||||
|
* @author Florent Mata <florentmata@gmail.com>
|
||||||
|
*/
|
||||||
|
class NoTmpDirFileException extends FileException
|
||||||
|
{
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/PartialFileException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/PartialFileException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an UPLOAD_ERR_PARTIAL error occurred with UploadedFile.
|
||||||
|
*
|
||||||
|
* @author Florent Mata <florentmata@gmail.com>
|
||||||
|
*/
|
||||||
|
class PartialFileException extends FileException
|
||||||
|
{
|
||||||
|
}
|
||||||
20
vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php
vendored
Normal file
20
vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
class UnexpectedTypeException extends FileException
|
||||||
|
{
|
||||||
|
public function __construct(mixed $value, string $expectedType)
|
||||||
|
{
|
||||||
|
parent::__construct(\sprintf('Expected argument of type %s, %s given', $expectedType, get_debug_type($value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
21
vendor/symfony/http-foundation/File/Exception/UploadException.php
vendored
Normal file
21
vendor/symfony/http-foundation/File/Exception/UploadException.php
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an error occurred during file upload.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class UploadException extends FileException
|
||||||
|
{
|
||||||
|
}
|
||||||
141
vendor/symfony/http-foundation/File/File.php
vendored
Normal file
141
vendor/symfony/http-foundation/File/File.php
vendored
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
|
||||||
|
use Symfony\Component\Mime\MimeTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A file in the file system.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class File extends \SplFileInfo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new file from the given path.
|
||||||
|
*
|
||||||
|
* @param string $path The path to the file
|
||||||
|
* @param bool $checkPath Whether to check the path or not
|
||||||
|
*
|
||||||
|
* @throws FileNotFoundException If the given path is not a file
|
||||||
|
*/
|
||||||
|
public function __construct(string $path, bool $checkPath = true)
|
||||||
|
{
|
||||||
|
if ($checkPath && !is_file($path)) {
|
||||||
|
throw new FileNotFoundException($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the extension based on the mime type.
|
||||||
|
*
|
||||||
|
* If the mime type is unknown, returns null.
|
||||||
|
*
|
||||||
|
* This method uses the mime type as guessed by getMimeType()
|
||||||
|
* to guess the file extension.
|
||||||
|
*
|
||||||
|
* @see MimeTypes
|
||||||
|
* @see getMimeType()
|
||||||
|
*/
|
||||||
|
public function guessExtension(): ?string
|
||||||
|
{
|
||||||
|
if (!class_exists(MimeTypes::class)) {
|
||||||
|
throw new \LogicException('You cannot guess the extension as the Mime component is not installed. Try running "composer require symfony/mime".');
|
||||||
|
}
|
||||||
|
|
||||||
|
return MimeTypes::getDefault()->getExtensions($this->getMimeType())[0] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mime type of the file.
|
||||||
|
*
|
||||||
|
* The mime type is guessed using a MimeTypeGuesserInterface instance,
|
||||||
|
* which uses finfo_file() then the "file" system binary,
|
||||||
|
* depending on which of those are available.
|
||||||
|
*
|
||||||
|
* @see MimeTypes
|
||||||
|
*/
|
||||||
|
public function getMimeType(): ?string
|
||||||
|
{
|
||||||
|
if (!class_exists(MimeTypes::class)) {
|
||||||
|
throw new \LogicException('You cannot guess the mime type as the Mime component is not installed. Try running "composer require symfony/mime".');
|
||||||
|
}
|
||||||
|
|
||||||
|
return MimeTypes::getDefault()->guessMimeType($this->getPathname());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the file to a new location.
|
||||||
|
*
|
||||||
|
* @throws FileException if the target file could not be created
|
||||||
|
*/
|
||||||
|
public function move(string $directory, ?string $name = null): self
|
||||||
|
{
|
||||||
|
$target = $this->getTargetFile($directory, $name);
|
||||||
|
|
||||||
|
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||||
|
try {
|
||||||
|
$renamed = rename($this->getPathname(), $target);
|
||||||
|
} finally {
|
||||||
|
restore_error_handler();
|
||||||
|
}
|
||||||
|
if (!$renamed) {
|
||||||
|
throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@chmod($target, 0o666 & ~umask());
|
||||||
|
|
||||||
|
return $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent(): string
|
||||||
|
{
|
||||||
|
$content = file_get_contents($this->getPathname());
|
||||||
|
|
||||||
|
if (false === $content) {
|
||||||
|
throw new FileException(\sprintf('Could not get the content of the file "%s".', $this->getPathname()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTargetFile(string $directory, ?string $name = null): self
|
||||||
|
{
|
||||||
|
if (!is_dir($directory) && !@mkdir($directory, 0o777, true) && !is_dir($directory)) {
|
||||||
|
if (is_file($directory)) {
|
||||||
|
throw new FileException(\sprintf('Unable to create the "%s" directory: a similarly-named file exists.', $directory));
|
||||||
|
}
|
||||||
|
throw new FileException(\sprintf('Unable to create the "%s" directory.', $directory));
|
||||||
|
} elseif (!is_writable($directory)) {
|
||||||
|
throw new FileException(\sprintf('Unable to write in the "%s" directory.', $directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
$target = rtrim($directory, '/\\').\DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : $this->getName($name));
|
||||||
|
|
||||||
|
return new self($target, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns locale independent base name of the given path.
|
||||||
|
*/
|
||||||
|
protected function getName(string $name): string
|
||||||
|
{
|
||||||
|
$originalName = str_replace('\\', '/', $name);
|
||||||
|
$pos = strrpos($originalName, '/');
|
||||||
|
|
||||||
|
return false === $pos ? $originalName : substr($originalName, $pos + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
vendor/symfony/http-foundation/File/Stream.php
vendored
Normal file
25
vendor/symfony/http-foundation/File/Stream.php
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A PHP stream of unknown size.
|
||||||
|
*
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
class Stream extends File
|
||||||
|
{
|
||||||
|
public function getSize(): int|false
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
289
vendor/symfony/http-foundation/File/UploadedFile.php
vendored
Normal file
289
vendor/symfony/http-foundation/File/UploadedFile.php
vendored
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\File;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\NoFileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\PartialFileException;
|
||||||
|
use Symfony\Component\Mime\MimeTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A file uploaded through a form.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
* @author Florian Eckerstorfer <florian@eckerstorfer.org>
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class UploadedFile extends File
|
||||||
|
{
|
||||||
|
private string $originalName;
|
||||||
|
private string $mimeType;
|
||||||
|
private int $error;
|
||||||
|
private string $originalPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts the information of the uploaded file as provided by the PHP global $_FILES.
|
||||||
|
*
|
||||||
|
* The file object is only created when the uploaded file is valid (i.e. when the
|
||||||
|
* isValid() method returns true). Otherwise the only methods that could be called
|
||||||
|
* on an UploadedFile instance are:
|
||||||
|
*
|
||||||
|
* * getClientOriginalName,
|
||||||
|
* * getClientMimeType,
|
||||||
|
* * isValid,
|
||||||
|
* * getError.
|
||||||
|
*
|
||||||
|
* Calling any other method on an non-valid instance will cause an unpredictable result.
|
||||||
|
*
|
||||||
|
* @param string $path The full temporary path to the file
|
||||||
|
* @param string $originalName The original file name of the uploaded file
|
||||||
|
* @param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream
|
||||||
|
* @param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK
|
||||||
|
* @param bool $test Whether the test mode is active
|
||||||
|
* Local files are used in test mode hence the code should not enforce HTTP uploads
|
||||||
|
*
|
||||||
|
* @throws FileException If file_uploads is disabled
|
||||||
|
* @throws FileNotFoundException If the file does not exist
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
string $path,
|
||||||
|
string $originalName,
|
||||||
|
?string $mimeType = null,
|
||||||
|
?int $error = null,
|
||||||
|
private bool $test = false,
|
||||||
|
) {
|
||||||
|
$this->originalName = $this->getName($originalName);
|
||||||
|
$this->originalPath = strtr($originalName, '\\', '/');
|
||||||
|
$this->mimeType = $mimeType ?: 'application/octet-stream';
|
||||||
|
$this->error = $error ?: \UPLOAD_ERR_OK;
|
||||||
|
|
||||||
|
parent::__construct($path, \UPLOAD_ERR_OK === $this->error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the original file name.
|
||||||
|
*
|
||||||
|
* It is extracted from the request from which the file has been uploaded.
|
||||||
|
* This should not be considered as a safe value to use for a file name on your servers.
|
||||||
|
*/
|
||||||
|
public function getClientOriginalName(): string
|
||||||
|
{
|
||||||
|
return $this->originalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the original file extension.
|
||||||
|
*
|
||||||
|
* It is extracted from the original file name that was uploaded.
|
||||||
|
* This should not be considered as a safe value to use for a file name on your servers.
|
||||||
|
*/
|
||||||
|
public function getClientOriginalExtension(): string
|
||||||
|
{
|
||||||
|
return pathinfo($this->originalName, \PATHINFO_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the original file full path.
|
||||||
|
*
|
||||||
|
* It is extracted from the request from which the file has been uploaded.
|
||||||
|
* This should not be considered as a safe value to use for a file name/path on your servers.
|
||||||
|
*
|
||||||
|
* If this file was uploaded with the "webkitdirectory" upload directive, this will contain
|
||||||
|
* the path of the file relative to the uploaded root directory. Otherwise this will be identical
|
||||||
|
* to getClientOriginalName().
|
||||||
|
*/
|
||||||
|
public function getClientOriginalPath(): string
|
||||||
|
{
|
||||||
|
return $this->originalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the file mime type.
|
||||||
|
*
|
||||||
|
* The client mime type is extracted from the request from which the file
|
||||||
|
* was uploaded, so it should not be considered as a safe value.
|
||||||
|
*
|
||||||
|
* For a trusted mime type, use getMimeType() instead (which guesses the mime
|
||||||
|
* type based on the file content).
|
||||||
|
*
|
||||||
|
* @see getMimeType()
|
||||||
|
*/
|
||||||
|
public function getClientMimeType(): string
|
||||||
|
{
|
||||||
|
return $this->mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the extension based on the client mime type.
|
||||||
|
*
|
||||||
|
* If the mime type is unknown, returns null.
|
||||||
|
*
|
||||||
|
* This method uses the mime type as guessed by getClientMimeType()
|
||||||
|
* to guess the file extension. As such, the extension returned
|
||||||
|
* by this method cannot be trusted.
|
||||||
|
*
|
||||||
|
* For a trusted extension, use guessExtension() instead (which guesses
|
||||||
|
* the extension based on the guessed mime type for the file).
|
||||||
|
*
|
||||||
|
* @see guessExtension()
|
||||||
|
* @see getClientMimeType()
|
||||||
|
*/
|
||||||
|
public function guessClientExtension(): ?string
|
||||||
|
{
|
||||||
|
if (!class_exists(MimeTypes::class)) {
|
||||||
|
throw new \LogicException('You cannot guess the extension as the Mime component is not installed. Try running "composer require symfony/mime".');
|
||||||
|
}
|
||||||
|
|
||||||
|
return MimeTypes::getDefault()->getExtensions($this->getClientMimeType())[0] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the upload error.
|
||||||
|
*
|
||||||
|
* If the upload was successful, the constant UPLOAD_ERR_OK is returned.
|
||||||
|
* Otherwise one of the other UPLOAD_ERR_XXX constants is returned.
|
||||||
|
*/
|
||||||
|
public function getError(): int
|
||||||
|
{
|
||||||
|
return $this->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the file has been uploaded with HTTP and no error occurred.
|
||||||
|
*/
|
||||||
|
public function isValid(): bool
|
||||||
|
{
|
||||||
|
$isOk = \UPLOAD_ERR_OK === $this->error;
|
||||||
|
|
||||||
|
return $this->test ? $isOk : $isOk && is_uploaded_file($this->getPathname());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the file to a new location.
|
||||||
|
*
|
||||||
|
* @throws FileException if, for any reason, the file could not have been moved
|
||||||
|
*/
|
||||||
|
public function move(string $directory, ?string $name = null): File
|
||||||
|
{
|
||||||
|
if ($this->isValid()) {
|
||||||
|
if ($this->test) {
|
||||||
|
return parent::move($directory, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$target = $this->getTargetFile($directory, $name);
|
||||||
|
|
||||||
|
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||||
|
try {
|
||||||
|
$moved = move_uploaded_file($this->getPathname(), $target);
|
||||||
|
} finally {
|
||||||
|
restore_error_handler();
|
||||||
|
}
|
||||||
|
if (!$moved) {
|
||||||
|
throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@chmod($target, 0o666 & ~umask());
|
||||||
|
|
||||||
|
return $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($this->error) {
|
||||||
|
case \UPLOAD_ERR_INI_SIZE:
|
||||||
|
throw new IniSizeFileException($this->getErrorMessage());
|
||||||
|
case \UPLOAD_ERR_FORM_SIZE:
|
||||||
|
throw new FormSizeFileException($this->getErrorMessage());
|
||||||
|
case \UPLOAD_ERR_PARTIAL:
|
||||||
|
throw new PartialFileException($this->getErrorMessage());
|
||||||
|
case \UPLOAD_ERR_NO_FILE:
|
||||||
|
throw new NoFileException($this->getErrorMessage());
|
||||||
|
case \UPLOAD_ERR_CANT_WRITE:
|
||||||
|
throw new CannotWriteFileException($this->getErrorMessage());
|
||||||
|
case \UPLOAD_ERR_NO_TMP_DIR:
|
||||||
|
throw new NoTmpDirFileException($this->getErrorMessage());
|
||||||
|
case \UPLOAD_ERR_EXTENSION:
|
||||||
|
throw new ExtensionFileException($this->getErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileException($this->getErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum size of an uploaded file as configured in php.ini.
|
||||||
|
*
|
||||||
|
* @return int|float The maximum size of an uploaded file in bytes (returns float if size > PHP_INT_MAX)
|
||||||
|
*/
|
||||||
|
public static function getMaxFilesize(): int|float
|
||||||
|
{
|
||||||
|
$sizePostMax = self::parseFilesize(\ini_get('post_max_size'));
|
||||||
|
$sizeUploadMax = self::parseFilesize(\ini_get('upload_max_filesize'));
|
||||||
|
|
||||||
|
return min($sizePostMax ?: \PHP_INT_MAX, $sizeUploadMax ?: \PHP_INT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function parseFilesize(string $size): int|float
|
||||||
|
{
|
||||||
|
if ('' === $size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = strtolower($size);
|
||||||
|
|
||||||
|
$max = ltrim($size, '+');
|
||||||
|
if (str_starts_with($max, '0x')) {
|
||||||
|
$max = \intval($max, 16);
|
||||||
|
} elseif (str_starts_with($max, '0')) {
|
||||||
|
$max = \intval($max, 8);
|
||||||
|
} else {
|
||||||
|
$max = (int) $max;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (substr($size, -1)) {
|
||||||
|
case 't': $max *= 1024;
|
||||||
|
// no break
|
||||||
|
case 'g': $max *= 1024;
|
||||||
|
// no break
|
||||||
|
case 'm': $max *= 1024;
|
||||||
|
// no break
|
||||||
|
case 'k': $max *= 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an informative upload error message.
|
||||||
|
*/
|
||||||
|
public function getErrorMessage(): string
|
||||||
|
{
|
||||||
|
static $errors = [
|
||||||
|
\UPLOAD_ERR_INI_SIZE => 'The file "%s" exceeds your upload_max_filesize ini directive (limit is %d KiB).',
|
||||||
|
\UPLOAD_ERR_FORM_SIZE => 'The file "%s" exceeds the upload limit defined in your form.',
|
||||||
|
\UPLOAD_ERR_PARTIAL => 'The file "%s" was only partially uploaded.',
|
||||||
|
\UPLOAD_ERR_NO_FILE => 'No file was uploaded.',
|
||||||
|
\UPLOAD_ERR_CANT_WRITE => 'The file "%s" could not be written on disk.',
|
||||||
|
\UPLOAD_ERR_NO_TMP_DIR => 'File could not be uploaded: missing temporary directory.',
|
||||||
|
\UPLOAD_ERR_EXTENSION => 'File upload was stopped by a PHP extension.',
|
||||||
|
];
|
||||||
|
|
||||||
|
$errorCode = $this->error;
|
||||||
|
$maxFilesize = \UPLOAD_ERR_INI_SIZE === $errorCode ? self::getMaxFilesize() / 1024 : 0;
|
||||||
|
$message = $errors[$errorCode] ?? 'The file "%s" was not uploaded due to an unknown error.';
|
||||||
|
|
||||||
|
return \sprintf($message, $this->getClientOriginalName(), $maxFilesize);
|
||||||
|
}
|
||||||
|
}
|
||||||
127
vendor/symfony/http-foundation/FileBag.php
vendored
Normal file
127
vendor/symfony/http-foundation/FileBag.php
vendored
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileBag is a container for uploaded files.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||||
|
*/
|
||||||
|
class FileBag extends ParameterBag
|
||||||
|
{
|
||||||
|
private const FILE_KEYS = ['error', 'full_path', 'name', 'size', 'tmp_name', 'type'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|UploadedFile[] $parameters An array of HTTP files
|
||||||
|
*/
|
||||||
|
public function __construct(array $parameters = [])
|
||||||
|
{
|
||||||
|
$this->replace($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function replace(array $files = []): void
|
||||||
|
{
|
||||||
|
$this->parameters = [];
|
||||||
|
$this->add($files);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value): void
|
||||||
|
{
|
||||||
|
if (!\is_array($value) && !$value instanceof UploadedFile) {
|
||||||
|
throw new \InvalidArgumentException('An uploaded file must be an array or an instance of UploadedFile.');
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::set($key, $this->convertFileInformation($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add(array $files = []): void
|
||||||
|
{
|
||||||
|
foreach ($files as $key => $file) {
|
||||||
|
$this->set($key, $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts uploaded files to UploadedFile instances.
|
||||||
|
*
|
||||||
|
* @return UploadedFile[]|UploadedFile|null
|
||||||
|
*/
|
||||||
|
protected function convertFileInformation(array|UploadedFile $file): array|UploadedFile|null
|
||||||
|
{
|
||||||
|
if ($file instanceof UploadedFile) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->fixPhpFilesArray($file);
|
||||||
|
$keys = array_keys($file + ['full_path' => null]);
|
||||||
|
sort($keys);
|
||||||
|
|
||||||
|
if (self::FILE_KEYS === $keys) {
|
||||||
|
if (\UPLOAD_ERR_NO_FILE === $file['error']) {
|
||||||
|
$file = null;
|
||||||
|
} else {
|
||||||
|
$file = new UploadedFile($file['tmp_name'], $file['full_path'] ?? $file['name'], $file['type'], $file['error'], false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$file = array_map(fn ($v) => $v instanceof UploadedFile || \is_array($v) ? $this->convertFileInformation($v) : $v, $file);
|
||||||
|
if (array_is_list($file)) {
|
||||||
|
$file = array_filter($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes a malformed PHP $_FILES array.
|
||||||
|
*
|
||||||
|
* PHP has a bug that the format of the $_FILES array differs, depending on
|
||||||
|
* whether the uploaded file fields had normal field names or array-like
|
||||||
|
* field names ("normal" vs. "parent[child]").
|
||||||
|
*
|
||||||
|
* This method fixes the array to look like the "normal" $_FILES array.
|
||||||
|
*
|
||||||
|
* It's safe to pass an already converted array, in which case this method
|
||||||
|
* just returns the original array unmodified.
|
||||||
|
*/
|
||||||
|
protected function fixPhpFilesArray(array $data): array
|
||||||
|
{
|
||||||
|
$keys = array_keys($data + ['full_path' => null]);
|
||||||
|
sort($keys);
|
||||||
|
|
||||||
|
if (self::FILE_KEYS !== $keys || !isset($data['name']) || !\is_array($data['name'])) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = $data;
|
||||||
|
foreach (self::FILE_KEYS as $k) {
|
||||||
|
unset($files[$k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($data['name'] as $key => $name) {
|
||||||
|
$files[$key] = $this->fixPhpFilesArray([
|
||||||
|
'error' => $data['error'][$key],
|
||||||
|
'name' => $name,
|
||||||
|
'type' => $data['type'][$key],
|
||||||
|
'tmp_name' => $data['tmp_name'][$key],
|
||||||
|
'size' => $data['size'][$key],
|
||||||
|
] + (isset($data['full_path'][$key]) ? [
|
||||||
|
'full_path' => $data['full_path'][$key],
|
||||||
|
] : []));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
}
|
||||||
273
vendor/symfony/http-foundation/HeaderBag.php
vendored
Normal file
273
vendor/symfony/http-foundation/HeaderBag.php
vendored
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HeaderBag is a container for HTTP headers.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* @implements \IteratorAggregate<string, list<string|null>>
|
||||||
|
*/
|
||||||
|
class HeaderBag implements \IteratorAggregate, \Countable, \Stringable
|
||||||
|
{
|
||||||
|
protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
protected const LOWER = '-abcdefghijklmnopqrstuvwxyz';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, list<string|null>>
|
||||||
|
*/
|
||||||
|
protected array $headers = [];
|
||||||
|
protected array $cacheControl = [];
|
||||||
|
|
||||||
|
public function __construct(array $headers = [])
|
||||||
|
{
|
||||||
|
foreach ($headers as $key => $values) {
|
||||||
|
$this->set($key, $values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the headers as a string.
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
if (!$headers = $this->all()) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($headers);
|
||||||
|
$max = max(array_map('strlen', array_keys($headers))) + 1;
|
||||||
|
$content = '';
|
||||||
|
foreach ($headers as $name => $values) {
|
||||||
|
$name = ucwords($name, '-');
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$content .= \sprintf("%-{$max}s %s\r\n", $name.':', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the headers.
|
||||||
|
*
|
||||||
|
* @param string|null $key The name of the headers to return or null to get them all
|
||||||
|
*
|
||||||
|
* @return ($key is null ? array<string, list<string|null>> : list<string|null>)
|
||||||
|
*/
|
||||||
|
public function all(?string $key = null): array
|
||||||
|
{
|
||||||
|
if (null !== $key) {
|
||||||
|
return $this->headers[strtr($key, self::UPPER, self::LOWER)] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter keys.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function keys(): array
|
||||||
|
{
|
||||||
|
return array_keys($this->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the current HTTP headers by a new set.
|
||||||
|
*/
|
||||||
|
public function replace(array $headers = []): void
|
||||||
|
{
|
||||||
|
$this->headers = [];
|
||||||
|
$this->add($headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds new headers the current HTTP headers set.
|
||||||
|
*/
|
||||||
|
public function add(array $headers): void
|
||||||
|
{
|
||||||
|
foreach ($headers as $key => $values) {
|
||||||
|
$this->set($key, $values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first header by name or the default one.
|
||||||
|
*/
|
||||||
|
public function get(string $key, ?string $default = null): ?string
|
||||||
|
{
|
||||||
|
$headers = $this->all($key);
|
||||||
|
|
||||||
|
if (!$headers) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $headers[0]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a header by name.
|
||||||
|
*
|
||||||
|
* @param string|string[]|null $values The value or an array of values
|
||||||
|
* @param bool $replace Whether to replace the actual value or not (true by default)
|
||||||
|
*/
|
||||||
|
public function set(string $key, string|array|null $values, bool $replace = true): void
|
||||||
|
{
|
||||||
|
$key = strtr($key, self::UPPER, self::LOWER);
|
||||||
|
|
||||||
|
if (\is_array($values)) {
|
||||||
|
$values = array_values($values);
|
||||||
|
|
||||||
|
if (true === $replace || !isset($this->headers[$key])) {
|
||||||
|
$this->headers[$key] = $values;
|
||||||
|
} else {
|
||||||
|
$this->headers[$key] = array_merge($this->headers[$key], $values);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (true === $replace || !isset($this->headers[$key])) {
|
||||||
|
$this->headers[$key] = [$values];
|
||||||
|
} else {
|
||||||
|
$this->headers[$key][] = $values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('cache-control' === $key) {
|
||||||
|
$this->cacheControl = $this->parseCacheControl(implode(', ', $this->headers[$key]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the HTTP header is defined.
|
||||||
|
*/
|
||||||
|
public function has(string $key): bool
|
||||||
|
{
|
||||||
|
return \array_key_exists(strtr($key, self::UPPER, self::LOWER), $this->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given HTTP header contains the given value.
|
||||||
|
*/
|
||||||
|
public function contains(string $key, string $value): bool
|
||||||
|
{
|
||||||
|
return \in_array($value, $this->all($key), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a header.
|
||||||
|
*/
|
||||||
|
public function remove(string $key): void
|
||||||
|
{
|
||||||
|
$key = strtr($key, self::UPPER, self::LOWER);
|
||||||
|
|
||||||
|
unset($this->headers[$key]);
|
||||||
|
|
||||||
|
if ('cache-control' === $key) {
|
||||||
|
$this->cacheControl = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTTP header value converted to a date.
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException When the HTTP header is not parseable
|
||||||
|
*/
|
||||||
|
public function getDate(string $key, ?\DateTimeInterface $default = null): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
if (null === $value = $this->get($key)) {
|
||||||
|
return null !== $default ? \DateTimeImmutable::createFromInterface($default) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $date = \DateTimeImmutable::createFromFormat(\DATE_RFC2822, $value)) {
|
||||||
|
throw new \RuntimeException(\sprintf('The "%s" HTTP header is not parseable (%s).', $key, $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a custom Cache-Control directive.
|
||||||
|
*/
|
||||||
|
public function addCacheControlDirective(string $key, bool|string $value = true): void
|
||||||
|
{
|
||||||
|
$this->cacheControl[$key] = $value;
|
||||||
|
|
||||||
|
$this->set('Cache-Control', $this->getCacheControlHeader());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the Cache-Control directive is defined.
|
||||||
|
*/
|
||||||
|
public function hasCacheControlDirective(string $key): bool
|
||||||
|
{
|
||||||
|
return \array_key_exists($key, $this->cacheControl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Cache-Control directive value by name.
|
||||||
|
*/
|
||||||
|
public function getCacheControlDirective(string $key): bool|string|null
|
||||||
|
{
|
||||||
|
return $this->cacheControl[$key] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a Cache-Control directive.
|
||||||
|
*/
|
||||||
|
public function removeCacheControlDirective(string $key): void
|
||||||
|
{
|
||||||
|
unset($this->cacheControl[$key]);
|
||||||
|
|
||||||
|
$this->set('Cache-Control', $this->getCacheControlHeader());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator for headers.
|
||||||
|
*
|
||||||
|
* @return \ArrayIterator<string, list<string|null>>
|
||||||
|
*/
|
||||||
|
public function getIterator(): \ArrayIterator
|
||||||
|
{
|
||||||
|
return new \ArrayIterator($this->headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of headers.
|
||||||
|
*/
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return \count($this->headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCacheControlHeader(): string
|
||||||
|
{
|
||||||
|
ksort($this->cacheControl);
|
||||||
|
|
||||||
|
return HeaderUtils::toString($this->cacheControl, ',');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a Cache-Control HTTP header.
|
||||||
|
*/
|
||||||
|
protected function parseCacheControl(string $header): array
|
||||||
|
{
|
||||||
|
$parts = HeaderUtils::split($header, ',=');
|
||||||
|
|
||||||
|
return HeaderUtils::combine($parts);
|
||||||
|
}
|
||||||
|
}
|
||||||
298
vendor/symfony/http-foundation/HeaderUtils.php
vendored
Normal file
298
vendor/symfony/http-foundation/HeaderUtils.php
vendored
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP header utility functions.
|
||||||
|
*
|
||||||
|
* @author Christian Schmidt <github@chsc.dk>
|
||||||
|
*/
|
||||||
|
class HeaderUtils
|
||||||
|
{
|
||||||
|
public const DISPOSITION_ATTACHMENT = 'attachment';
|
||||||
|
public const DISPOSITION_INLINE = 'inline';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class should not be instantiated.
|
||||||
|
*/
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits an HTTP header by one or more separators.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* HeaderUtils::split('da, en-gb;q=0.8', ',;')
|
||||||
|
* # returns [['da'], ['en-gb', 'q=0.8']]
|
||||||
|
*
|
||||||
|
* @param string $separators List of characters to split on, ordered by
|
||||||
|
* precedence, e.g. ',', ';=', or ',;='
|
||||||
|
*
|
||||||
|
* @return array Nested array with as many levels as there are characters in
|
||||||
|
* $separators
|
||||||
|
*/
|
||||||
|
public static function split(string $header, string $separators): array
|
||||||
|
{
|
||||||
|
if ('' === $separators) {
|
||||||
|
throw new \InvalidArgumentException('At least one separator must be specified.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$quotedSeparators = preg_quote($separators, '/');
|
||||||
|
|
||||||
|
preg_match_all('
|
||||||
|
/
|
||||||
|
(?!\s)
|
||||||
|
(?:
|
||||||
|
# quoted-string
|
||||||
|
"(?:[^"\\\\]|\\\\.)*(?:"|\\\\|$)
|
||||||
|
|
|
||||||
|
# token
|
||||||
|
[^"'.$quotedSeparators.']+
|
||||||
|
)+
|
||||||
|
(?<!\s)
|
||||||
|
|
|
||||||
|
# separator
|
||||||
|
\s*
|
||||||
|
(?<separator>['.$quotedSeparators.'])
|
||||||
|
\s*
|
||||||
|
/x', trim($header), $matches, \PREG_SET_ORDER);
|
||||||
|
|
||||||
|
return self::groupParts($matches, $separators);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines an array of arrays into one associative array.
|
||||||
|
*
|
||||||
|
* Each of the nested arrays should have one or two elements. The first
|
||||||
|
* value will be used as the keys in the associative array, and the second
|
||||||
|
* will be used as the values, or true if the nested array only contains one
|
||||||
|
* element. Array keys are lowercased.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* HeaderUtils::combine([['foo', 'abc'], ['bar']])
|
||||||
|
* // => ['foo' => 'abc', 'bar' => true]
|
||||||
|
*/
|
||||||
|
public static function combine(array $parts): array
|
||||||
|
{
|
||||||
|
$assoc = [];
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
$name = strtolower($part[0]);
|
||||||
|
$value = $part[1] ?? true;
|
||||||
|
$assoc[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins an associative array into a string for use in an HTTP header.
|
||||||
|
*
|
||||||
|
* The key and value of each entry are joined with '=', and all entries
|
||||||
|
* are joined with the specified separator and an additional space (for
|
||||||
|
* readability). Values are quoted if necessary.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* HeaderUtils::toString(['foo' => 'abc', 'bar' => true, 'baz' => 'a b c'], ',')
|
||||||
|
* // => 'foo=abc, bar, baz="a b c"'
|
||||||
|
*/
|
||||||
|
public static function toString(array $assoc, string $separator): string
|
||||||
|
{
|
||||||
|
$parts = [];
|
||||||
|
foreach ($assoc as $name => $value) {
|
||||||
|
if (true === $value) {
|
||||||
|
$parts[] = $name;
|
||||||
|
} else {
|
||||||
|
$parts[] = $name.'='.self::quote($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode($separator.' ', $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a string as a quoted string, if necessary.
|
||||||
|
*
|
||||||
|
* If a string contains characters not allowed by the "token" construct in
|
||||||
|
* the HTTP specification, it is backslash-escaped and enclosed in quotes
|
||||||
|
* to match the "quoted-string" construct.
|
||||||
|
*/
|
||||||
|
public static function quote(string $s): string
|
||||||
|
{
|
||||||
|
if (preg_match('/^[a-z0-9!#$%&\'*.^_`|~-]+$/i', $s)) {
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '"'.addcslashes($s, '"\\"').'"';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a quoted string.
|
||||||
|
*
|
||||||
|
* If passed an unquoted string that matches the "token" construct (as
|
||||||
|
* defined in the HTTP specification), it is passed through verbatim.
|
||||||
|
*/
|
||||||
|
public static function unquote(string $s): string
|
||||||
|
{
|
||||||
|
return preg_replace('/\\\\(.)|"/', '$1', $s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an HTTP Content-Disposition field-value.
|
||||||
|
*
|
||||||
|
* @param string $disposition One of "inline" or "attachment"
|
||||||
|
* @param string $filename A unicode string
|
||||||
|
* @param string $filenameFallback A string containing only ASCII characters that
|
||||||
|
* is semantically equivalent to $filename. If the filename is already ASCII,
|
||||||
|
* it can be omitted, or just copied from $filename
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @see RFC 6266
|
||||||
|
*/
|
||||||
|
public static function makeDisposition(string $disposition, string $filename, string $filenameFallback = ''): string
|
||||||
|
{
|
||||||
|
if (!\in_array($disposition, [self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE], true)) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' === $filenameFallback) {
|
||||||
|
$filenameFallback = $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filenameFallback is not ASCII.
|
||||||
|
if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) {
|
||||||
|
throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// percent characters aren't safe in fallback.
|
||||||
|
if (str_contains($filenameFallback, '%')) {
|
||||||
|
throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// path separators aren't allowed in either.
|
||||||
|
if (str_contains($filename, '/') || str_contains($filename, '\\') || str_contains($filenameFallback, '/') || str_contains($filenameFallback, '\\')) {
|
||||||
|
throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = ['filename' => $filenameFallback];
|
||||||
|
if ($filename !== $filenameFallback) {
|
||||||
|
$params['filename*'] = "utf-8''".rawurlencode($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $disposition.'; '.self::toString($params, ';');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like parse_str(), but preserves dots in variable names.
|
||||||
|
*/
|
||||||
|
public static function parseQuery(string $query, bool $ignoreBrackets = false, string $separator = '&'): array
|
||||||
|
{
|
||||||
|
$q = [];
|
||||||
|
|
||||||
|
foreach (explode($separator, $query) as $v) {
|
||||||
|
if (false !== $i = strpos($v, "\0")) {
|
||||||
|
$v = substr($v, 0, $i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $i = strpos($v, '=')) {
|
||||||
|
$k = urldecode($v);
|
||||||
|
$v = '';
|
||||||
|
} else {
|
||||||
|
$k = urldecode(substr($v, 0, $i));
|
||||||
|
$v = substr($v, $i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== $i = strpos($k, "\0")) {
|
||||||
|
$k = substr($k, 0, $i);
|
||||||
|
}
|
||||||
|
|
||||||
|
$k = ltrim($k, ' ');
|
||||||
|
|
||||||
|
if ($ignoreBrackets) {
|
||||||
|
$q[$k][] = urldecode(substr($v, 1));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $i = strpos($k, '[')) {
|
||||||
|
$q[] = bin2hex($k).$v;
|
||||||
|
} else {
|
||||||
|
$q[] = bin2hex(substr($k, 0, $i)).rawurlencode(substr($k, $i)).$v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ignoreBrackets) {
|
||||||
|
return $q;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_str(implode('&', $q), $q);
|
||||||
|
|
||||||
|
$query = [];
|
||||||
|
|
||||||
|
foreach ($q as $k => $v) {
|
||||||
|
if (false !== $i = strpos($k, '_')) {
|
||||||
|
$query[substr_replace($k, hex2bin(substr($k, 0, $i)).'[', 0, 1 + $i)] = $v;
|
||||||
|
} else {
|
||||||
|
$query[hex2bin($k)] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function groupParts(array $matches, string $separators, bool $first = true): array
|
||||||
|
{
|
||||||
|
$separator = $separators[0];
|
||||||
|
$separators = substr($separators, 1) ?: '';
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
if ('' === $separators && !$first) {
|
||||||
|
$parts = [''];
|
||||||
|
|
||||||
|
foreach ($matches as $match) {
|
||||||
|
if (!$i && isset($match['separator'])) {
|
||||||
|
$i = 1;
|
||||||
|
$parts[1] = '';
|
||||||
|
} else {
|
||||||
|
$parts[$i] .= self::unquote($match[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = [];
|
||||||
|
$partMatches = [];
|
||||||
|
|
||||||
|
foreach ($matches as $match) {
|
||||||
|
if (($match['separator'] ?? null) === $separator) {
|
||||||
|
++$i;
|
||||||
|
} else {
|
||||||
|
$partMatches[$i][] = $match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($partMatches as $matches) {
|
||||||
|
if ('' === $separators && '' !== $unquoted = self::unquote($matches[0][0])) {
|
||||||
|
$parts[] = $unquoted;
|
||||||
|
} elseif ($groupedParts = self::groupParts($matches, $separators, false)) {
|
||||||
|
$parts[] = $groupedParts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
}
|
||||||
152
vendor/symfony/http-foundation/InputBag.php
vendored
Normal file
152
vendor/symfony/http-foundation/InputBag.php
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||||
|
use Symfony\Component\HttpFoundation\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InputBag is a container for user input values such as $_GET, $_POST, $_REQUEST, and $_COOKIE.
|
||||||
|
*
|
||||||
|
* @template TInput of string|int|float|bool|null
|
||||||
|
*
|
||||||
|
* @author Saif Eddin Gmati <azjezz@protonmail.com>
|
||||||
|
*/
|
||||||
|
final class InputBag extends ParameterBag
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns a scalar input value by name.
|
||||||
|
*
|
||||||
|
* @template TDefault of string|int|float|bool|null
|
||||||
|
*
|
||||||
|
* @param TDefault $default The default value if the input key does not exist
|
||||||
|
*
|
||||||
|
* @return TDefault|TInput
|
||||||
|
*
|
||||||
|
* @throws BadRequestException if the input contains a non-scalar value
|
||||||
|
*/
|
||||||
|
public function get(string $key, mixed $default = null): string|int|float|bool|null
|
||||||
|
{
|
||||||
|
if (null !== $default && !\is_scalar($default) && !$default instanceof \Stringable) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('Expected a scalar value as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($default)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = parent::get($key, $this);
|
||||||
|
|
||||||
|
if (null !== $value && $this !== $value && !\is_scalar($value) && !$value instanceof \Stringable) {
|
||||||
|
throw new BadRequestException(\sprintf('Input value "%s" contains a non-scalar value.', $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this === $value ? $default : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the current input values by a new set.
|
||||||
|
*/
|
||||||
|
public function replace(array $inputs = []): void
|
||||||
|
{
|
||||||
|
$this->parameters = [];
|
||||||
|
$this->add($inputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds input values.
|
||||||
|
*/
|
||||||
|
public function add(array $inputs = []): void
|
||||||
|
{
|
||||||
|
foreach ($inputs as $input => $value) {
|
||||||
|
$this->set($input, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an input by name.
|
||||||
|
*
|
||||||
|
* @param string|int|float|bool|array|null $value
|
||||||
|
*/
|
||||||
|
public function set(string $key, mixed $value): void
|
||||||
|
{
|
||||||
|
if (null !== $value && !\is_scalar($value) && !\is_array($value) && !$value instanceof \Stringable) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('Expected a scalar, or an array as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->parameters[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter value converted to an enum.
|
||||||
|
*
|
||||||
|
* @template T of \BackedEnum
|
||||||
|
*
|
||||||
|
* @param class-string<T> $class
|
||||||
|
* @param ?T $default
|
||||||
|
*
|
||||||
|
* @return ?T
|
||||||
|
*
|
||||||
|
* @psalm-return ($default is null ? T|null : T)
|
||||||
|
*
|
||||||
|
* @throws BadRequestException if the input cannot be converted to an enum
|
||||||
|
*/
|
||||||
|
public function getEnum(string $key, string $class, ?\BackedEnum $default = null): ?\BackedEnum
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return parent::getEnum($key, $class, $default);
|
||||||
|
} catch (UnexpectedValueException $e) {
|
||||||
|
throw new BadRequestException($e->getMessage(), $e->getCode(), $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter value converted to string.
|
||||||
|
*
|
||||||
|
* @throws BadRequestException if the input contains a non-scalar value
|
||||||
|
*/
|
||||||
|
public function getString(string $key, string $default = ''): string
|
||||||
|
{
|
||||||
|
// Shortcuts the parent method because the validation on scalar is already done in get().
|
||||||
|
return (string) $this->get($key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws BadRequestException if the input value is an array and \FILTER_REQUIRE_ARRAY or \FILTER_FORCE_ARRAY is not set
|
||||||
|
* @throws BadRequestException if the input value is invalid and \FILTER_NULL_ON_FAILURE is not set
|
||||||
|
*/
|
||||||
|
public function filter(string $key, mixed $default = null, int $filter = \FILTER_DEFAULT, mixed $options = []): mixed
|
||||||
|
{
|
||||||
|
$value = $this->has($key) ? $this->all()[$key] : $default;
|
||||||
|
|
||||||
|
// Always turn $options into an array - this allows filter_var option shortcuts.
|
||||||
|
if (!\is_array($options) && $options) {
|
||||||
|
$options = ['flags' => $options];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_array($value) && !(($options['flags'] ?? 0) & (\FILTER_REQUIRE_ARRAY | \FILTER_FORCE_ARRAY))) {
|
||||||
|
throw new BadRequestException(\sprintf('Input value "%s" contains an array, but "FILTER_REQUIRE_ARRAY" or "FILTER_FORCE_ARRAY" flags were not set.', $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((\FILTER_CALLBACK & $filter) && !(($options['options'] ?? null) instanceof \Closure)) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['flags'] ??= 0;
|
||||||
|
$nullOnFailure = $options['flags'] & \FILTER_NULL_ON_FAILURE;
|
||||||
|
$options['flags'] |= \FILTER_NULL_ON_FAILURE;
|
||||||
|
|
||||||
|
$value = filter_var($value, $filter, $options);
|
||||||
|
|
||||||
|
if (null !== $value || $nullOnFailure) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new BadRequestException(\sprintf('Input value "%s" is invalid and flag "FILTER_NULL_ON_FAILURE" was not set.', $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
270
vendor/symfony/http-foundation/IpUtils.php
vendored
Normal file
270
vendor/symfony/http-foundation/IpUtils.php
vendored
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Http utility functions.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class IpUtils
|
||||||
|
{
|
||||||
|
public const PRIVATE_SUBNETS = [
|
||||||
|
'127.0.0.0/8', // RFC1700 (Loopback)
|
||||||
|
'10.0.0.0/8', // RFC1918
|
||||||
|
'192.168.0.0/16', // RFC1918
|
||||||
|
'172.16.0.0/12', // RFC1918
|
||||||
|
'169.254.0.0/16', // RFC3927
|
||||||
|
'0.0.0.0/8', // RFC5735
|
||||||
|
'240.0.0.0/4', // RFC1112
|
||||||
|
'::1/128', // Loopback
|
||||||
|
'fc00::/7', // Unique Local Address
|
||||||
|
'fe80::/10', // Link Local Address
|
||||||
|
'::ffff:0:0/96', // IPv4 translations
|
||||||
|
'::/128', // Unspecified address
|
||||||
|
];
|
||||||
|
|
||||||
|
private static array $checkedIps = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class should not be instantiated.
|
||||||
|
*/
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an IPv4 or IPv6 address is contained in the list of given IPs or subnets.
|
||||||
|
*
|
||||||
|
* @param string|array $ips List of IPs or subnets (can be a string if only a single one)
|
||||||
|
*/
|
||||||
|
public static function checkIp(string $requestIp, string|array $ips): bool
|
||||||
|
{
|
||||||
|
if (!\is_array($ips)) {
|
||||||
|
$ips = [$ips];
|
||||||
|
}
|
||||||
|
|
||||||
|
$method = substr_count($requestIp, ':') > 1 ? 'checkIp6' : 'checkIp4';
|
||||||
|
|
||||||
|
foreach ($ips as $ip) {
|
||||||
|
if (self::$method($requestIp, $ip)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two IPv4 addresses.
|
||||||
|
* In case a subnet is given, it checks if it contains the request IP.
|
||||||
|
*
|
||||||
|
* @param string $ip IPv4 address or subnet in CIDR notation
|
||||||
|
*
|
||||||
|
* @return bool Whether the request IP matches the IP, or whether the request IP is within the CIDR subnet
|
||||||
|
*/
|
||||||
|
public static function checkIp4(string $requestIp, string $ip): bool
|
||||||
|
{
|
||||||
|
$cacheKey = $requestIp.'-'.$ip.'-v4';
|
||||||
|
if (null !== $cacheValue = self::getCacheResult($cacheKey)) {
|
||||||
|
return $cacheValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filter_var($requestIp, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($ip, '/')) {
|
||||||
|
[$address, $netmask] = explode('/', $ip, 2);
|
||||||
|
|
||||||
|
if ('0' === $netmask) {
|
||||||
|
return self::setCacheResult($cacheKey, false !== filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($netmask < 0 || $netmask > 32) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$address = $ip;
|
||||||
|
$netmask = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === ip2long($address)) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::setCacheResult($cacheKey, 0 === substr_compare(\sprintf('%032b', ip2long($requestIp)), \sprintf('%032b', ip2long($address)), 0, $netmask));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two IPv6 addresses.
|
||||||
|
* In case a subnet is given, it checks if it contains the request IP.
|
||||||
|
*
|
||||||
|
* @author David Soria Parra <dsp at php dot net>
|
||||||
|
*
|
||||||
|
* @see https://github.com/dsp/v6tools
|
||||||
|
*
|
||||||
|
* @param string $ip IPv6 address or subnet in CIDR notation
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException When IPV6 support is not enabled
|
||||||
|
*/
|
||||||
|
public static function checkIp6(string $requestIp, string $ip): bool
|
||||||
|
{
|
||||||
|
$cacheKey = $requestIp.'-'.$ip.'-v6';
|
||||||
|
if (null !== $cacheValue = self::getCacheResult($cacheKey)) {
|
||||||
|
return $cacheValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!((\extension_loaded('sockets') && \defined('AF_INET6')) || @inet_pton('::1'))) {
|
||||||
|
throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if we were given a IP4 $requestIp or $ip by mistake
|
||||||
|
if (!filter_var($requestIp, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($ip, '/')) {
|
||||||
|
[$address, $netmask] = explode('/', $ip, 2);
|
||||||
|
|
||||||
|
if (!filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('0' === $netmask) {
|
||||||
|
return (bool) unpack('n*', @inet_pton($address));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($netmask < 1 || $netmask > 128) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$address = $ip;
|
||||||
|
$netmask = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bytesAddr = unpack('n*', @inet_pton($address));
|
||||||
|
$bytesTest = unpack('n*', @inet_pton($requestIp));
|
||||||
|
|
||||||
|
if (!$bytesAddr || !$bytesTest) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) {
|
||||||
|
$left = $netmask - 16 * ($i - 1);
|
||||||
|
$left = ($left <= 16) ? $left : 16;
|
||||||
|
$mask = ~(0xFFFF >> $left) & 0xFFFF;
|
||||||
|
if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
|
||||||
|
return self::setCacheResult($cacheKey, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::setCacheResult($cacheKey, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anonymizes an IP/IPv6.
|
||||||
|
*
|
||||||
|
* Removes the last bytes of IPv4 and IPv6 addresses (1 byte for IPv4 and 8 bytes for IPv6 by default).
|
||||||
|
*
|
||||||
|
* @param int<0, 4> $v4Bytes
|
||||||
|
* @param int<0, 16> $v6Bytes
|
||||||
|
*/
|
||||||
|
public static function anonymize(string $ip, int $v4Bytes = 1, int $v6Bytes = 8): string
|
||||||
|
{
|
||||||
|
if ($v4Bytes < 0 || $v6Bytes < 0) {
|
||||||
|
throw new \InvalidArgumentException('Cannot anonymize less than 0 bytes.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($v4Bytes > 4 || $v6Bytes > 16) {
|
||||||
|
throw new \InvalidArgumentException('Cannot anonymize more than 4 bytes for IPv4 and 16 bytes for IPv6.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the IP contains a % symbol, then it is a local-link address with scoping according to RFC 4007
|
||||||
|
* In that case, we only care about the part before the % symbol, as the following functions, can only work with
|
||||||
|
* the IP address itself. As the scope can leak information (containing interface name), we do not want to
|
||||||
|
* include it in our anonymized IP data.
|
||||||
|
*/
|
||||||
|
if (str_contains($ip, '%')) {
|
||||||
|
$ip = substr($ip, 0, strpos($ip, '%'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$wrappedIPv6 = false;
|
||||||
|
if (str_starts_with($ip, '[') && str_ends_with($ip, ']')) {
|
||||||
|
$wrappedIPv6 = true;
|
||||||
|
$ip = substr($ip, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$mappedIpV4MaskGenerator = function (string $mask, int $bytesToAnonymize) {
|
||||||
|
$mask .= str_repeat('ff', 4 - $bytesToAnonymize);
|
||||||
|
$mask .= str_repeat('00', $bytesToAnonymize);
|
||||||
|
|
||||||
|
return '::'.implode(':', str_split($mask, 4));
|
||||||
|
};
|
||||||
|
|
||||||
|
$packedAddress = inet_pton($ip);
|
||||||
|
if (4 === \strlen($packedAddress)) {
|
||||||
|
$mask = rtrim(str_repeat('255.', 4 - $v4Bytes).str_repeat('0.', $v4Bytes), '.');
|
||||||
|
} elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff:ffff'))) {
|
||||||
|
$mask = $mappedIpV4MaskGenerator('ffff', $v4Bytes);
|
||||||
|
} elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff'))) {
|
||||||
|
$mask = $mappedIpV4MaskGenerator('', $v4Bytes);
|
||||||
|
} else {
|
||||||
|
$mask = str_repeat('ff', 16 - $v6Bytes).str_repeat('00', $v6Bytes);
|
||||||
|
$mask = implode(':', str_split($mask, 4));
|
||||||
|
}
|
||||||
|
$ip = inet_ntop($packedAddress & inet_pton($mask));
|
||||||
|
|
||||||
|
if ($wrappedIPv6) {
|
||||||
|
$ip = '['.$ip.']';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an IPv4 or IPv6 address is contained in the list of private IP subnets.
|
||||||
|
*/
|
||||||
|
public static function isPrivateIp(string $requestIp): bool
|
||||||
|
{
|
||||||
|
return self::checkIp($requestIp, self::PRIVATE_SUBNETS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getCacheResult(string $cacheKey): ?bool
|
||||||
|
{
|
||||||
|
if (isset(self::$checkedIps[$cacheKey])) {
|
||||||
|
// Move the item last in cache (LRU)
|
||||||
|
$value = self::$checkedIps[$cacheKey];
|
||||||
|
unset(self::$checkedIps[$cacheKey]);
|
||||||
|
self::$checkedIps[$cacheKey] = $value;
|
||||||
|
|
||||||
|
return self::$checkedIps[$cacheKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function setCacheResult(string $cacheKey, bool $result): bool
|
||||||
|
{
|
||||||
|
if (1000 < \count(self::$checkedIps)) {
|
||||||
|
// stop memory leak if there are many keys
|
||||||
|
self::$checkedIps = \array_slice(self::$checkedIps, 500, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$checkedIps[$cacheKey] = $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
187
vendor/symfony/http-foundation/JsonResponse.php
vendored
Normal file
187
vendor/symfony/http-foundation/JsonResponse.php
vendored
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response represents an HTTP response in JSON format.
|
||||||
|
*
|
||||||
|
* Note that this class does not force the returned JSON content to be an
|
||||||
|
* object. It is however recommended that you do return an object as it
|
||||||
|
* protects yourself against XSSI and JSON-JavaScript Hijacking.
|
||||||
|
*
|
||||||
|
* @see https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/AJAX_Security_Cheat_Sheet.md#always-return-json-with-an-object-on-the-outside
|
||||||
|
*
|
||||||
|
* @author Igor Wiedler <igor@wiedler.ch>
|
||||||
|
*/
|
||||||
|
class JsonResponse extends Response
|
||||||
|
{
|
||||||
|
protected mixed $data;
|
||||||
|
protected ?string $callback = null;
|
||||||
|
|
||||||
|
// Encode <, >, ', &, and " characters in the JSON, making it also safe to be embedded into HTML.
|
||||||
|
// 15 === JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
|
||||||
|
public const DEFAULT_ENCODING_OPTIONS = 15;
|
||||||
|
|
||||||
|
protected int $encodingOptions = self::DEFAULT_ENCODING_OPTIONS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $json If the data is already a JSON string
|
||||||
|
*/
|
||||||
|
public function __construct(mixed $data = null, int $status = 200, array $headers = [], bool $json = false)
|
||||||
|
{
|
||||||
|
parent::__construct('', $status, $headers);
|
||||||
|
|
||||||
|
if ($json && !\is_string($data) && !is_numeric($data) && !$data instanceof \Stringable) {
|
||||||
|
throw new \TypeError(\sprintf('"%s": If $json is set to true, argument $data must be a string or object implementing __toString(), "%s" given.', __METHOD__, get_debug_type($data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$data ??= new \ArrayObject();
|
||||||
|
|
||||||
|
$json ? $this->setJson($data) : $this->setData($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for chainability.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* return JsonResponse::fromJsonString('{"key": "value"}')
|
||||||
|
* ->setSharedMaxAge(300);
|
||||||
|
*
|
||||||
|
* @param string $data The JSON response string
|
||||||
|
* @param int $status The response status code (200 "OK" by default)
|
||||||
|
* @param array $headers An array of response headers
|
||||||
|
*/
|
||||||
|
public static function fromJsonString(string $data, int $status = 200, array $headers = []): static
|
||||||
|
{
|
||||||
|
return new static($data, $status, $headers, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JSONP callback.
|
||||||
|
*
|
||||||
|
* @param string|null $callback The JSONP callback or null to use none
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException When the callback name is not valid
|
||||||
|
*/
|
||||||
|
public function setCallback(?string $callback): static
|
||||||
|
{
|
||||||
|
if (null !== $callback) {
|
||||||
|
// partially taken from https://geekality.net/2011/08/03/valid-javascript-identifier/
|
||||||
|
// partially taken from https://github.com/willdurand/JsonpCallbackValidator
|
||||||
|
// JsonpCallbackValidator is released under the MIT License. See https://github.com/willdurand/JsonpCallbackValidator/blob/v1.1.0/LICENSE for details.
|
||||||
|
// (c) William Durand <william.durand1@gmail.com>
|
||||||
|
$pattern = '/^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]*(?:\[(?:"(?:\\\.|[^"\\\])*"|\'(?:\\\.|[^\'\\\])*\'|\d+)\])*?$/u';
|
||||||
|
$reserved = [
|
||||||
|
'break', 'do', 'instanceof', 'typeof', 'case', 'else', 'new', 'var', 'catch', 'finally', 'return', 'void', 'continue', 'for', 'switch', 'while',
|
||||||
|
'debugger', 'function', 'this', 'with', 'default', 'if', 'throw', 'delete', 'in', 'try', 'class', 'enum', 'extends', 'super', 'const', 'export',
|
||||||
|
'import', 'implements', 'let', 'private', 'public', 'yield', 'interface', 'package', 'protected', 'static', 'null', 'true', 'false',
|
||||||
|
];
|
||||||
|
$parts = explode('.', $callback);
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if (!preg_match($pattern, $part) || \in_array($part, $reserved, true)) {
|
||||||
|
throw new \InvalidArgumentException('The callback name is not valid.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->callback = $callback;
|
||||||
|
|
||||||
|
return $this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a raw string containing a JSON document to be sent.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setJson(string $json): static
|
||||||
|
{
|
||||||
|
$this->data = $json;
|
||||||
|
|
||||||
|
return $this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data to be sent as JSON.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setData(mixed $data = []): static
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = json_encode($data, $this->encodingOptions);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if ('Exception' === $e::class && str_starts_with($e->getMessage(), 'Failed calling ')) {
|
||||||
|
throw $e->getPrevious() ?: $e;
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\JSON_THROW_ON_ERROR & $this->encodingOptions) {
|
||||||
|
return $this->setJson($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\JSON_ERROR_NONE !== json_last_error()) {
|
||||||
|
throw new \InvalidArgumentException(json_last_error_msg());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->setJson($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns options used while encoding data to JSON.
|
||||||
|
*/
|
||||||
|
public function getEncodingOptions(): int
|
||||||
|
{
|
||||||
|
return $this->encodingOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets options used while encoding data to JSON.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setEncodingOptions(int $encodingOptions): static
|
||||||
|
{
|
||||||
|
$this->encodingOptions = $encodingOptions;
|
||||||
|
|
||||||
|
return $this->setData(json_decode($this->data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the content and headers according to the JSON data and callback.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function update(): static
|
||||||
|
{
|
||||||
|
if (null !== $this->callback) {
|
||||||
|
// Not using application/javascript for compatibility reasons with older browsers.
|
||||||
|
$this->headers->set('Content-Type', 'text/javascript');
|
||||||
|
|
||||||
|
return $this->setContent(\sprintf('/**/%s(%s);', $this->callback, $this->data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only set the header when there is none or when it equals 'text/javascript' (from a previous update with callback)
|
||||||
|
// in order to not overwrite a custom definition.
|
||||||
|
if (!$this->headers->has('Content-Type') || 'text/javascript' === $this->headers->get('Content-Type')) {
|
||||||
|
$this->headers->set('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->setContent($this->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
vendor/symfony/http-foundation/LICENSE
vendored
Normal file
19
vendor/symfony/http-foundation/LICENSE
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2004-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.
|
||||||
271
vendor/symfony/http-foundation/ParameterBag.php
vendored
Normal file
271
vendor/symfony/http-foundation/ParameterBag.php
vendored
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||||
|
use Symfony\Component\HttpFoundation\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParameterBag is a container for key/value pairs.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* @implements \IteratorAggregate<string, mixed>
|
||||||
|
*/
|
||||||
|
class ParameterBag implements \IteratorAggregate, \Countable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $parameters
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
protected array $parameters = [],
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameters.
|
||||||
|
*
|
||||||
|
* @template TKey of string|null
|
||||||
|
*
|
||||||
|
* @param TKey $key The name of the parameter to return or null to get them all
|
||||||
|
*
|
||||||
|
* @return (TKey is null ? array<string, mixed> : array<mixed>)
|
||||||
|
*
|
||||||
|
* @throws BadRequestException if the value is not an array
|
||||||
|
*/
|
||||||
|
public function all(?string $key = null): array
|
||||||
|
{
|
||||||
|
if (null === $key) {
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\is_array($value = $this->parameters[$key] ?? [])) {
|
||||||
|
throw new BadRequestException(\sprintf('Unexpected value for parameter "%s": expecting "array", got "%s".', $key, get_debug_type($value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter keys.
|
||||||
|
*
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function keys(): array
|
||||||
|
{
|
||||||
|
return array_keys($this->parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the current parameters by a new set.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $parameters
|
||||||
|
*/
|
||||||
|
public function replace(array $parameters = []): void
|
||||||
|
{
|
||||||
|
$this->parameters = $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds parameters.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $parameters
|
||||||
|
*/
|
||||||
|
public function add(array $parameters = []): void
|
||||||
|
{
|
||||||
|
$this->parameters = array_replace($this->parameters, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key, mixed $default = null): mixed
|
||||||
|
{
|
||||||
|
return \array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value): void
|
||||||
|
{
|
||||||
|
$this->parameters[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the parameter is defined.
|
||||||
|
*/
|
||||||
|
public function has(string $key): bool
|
||||||
|
{
|
||||||
|
return \array_key_exists($key, $this->parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a parameter.
|
||||||
|
*/
|
||||||
|
public function remove(string $key): void
|
||||||
|
{
|
||||||
|
unset($this->parameters[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the alphabetic characters of the parameter value.
|
||||||
|
*
|
||||||
|
* @throws UnexpectedValueException if the value cannot be converted to string
|
||||||
|
*/
|
||||||
|
public function getAlpha(string $key, string $default = ''): string
|
||||||
|
{
|
||||||
|
return preg_replace('/[^[:alpha:]]/', '', $this->getString($key, $default));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the alphabetic characters and digits of the parameter value.
|
||||||
|
*
|
||||||
|
* @throws UnexpectedValueException if the value cannot be converted to string
|
||||||
|
*/
|
||||||
|
public function getAlnum(string $key, string $default = ''): string
|
||||||
|
{
|
||||||
|
return preg_replace('/[^[:alnum:]]/', '', $this->getString($key, $default));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the digits of the parameter value.
|
||||||
|
*
|
||||||
|
* @throws UnexpectedValueException if the value cannot be converted to string
|
||||||
|
*/
|
||||||
|
public function getDigits(string $key, string $default = ''): string
|
||||||
|
{
|
||||||
|
return preg_replace('/[^[:digit:]]/', '', $this->getString($key, $default));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter as string.
|
||||||
|
*
|
||||||
|
* @throws UnexpectedValueException if the value cannot be converted to string
|
||||||
|
*/
|
||||||
|
public function getString(string $key, string $default = ''): string
|
||||||
|
{
|
||||||
|
$value = $this->get($key, $default);
|
||||||
|
if (!\is_scalar($value) && !$value instanceof \Stringable) {
|
||||||
|
throw new UnexpectedValueException(\sprintf('Parameter value "%s" cannot be converted to "string".', $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter value converted to integer.
|
||||||
|
*
|
||||||
|
* @throws UnexpectedValueException if the value cannot be converted to integer
|
||||||
|
*/
|
||||||
|
public function getInt(string $key, int $default = 0): int
|
||||||
|
{
|
||||||
|
return $this->filter($key, $default, \FILTER_VALIDATE_INT, ['flags' => \FILTER_REQUIRE_SCALAR]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter value converted to boolean.
|
||||||
|
*
|
||||||
|
* @throws UnexpectedValueException if the value cannot be converted to a boolean
|
||||||
|
*/
|
||||||
|
public function getBoolean(string $key, bool $default = false): bool
|
||||||
|
{
|
||||||
|
return $this->filter($key, $default, \FILTER_VALIDATE_BOOL, ['flags' => \FILTER_REQUIRE_SCALAR]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parameter value converted to an enum.
|
||||||
|
*
|
||||||
|
* @template T of \BackedEnum
|
||||||
|
*
|
||||||
|
* @param class-string<T> $class
|
||||||
|
* @param ?T $default
|
||||||
|
*
|
||||||
|
* @return ?T
|
||||||
|
*
|
||||||
|
* @psalm-return ($default is null ? T|null : T)
|
||||||
|
*
|
||||||
|
* @throws UnexpectedValueException if the parameter value cannot be converted to an enum
|
||||||
|
*/
|
||||||
|
public function getEnum(string $key, string $class, ?\BackedEnum $default = null): ?\BackedEnum
|
||||||
|
{
|
||||||
|
$value = $this->get($key);
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $class::from($value);
|
||||||
|
} catch (\ValueError|\TypeError $e) {
|
||||||
|
throw new UnexpectedValueException(\sprintf('Parameter "%s" cannot be converted to enum: ', $key).$e->getMessage().'.', $e->getCode(), $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter key.
|
||||||
|
*
|
||||||
|
* @param int $filter FILTER_* constant
|
||||||
|
* @param int|array{flags?: int, options?: array} $options Flags from FILTER_* constants
|
||||||
|
*
|
||||||
|
* @see https://php.net/filter-var
|
||||||
|
*
|
||||||
|
* @throws UnexpectedValueException if the parameter value is a non-stringable object
|
||||||
|
* @throws UnexpectedValueException if the parameter value is invalid and \FILTER_NULL_ON_FAILURE is not set
|
||||||
|
*/
|
||||||
|
public function filter(string $key, mixed $default = null, int $filter = \FILTER_DEFAULT, mixed $options = []): mixed
|
||||||
|
{
|
||||||
|
$value = $this->get($key, $default);
|
||||||
|
|
||||||
|
// Always turn $options into an array - this allows filter_var option shortcuts.
|
||||||
|
if (!\is_array($options) && $options) {
|
||||||
|
$options = ['flags' => $options];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a convenience check for arrays.
|
||||||
|
if (\is_array($value) && !isset($options['flags'])) {
|
||||||
|
$options['flags'] = \FILTER_REQUIRE_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_object($value) && !$value instanceof \Stringable) {
|
||||||
|
throw new UnexpectedValueException(\sprintf('Parameter value "%s" cannot be filtered.', $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((\FILTER_CALLBACK & $filter) && !(($options['options'] ?? null) instanceof \Closure)) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$options['flags'] ??= 0;
|
||||||
|
$nullOnFailure = $options['flags'] & \FILTER_NULL_ON_FAILURE;
|
||||||
|
$options['flags'] |= \FILTER_NULL_ON_FAILURE;
|
||||||
|
|
||||||
|
$value = filter_var($value, $filter, $options);
|
||||||
|
|
||||||
|
if (null !== $value || $nullOnFailure) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \UnexpectedValueException(\sprintf('Parameter value "%s" is invalid and flag "FILTER_NULL_ON_FAILURE" was not set.', $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator for parameters.
|
||||||
|
*
|
||||||
|
* @return \ArrayIterator<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getIterator(): \ArrayIterator
|
||||||
|
{
|
||||||
|
return new \ArrayIterator($this->parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of parameters.
|
||||||
|
*/
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return \count($this->parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
vendor/symfony/http-foundation/README.md
vendored
Normal file
14
vendor/symfony/http-foundation/README.md
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
HttpFoundation Component
|
||||||
|
========================
|
||||||
|
|
||||||
|
The HttpFoundation component defines an object-oriented layer for the HTTP
|
||||||
|
specification.
|
||||||
|
|
||||||
|
Resources
|
||||||
|
---------
|
||||||
|
|
||||||
|
* [Documentation](https://symfony.com/doc/current/components/http_foundation.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)
|
||||||
81
vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php
vendored
Normal file
81
vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RateLimiter;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\RateLimiter\LimiterInterface;
|
||||||
|
use Symfony\Component\RateLimiter\Policy\NoLimiter;
|
||||||
|
use Symfony\Component\RateLimiter\RateLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of PeekableRequestRateLimiterInterface that
|
||||||
|
* fits most use-cases.
|
||||||
|
*
|
||||||
|
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||||
|
*/
|
||||||
|
abstract class AbstractRequestRateLimiter implements PeekableRequestRateLimiterInterface
|
||||||
|
{
|
||||||
|
public function consume(Request $request): RateLimit
|
||||||
|
{
|
||||||
|
return $this->doConsume($request, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function peek(Request $request): RateLimit
|
||||||
|
{
|
||||||
|
return $this->doConsume($request, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function doConsume(Request $request, int $tokens): RateLimit
|
||||||
|
{
|
||||||
|
$limiters = $this->getLimiters($request);
|
||||||
|
if (0 === \count($limiters)) {
|
||||||
|
$limiters = [new NoLimiter()];
|
||||||
|
}
|
||||||
|
|
||||||
|
$minimalRateLimit = null;
|
||||||
|
foreach ($limiters as $limiter) {
|
||||||
|
$rateLimit = $limiter->consume($tokens);
|
||||||
|
|
||||||
|
$minimalRateLimit = $minimalRateLimit ? self::getMinimalRateLimit($minimalRateLimit, $rateLimit) : $rateLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $minimalRateLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reset(Request $request): void
|
||||||
|
{
|
||||||
|
foreach ($this->getLimiters($request) as $limiter) {
|
||||||
|
$limiter->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return LimiterInterface[] a set of limiters using keys extracted from the request
|
||||||
|
*/
|
||||||
|
abstract protected function getLimiters(Request $request): array;
|
||||||
|
|
||||||
|
private static function getMinimalRateLimit(RateLimit $first, RateLimit $second): RateLimit
|
||||||
|
{
|
||||||
|
if ($first->isAccepted() !== $second->isAccepted()) {
|
||||||
|
return $first->isAccepted() ? $second : $first;
|
||||||
|
}
|
||||||
|
|
||||||
|
$firstRemainingTokens = $first->getRemainingTokens();
|
||||||
|
$secondRemainingTokens = $second->getRemainingTokens();
|
||||||
|
|
||||||
|
if ($firstRemainingTokens === $secondRemainingTokens) {
|
||||||
|
return $first->getRetryAfter() < $second->getRetryAfter() ? $second : $first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $firstRemainingTokens > $secondRemainingTokens ? $second : $first;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php
vendored
Normal file
35
vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RateLimiter;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\RateLimiter\RateLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A request limiter which allows peeking ahead.
|
||||||
|
*
|
||||||
|
* This is valuable to reduce the cache backend load in scenarios
|
||||||
|
* like a login when we only want to consume a token on login failure,
|
||||||
|
* and where the majority of requests will be successful and thus not
|
||||||
|
* need to consume a token.
|
||||||
|
*
|
||||||
|
* This way we can peek ahead before allowing the request through, and
|
||||||
|
* only consume if the request failed (1 backend op). This is compared
|
||||||
|
* to always consuming and then resetting the limit if the request
|
||||||
|
* is successful (2 backend ops).
|
||||||
|
*
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*/
|
||||||
|
interface PeekableRequestRateLimiterInterface extends RequestRateLimiterInterface
|
||||||
|
{
|
||||||
|
public function peek(Request $request): RateLimit;
|
||||||
|
}
|
||||||
30
vendor/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php
vendored
Normal file
30
vendor/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RateLimiter;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\RateLimiter\RateLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special type of limiter that deals with requests.
|
||||||
|
*
|
||||||
|
* This allows to limit on different types of information
|
||||||
|
* from the requests.
|
||||||
|
*
|
||||||
|
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||||
|
*/
|
||||||
|
interface RequestRateLimiterInterface
|
||||||
|
{
|
||||||
|
public function consume(Request $request): RateLimit;
|
||||||
|
|
||||||
|
public function reset(Request $request): void;
|
||||||
|
}
|
||||||
92
vendor/symfony/http-foundation/RedirectResponse.php
vendored
Normal file
92
vendor/symfony/http-foundation/RedirectResponse.php
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RedirectResponse represents an HTTP response doing a redirect.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class RedirectResponse extends Response
|
||||||
|
{
|
||||||
|
protected string $targetUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a redirect response so that it conforms to the rules defined for a redirect status code.
|
||||||
|
*
|
||||||
|
* @param string $url The URL to redirect to. The URL should be a full URL, with schema etc.,
|
||||||
|
* but practically every browser redirects on paths only as well
|
||||||
|
* @param int $status The HTTP status code (302 "Found" by default)
|
||||||
|
* @param array $headers The headers (Location is always set to the given URL)
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @see https://tools.ietf.org/html/rfc2616#section-10.3
|
||||||
|
*/
|
||||||
|
public function __construct(string $url, int $status = 302, array $headers = [])
|
||||||
|
{
|
||||||
|
parent::__construct('', $status, $headers);
|
||||||
|
|
||||||
|
$this->setTargetUrl($url);
|
||||||
|
|
||||||
|
if (!$this->isRedirect()) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('The HTTP status code is not a redirect ("%s" given).', $status));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (301 == $status && !\array_key_exists('cache-control', array_change_key_case($headers, \CASE_LOWER))) {
|
||||||
|
$this->headers->remove('cache-control');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the target URL.
|
||||||
|
*/
|
||||||
|
public function getTargetUrl(): string
|
||||||
|
{
|
||||||
|
return $this->targetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the redirect target of this response.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setTargetUrl(string $url): static
|
||||||
|
{
|
||||||
|
if ('' === $url) {
|
||||||
|
throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->targetUrl = $url;
|
||||||
|
|
||||||
|
$this->setContent(
|
||||||
|
\sprintf('<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="refresh" content="0;url=\'%1$s\'" />
|
||||||
|
|
||||||
|
<title>Redirecting to %1$s</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Redirecting to <a href="%1$s">%1$s</a>.
|
||||||
|
</body>
|
||||||
|
</html>', htmlspecialchars($url, \ENT_QUOTES, 'UTF-8')));
|
||||||
|
|
||||||
|
$this->headers->set('Location', $url);
|
||||||
|
$this->headers->set('Content-Type', 'text/html; charset=utf-8');
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
2214
vendor/symfony/http-foundation/Request.php
vendored
Normal file
2214
vendor/symfony/http-foundation/Request.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
45
vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php
vendored
Normal file
45
vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the Request attributes matches all regular expressions.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class AttributesRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param array<string, string> $regexps
|
||||||
|
*/
|
||||||
|
public function __construct(private array $regexps)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
foreach ($this->regexps as $key => $regexp) {
|
||||||
|
$attribute = $request->attributes->get($key);
|
||||||
|
if (!\is_string($attribute)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!preg_match('{'.$regexp.'}', $attribute)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php
vendored
Normal file
43
vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\ExpressionLanguage\Expression;
|
||||||
|
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ExpressionRequestMatcher uses an expression to match a Request.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class ExpressionRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private ExpressionLanguage $language,
|
||||||
|
private Expression|string $expression,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
return $this->language->evaluate($this->expression, [
|
||||||
|
'request' => $request,
|
||||||
|
'method' => $request->getMethod(),
|
||||||
|
'path' => rawurldecode($request->getPathInfo()),
|
||||||
|
'host' => $request->getHost(),
|
||||||
|
'ip' => $request->getClientIp(),
|
||||||
|
'attributes' => $request->attributes->all(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
vendor/symfony/http-foundation/RequestMatcher/HeaderRequestMatcher.php
vendored
Normal file
52
vendor/symfony/http-foundation/RequestMatcher/HeaderRequestMatcher.php
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the presence of HTTP headers in a Request.
|
||||||
|
*
|
||||||
|
* @author Alexandre Daubois <alex.daubois@gmail.com>
|
||||||
|
*/
|
||||||
|
class HeaderRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private array $headers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[]|string $headers A header or a list of headers
|
||||||
|
* Strings can contain a comma-delimited list of headers
|
||||||
|
*/
|
||||||
|
public function __construct(array|string $headers)
|
||||||
|
{
|
||||||
|
$this->headers = array_reduce((array) $headers, static fn (array $headers, string $header) => array_merge($headers, preg_split('/\s*,\s*/', $header)), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
if (!$this->headers) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->headers as $header) {
|
||||||
|
if (!$request->headers->has($header)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php
vendored
Normal file
32
vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the Request URL host name matches a regular expression.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class HostRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
public function __construct(private string $regexp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
return preg_match('{'.$this->regexp.'}i', $request->getHost());
|
||||||
|
}
|
||||||
|
}
|
||||||
44
vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php
vendored
Normal file
44
vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\IpUtils;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the client IP of a Request.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class IpsRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
private array $ips;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[]|string $ips A specific IP address or a range specified using IP/netmask like 192.168.1.0/24
|
||||||
|
* Strings can contain a comma-delimited list of IPs/ranges
|
||||||
|
*/
|
||||||
|
public function __construct(array|string $ips)
|
||||||
|
{
|
||||||
|
$this->ips = array_reduce((array) $ips, static fn (array $ips, string $ip) => array_merge($ips, preg_split('/\s*,\s*/', $ip)), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
if (!$this->ips) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IpUtils::checkIp($request->getClientIp() ?? '', $this->ips);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php
vendored
Normal file
28
vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the Request content is valid JSON.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class IsJsonRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
return json_validate($request->getContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
46
vendor/symfony/http-foundation/RequestMatcher/MethodRequestMatcher.php
vendored
Normal file
46
vendor/symfony/http-foundation/RequestMatcher/MethodRequestMatcher.php
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the HTTP method of a Request.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class MethodRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private array $methods = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[]|string $methods An HTTP method or an array of HTTP methods
|
||||||
|
* Strings can contain a comma-delimited list of methods
|
||||||
|
*/
|
||||||
|
public function __construct(array|string $methods)
|
||||||
|
{
|
||||||
|
$this->methods = array_reduce(array_map('strtoupper', (array) $methods), static fn (array $methods, string $method) => array_merge($methods, preg_split('/\s*,\s*/', $method)), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
if (!$this->methods) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return \in_array($request->getMethod(), $this->methods, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php
vendored
Normal file
32
vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the Request URL path info matches a regular expression.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class PathRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
public function __construct(private string $regexp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
return preg_match('{'.$this->regexp.'}', rawurldecode($request->getPathInfo()));
|
||||||
|
}
|
||||||
|
}
|
||||||
32
vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php
vendored
Normal file
32
vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the HTTP port of a Request.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class PortRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
public function __construct(private int $port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
return $request->getPort() === $this->port;
|
||||||
|
}
|
||||||
|
}
|
||||||
46
vendor/symfony/http-foundation/RequestMatcher/QueryParameterRequestMatcher.php
vendored
Normal file
46
vendor/symfony/http-foundation/RequestMatcher/QueryParameterRequestMatcher.php
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the presence of HTTP query parameters of a Request.
|
||||||
|
*
|
||||||
|
* @author Alexandre Daubois <alex.daubois@gmail.com>
|
||||||
|
*/
|
||||||
|
class QueryParameterRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private array $parameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[]|string $parameters A parameter or a list of parameters
|
||||||
|
* Strings can contain a comma-delimited list of query parameters
|
||||||
|
*/
|
||||||
|
public function __construct(array|string $parameters)
|
||||||
|
{
|
||||||
|
$this->parameters = array_reduce(array_map(strtolower(...), (array) $parameters), static fn (array $parameters, string $parameter) => array_merge($parameters, preg_split('/\s*,\s*/', $parameter)), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
if (!$this->parameters) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 === \count(array_diff_assoc($this->parameters, $request->query->keys()));
|
||||||
|
}
|
||||||
|
}
|
||||||
46
vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php
vendored
Normal file
46
vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\RequestMatcher;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the HTTP scheme of a Request.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class SchemeRequestMatcher implements RequestMatcherInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private array $schemes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[]|string $schemes A scheme or a list of schemes
|
||||||
|
* Strings can contain a comma-delimited list of schemes
|
||||||
|
*/
|
||||||
|
public function __construct(array|string $schemes)
|
||||||
|
{
|
||||||
|
$this->schemes = array_reduce(array_map('strtolower', (array) $schemes), static fn (array $schemes, string $scheme) => array_merge($schemes, preg_split('/\s*,\s*/', $scheme)), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matches(Request $request): bool
|
||||||
|
{
|
||||||
|
if (!$this->schemes) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return \in_array($request->getScheme(), $this->schemes, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
vendor/symfony/http-foundation/RequestMatcherInterface.php
vendored
Normal file
25
vendor/symfony/http-foundation/RequestMatcherInterface.php
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RequestMatcherInterface is an interface for strategies to match a Request.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
interface RequestMatcherInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Decides whether the rule(s) implemented by the strategy matches the supplied request.
|
||||||
|
*/
|
||||||
|
public function matches(Request $request): bool;
|
||||||
|
}
|
||||||
124
vendor/symfony/http-foundation/RequestStack.php
vendored
Normal file
124
vendor/symfony/http-foundation/RequestStack.php
vendored
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request stack that controls the lifecycle of requests.
|
||||||
|
*
|
||||||
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
|
*/
|
||||||
|
class RequestStack
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Request[]
|
||||||
|
*/
|
||||||
|
private array $requests = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request[] $requests
|
||||||
|
*/
|
||||||
|
public function __construct(array $requests = [])
|
||||||
|
{
|
||||||
|
foreach ($requests as $request) {
|
||||||
|
$this->push($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes a Request on the stack.
|
||||||
|
*
|
||||||
|
* This method should generally not be called directly as the stack
|
||||||
|
* management should be taken care of by the application itself.
|
||||||
|
*/
|
||||||
|
public function push(Request $request): void
|
||||||
|
{
|
||||||
|
$this->requests[] = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pops the current request from the stack.
|
||||||
|
*
|
||||||
|
* This operation lets the current request go out of scope.
|
||||||
|
*
|
||||||
|
* This method should generally not be called directly as the stack
|
||||||
|
* management should be taken care of by the application itself.
|
||||||
|
*/
|
||||||
|
public function pop(): ?Request
|
||||||
|
{
|
||||||
|
if (!$this->requests) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_pop($this->requests);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCurrentRequest(): ?Request
|
||||||
|
{
|
||||||
|
return end($this->requests) ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the main request.
|
||||||
|
*
|
||||||
|
* Be warned that making your code aware of the main request
|
||||||
|
* might make it un-compatible with other features of your framework
|
||||||
|
* like ESI support.
|
||||||
|
*/
|
||||||
|
public function getMainRequest(): ?Request
|
||||||
|
{
|
||||||
|
if (!$this->requests) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->requests[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parent request of the current.
|
||||||
|
*
|
||||||
|
* Be warned that making your code aware of the parent request
|
||||||
|
* might make it un-compatible with other features of your framework
|
||||||
|
* like ESI support.
|
||||||
|
*
|
||||||
|
* If current Request is the main request, it returns null.
|
||||||
|
*/
|
||||||
|
public function getParentRequest(): ?Request
|
||||||
|
{
|
||||||
|
$pos = \count($this->requests) - 2;
|
||||||
|
|
||||||
|
return $this->requests[$pos] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current session.
|
||||||
|
*
|
||||||
|
* @throws SessionNotFoundException
|
||||||
|
*/
|
||||||
|
public function getSession(): SessionInterface
|
||||||
|
{
|
||||||
|
if ((null !== $request = end($this->requests) ?: null) && $request->hasSession()) {
|
||||||
|
return $request->getSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new SessionNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resetRequestFormats(): void
|
||||||
|
{
|
||||||
|
static $resetRequestFormats;
|
||||||
|
$resetRequestFormats ??= \Closure::bind(static fn () => self::$formats = null, null, Request::class);
|
||||||
|
$resetRequestFormats();
|
||||||
|
}
|
||||||
|
}
|
||||||
1322
vendor/symfony/http-foundation/Response.php
vendored
Normal file
1322
vendor/symfony/http-foundation/Response.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
267
vendor/symfony/http-foundation/ResponseHeaderBag.php
vendored
Normal file
267
vendor/symfony/http-foundation/ResponseHeaderBag.php
vendored
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ResponseHeaderBag is a container for Response HTTP headers.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class ResponseHeaderBag extends HeaderBag
|
||||||
|
{
|
||||||
|
public const COOKIES_FLAT = 'flat';
|
||||||
|
public const COOKIES_ARRAY = 'array';
|
||||||
|
|
||||||
|
public const DISPOSITION_ATTACHMENT = 'attachment';
|
||||||
|
public const DISPOSITION_INLINE = 'inline';
|
||||||
|
|
||||||
|
protected array $computedCacheControl = [];
|
||||||
|
protected array $cookies = [];
|
||||||
|
protected array $headerNames = [];
|
||||||
|
|
||||||
|
public function __construct(array $headers = [])
|
||||||
|
{
|
||||||
|
parent::__construct($headers);
|
||||||
|
|
||||||
|
if (!isset($this->headers['cache-control'])) {
|
||||||
|
$this->set('Cache-Control', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RFC2616 - 14.18 says all Responses need to have a Date */
|
||||||
|
if (!isset($this->headers['date'])) {
|
||||||
|
$this->initDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the headers, with original capitalizations.
|
||||||
|
*/
|
||||||
|
public function allPreserveCase(): array
|
||||||
|
{
|
||||||
|
$headers = [];
|
||||||
|
foreach ($this->all() as $name => $value) {
|
||||||
|
$headers[$this->headerNames[$name] ?? $name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function allPreserveCaseWithoutCookies(): array
|
||||||
|
{
|
||||||
|
$headers = $this->allPreserveCase();
|
||||||
|
if (isset($this->headerNames['set-cookie'])) {
|
||||||
|
unset($headers[$this->headerNames['set-cookie']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function replace(array $headers = []): void
|
||||||
|
{
|
||||||
|
$this->headerNames = [];
|
||||||
|
|
||||||
|
parent::replace($headers);
|
||||||
|
|
||||||
|
if (!isset($this->headers['cache-control'])) {
|
||||||
|
$this->set('Cache-Control', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->headers['date'])) {
|
||||||
|
$this->initDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(?string $key = null): array
|
||||||
|
{
|
||||||
|
$headers = parent::all();
|
||||||
|
|
||||||
|
if (null !== $key) {
|
||||||
|
$key = strtr($key, self::UPPER, self::LOWER);
|
||||||
|
|
||||||
|
return 'set-cookie' !== $key ? $headers[$key] ?? [] : array_map('strval', $this->getCookies());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->getCookies() as $cookie) {
|
||||||
|
$headers['set-cookie'][] = (string) $cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, string|array|null $values, bool $replace = true): void
|
||||||
|
{
|
||||||
|
$uniqueKey = strtr($key, self::UPPER, self::LOWER);
|
||||||
|
|
||||||
|
if ('set-cookie' === $uniqueKey) {
|
||||||
|
if ($replace) {
|
||||||
|
$this->cookies = [];
|
||||||
|
}
|
||||||
|
foreach ((array) $values as $cookie) {
|
||||||
|
$this->setCookie(Cookie::fromString($cookie));
|
||||||
|
}
|
||||||
|
$this->headerNames[$uniqueKey] = $key;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->headerNames[$uniqueKey] = $key;
|
||||||
|
|
||||||
|
parent::set($key, $values, $replace);
|
||||||
|
|
||||||
|
// ensure the cache-control header has sensible defaults
|
||||||
|
if (\in_array($uniqueKey, ['cache-control', 'etag', 'last-modified', 'expires'], true) && '' !== $computed = $this->computeCacheControlValue()) {
|
||||||
|
$this->headers['cache-control'] = [$computed];
|
||||||
|
$this->headerNames['cache-control'] = 'Cache-Control';
|
||||||
|
$this->computedCacheControl = $this->parseCacheControl($computed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove(string $key): void
|
||||||
|
{
|
||||||
|
$uniqueKey = strtr($key, self::UPPER, self::LOWER);
|
||||||
|
unset($this->headerNames[$uniqueKey]);
|
||||||
|
|
||||||
|
if ('set-cookie' === $uniqueKey) {
|
||||||
|
$this->cookies = [];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::remove($key);
|
||||||
|
|
||||||
|
if ('cache-control' === $uniqueKey) {
|
||||||
|
$this->computedCacheControl = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('date' === $uniqueKey) {
|
||||||
|
$this->initDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasCacheControlDirective(string $key): bool
|
||||||
|
{
|
||||||
|
return \array_key_exists($key, $this->computedCacheControl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCacheControlDirective(string $key): bool|string|null
|
||||||
|
{
|
||||||
|
return $this->computedCacheControl[$key] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCookie(Cookie $cookie): void
|
||||||
|
{
|
||||||
|
$this->cookies[$cookie->getDomain() ?? ''][$cookie->getPath()][$cookie->getName()] = $cookie;
|
||||||
|
$this->headerNames['set-cookie'] = 'Set-Cookie';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a cookie from the array, but does not unset it in the browser.
|
||||||
|
*/
|
||||||
|
public function removeCookie(string $name, ?string $path = '/', ?string $domain = null): void
|
||||||
|
{
|
||||||
|
$path ??= '/';
|
||||||
|
|
||||||
|
unset($this->cookies[$domain ?? ''][$path][$name]);
|
||||||
|
|
||||||
|
if (empty($this->cookies[$domain ?? ''][$path])) {
|
||||||
|
unset($this->cookies[$domain ?? ''][$path]);
|
||||||
|
|
||||||
|
if (empty($this->cookies[$domain ?? ''])) {
|
||||||
|
unset($this->cookies[$domain ?? '']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->cookies) {
|
||||||
|
unset($this->headerNames['set-cookie']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array with all cookies.
|
||||||
|
*
|
||||||
|
* @return Cookie[]
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException When the $format is invalid
|
||||||
|
*/
|
||||||
|
public function getCookies(string $format = self::COOKIES_FLAT): array
|
||||||
|
{
|
||||||
|
if (!\in_array($format, [self::COOKIES_FLAT, self::COOKIES_ARRAY], true)) {
|
||||||
|
throw new \InvalidArgumentException(\sprintf('Format "%s" invalid (%s).', $format, implode(', ', [self::COOKIES_FLAT, self::COOKIES_ARRAY])));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::COOKIES_ARRAY === $format) {
|
||||||
|
return $this->cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
$flattenedCookies = [];
|
||||||
|
foreach ($this->cookies as $path) {
|
||||||
|
foreach ($path as $cookies) {
|
||||||
|
foreach ($cookies as $cookie) {
|
||||||
|
$flattenedCookies[] = $cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $flattenedCookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears a cookie in the browser.
|
||||||
|
*/
|
||||||
|
public function clearCookie(string $name, ?string $path = '/', ?string $domain = null, bool $secure = false, bool $httpOnly = true, ?string $sameSite = null, bool $partitioned = false): void
|
||||||
|
{
|
||||||
|
$this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, $sameSite, $partitioned));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see HeaderUtils::makeDisposition()
|
||||||
|
*/
|
||||||
|
public function makeDisposition(string $disposition, string $filename, string $filenameFallback = ''): string
|
||||||
|
{
|
||||||
|
return HeaderUtils::makeDisposition($disposition, $filename, $filenameFallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the calculated value of the cache-control header.
|
||||||
|
*
|
||||||
|
* This considers several other headers and calculates or modifies the
|
||||||
|
* cache-control header to a sensible, conservative value.
|
||||||
|
*/
|
||||||
|
protected function computeCacheControlValue(): string
|
||||||
|
{
|
||||||
|
if (!$this->cacheControl) {
|
||||||
|
if ($this->has('Last-Modified') || $this->has('Expires')) {
|
||||||
|
return 'private, must-revalidate'; // allows for heuristic expiration (RFC 7234 Section 4.2.2) in the case of "Last-Modified"
|
||||||
|
}
|
||||||
|
|
||||||
|
// conservative by default
|
||||||
|
return 'no-cache, private';
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = $this->getCacheControlHeader();
|
||||||
|
if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) {
|
||||||
|
return $header;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public if s-maxage is defined, private otherwise
|
||||||
|
if (!isset($this->cacheControl['s-maxage'])) {
|
||||||
|
return $header.', private';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $header;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initDate(): void
|
||||||
|
{
|
||||||
|
$this->set('Date', gmdate('D, d M Y H:i:s').' GMT');
|
||||||
|
}
|
||||||
|
}
|
||||||
97
vendor/symfony/http-foundation/ServerBag.php
vendored
Normal file
97
vendor/symfony/http-foundation/ServerBag.php
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ServerBag is a container for HTTP headers from the $_SERVER variable.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||||
|
* @author Robert Kiss <kepten@gmail.com>
|
||||||
|
*/
|
||||||
|
class ServerBag extends ParameterBag
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Gets the HTTP headers.
|
||||||
|
*/
|
||||||
|
public function getHeaders(): array
|
||||||
|
{
|
||||||
|
$headers = [];
|
||||||
|
foreach ($this->parameters as $key => $value) {
|
||||||
|
if (str_starts_with($key, 'HTTP_')) {
|
||||||
|
$headers[substr($key, 5)] = $value;
|
||||||
|
} elseif (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true) && '' !== $value) {
|
||||||
|
$headers[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->parameters['PHP_AUTH_USER'])) {
|
||||||
|
$headers['PHP_AUTH_USER'] = $this->parameters['PHP_AUTH_USER'];
|
||||||
|
$headers['PHP_AUTH_PW'] = $this->parameters['PHP_AUTH_PW'] ?? '';
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default
|
||||||
|
* For this workaround to work, add these lines to your .htaccess file:
|
||||||
|
* RewriteCond %{HTTP:Authorization} .+
|
||||||
|
* RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
|
||||||
|
*
|
||||||
|
* A sample .htaccess file:
|
||||||
|
* RewriteEngine On
|
||||||
|
* RewriteCond %{HTTP:Authorization} .+
|
||||||
|
* RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
|
||||||
|
* RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
* RewriteRule ^(.*)$ index.php [QSA,L]
|
||||||
|
*/
|
||||||
|
|
||||||
|
$authorizationHeader = null;
|
||||||
|
if (isset($this->parameters['HTTP_AUTHORIZATION'])) {
|
||||||
|
$authorizationHeader = $this->parameters['HTTP_AUTHORIZATION'];
|
||||||
|
} elseif (isset($this->parameters['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||||
|
$authorizationHeader = $this->parameters['REDIRECT_HTTP_AUTHORIZATION'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $authorizationHeader) {
|
||||||
|
if (0 === stripos($authorizationHeader, 'basic ')) {
|
||||||
|
// Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic
|
||||||
|
$exploded = explode(':', base64_decode(substr($authorizationHeader, 6)), 2);
|
||||||
|
if (2 == \count($exploded)) {
|
||||||
|
[$headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']] = $exploded;
|
||||||
|
}
|
||||||
|
} elseif (empty($this->parameters['PHP_AUTH_DIGEST']) && (0 === stripos($authorizationHeader, 'digest '))) {
|
||||||
|
// In some circumstances PHP_AUTH_DIGEST needs to be set
|
||||||
|
$headers['PHP_AUTH_DIGEST'] = $authorizationHeader;
|
||||||
|
$this->parameters['PHP_AUTH_DIGEST'] = $authorizationHeader;
|
||||||
|
} elseif (0 === stripos($authorizationHeader, 'bearer ')) {
|
||||||
|
/*
|
||||||
|
* XXX: Since there is no PHP_AUTH_BEARER in PHP predefined variables,
|
||||||
|
* I'll just set $headers['AUTHORIZATION'] here.
|
||||||
|
* https://php.net/reserved.variables.server
|
||||||
|
*/
|
||||||
|
$headers['AUTHORIZATION'] = $authorizationHeader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($headers['AUTHORIZATION'])) {
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHP_AUTH_USER/PHP_AUTH_PW
|
||||||
|
if (isset($headers['PHP_AUTH_USER'])) {
|
||||||
|
$headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.($headers['PHP_AUTH_PW'] ?? ''));
|
||||||
|
} elseif (isset($headers['PHP_AUTH_DIGEST'])) {
|
||||||
|
$headers['AUTHORIZATION'] = $headers['PHP_AUTH_DIGEST'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
145
vendor/symfony/http-foundation/ServerEvent.php
vendored
Normal file
145
vendor/symfony/http-foundation/ServerEvent.php
vendored
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event generated on the server intended for streaming to the client
|
||||||
|
* as part of the SSE streaming technique.
|
||||||
|
*
|
||||||
|
* @implements \IteratorAggregate<string>
|
||||||
|
*
|
||||||
|
* @author Yonel Ceruto <open@yceruto.dev>
|
||||||
|
*/
|
||||||
|
class ServerEvent implements \IteratorAggregate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string|iterable<string> $data The event data field for the message
|
||||||
|
* @param string|null $type The event type
|
||||||
|
* @param int|null $retry The number of milliseconds the client should wait
|
||||||
|
* before reconnecting in case of network failure
|
||||||
|
* @param string|null $id The event ID to set the EventSource object's last event ID value
|
||||||
|
* @param string|null $comment The event comment
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private string|iterable $data,
|
||||||
|
private ?string $type = null,
|
||||||
|
private ?int $retry = null,
|
||||||
|
private ?string $id = null,
|
||||||
|
private ?string $comment = null,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData(): iterable|string
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setData(iterable|string $data): static
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): ?string
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setType(string $type): static
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRetry(): ?int
|
||||||
|
{
|
||||||
|
return $this->retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setRetry(?int $retry): static
|
||||||
|
{
|
||||||
|
$this->retry = $retry;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): ?string
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setId(string $id): static
|
||||||
|
{
|
||||||
|
$this->id = $id;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComment(): ?string
|
||||||
|
{
|
||||||
|
return $this->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setComment(string $comment): static
|
||||||
|
{
|
||||||
|
$this->comment = $comment;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Traversable<string>
|
||||||
|
*/
|
||||||
|
public function getIterator(): \Traversable
|
||||||
|
{
|
||||||
|
static $lastRetry = null;
|
||||||
|
|
||||||
|
$head = '';
|
||||||
|
if ($this->comment) {
|
||||||
|
$head .= \sprintf(': %s', $this->comment)."\n";
|
||||||
|
}
|
||||||
|
if ($this->id) {
|
||||||
|
$head .= \sprintf('id: %s', $this->id)."\n";
|
||||||
|
}
|
||||||
|
if ($this->retry > 0 && $this->retry !== $lastRetry) {
|
||||||
|
$head .= \sprintf('retry: %s', $lastRetry = $this->retry)."\n";
|
||||||
|
}
|
||||||
|
if ($this->type) {
|
||||||
|
$head .= \sprintf('event: %s', $this->type)."\n";
|
||||||
|
}
|
||||||
|
yield $head;
|
||||||
|
|
||||||
|
if (is_iterable($this->data)) {
|
||||||
|
foreach ($this->data as $data) {
|
||||||
|
yield \sprintf('data: %s', $data)."\n";
|
||||||
|
}
|
||||||
|
} elseif ('' !== $this->data) {
|
||||||
|
yield \sprintf('data: %s', $this->data)."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
yield "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
117
vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php
vendored
Normal file
117
vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session\Attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class relates to session attribute storage.
|
||||||
|
*
|
||||||
|
* @implements \IteratorAggregate<string, mixed>
|
||||||
|
*/
|
||||||
|
class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Countable
|
||||||
|
{
|
||||||
|
protected array $attributes = [];
|
||||||
|
|
||||||
|
private string $name = 'attributes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $storageKey The key used to store attributes in the session
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private string $storageKey = '_sf2_attributes',
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(string $name): void
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initialize(array &$attributes): void
|
||||||
|
{
|
||||||
|
$this->attributes = &$attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStorageKey(): string
|
||||||
|
{
|
||||||
|
return $this->storageKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has(string $name): bool
|
||||||
|
{
|
||||||
|
return \array_key_exists($name, $this->attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $name, mixed $default = null): mixed
|
||||||
|
{
|
||||||
|
return \array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $name, mixed $value): void
|
||||||
|
{
|
||||||
|
$this->attributes[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(): array
|
||||||
|
{
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function replace(array $attributes): void
|
||||||
|
{
|
||||||
|
$this->attributes = [];
|
||||||
|
foreach ($attributes as $key => $value) {
|
||||||
|
$this->set($key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove(string $name): mixed
|
||||||
|
{
|
||||||
|
$retval = null;
|
||||||
|
if (\array_key_exists($name, $this->attributes)) {
|
||||||
|
$retval = $this->attributes[$name];
|
||||||
|
unset($this->attributes[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear(): mixed
|
||||||
|
{
|
||||||
|
$return = $this->attributes;
|
||||||
|
$this->attributes = [];
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator for attributes.
|
||||||
|
*
|
||||||
|
* @return \ArrayIterator<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getIterator(): \ArrayIterator
|
||||||
|
{
|
||||||
|
return new \ArrayIterator($this->attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of attributes.
|
||||||
|
*/
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return \count($this->attributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php
vendored
Normal file
53
vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session\Attribute;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attributes store.
|
||||||
|
*
|
||||||
|
* @author Drak <drak@zikula.org>
|
||||||
|
*/
|
||||||
|
interface AttributeBagInterface extends SessionBagInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Checks if an attribute is defined.
|
||||||
|
*/
|
||||||
|
public function has(string $name): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an attribute.
|
||||||
|
*/
|
||||||
|
public function get(string $name, mixed $default = null): mixed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an attribute.
|
||||||
|
*/
|
||||||
|
public function set(string $name, mixed $value): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns attributes.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function all(): array;
|
||||||
|
|
||||||
|
public function replace(array $attributes): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an attribute.
|
||||||
|
*
|
||||||
|
* @return mixed The removed value or null when it does not exist
|
||||||
|
*/
|
||||||
|
public function remove(string $name): mixed;
|
||||||
|
}
|
||||||
121
vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php
vendored
Normal file
121
vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session\Flash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AutoExpireFlashBag flash message container.
|
||||||
|
*
|
||||||
|
* @author Drak <drak@zikula.org>
|
||||||
|
*/
|
||||||
|
class AutoExpireFlashBag implements FlashBagInterface
|
||||||
|
{
|
||||||
|
private string $name = 'flashes';
|
||||||
|
private array $flashes = ['display' => [], 'new' => []];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $storageKey The key used to store flashes in the session
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private string $storageKey = '_symfony_flashes',
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(string $name): void
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initialize(array &$flashes): void
|
||||||
|
{
|
||||||
|
$this->flashes = &$flashes;
|
||||||
|
|
||||||
|
// The logic: messages from the last request will be stored in new, so we move them to previous
|
||||||
|
// This request we will show what is in 'display'. What is placed into 'new' this time round will
|
||||||
|
// be moved to display next time round.
|
||||||
|
$this->flashes['display'] = \array_key_exists('new', $this->flashes) ? $this->flashes['new'] : [];
|
||||||
|
$this->flashes['new'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add(string $type, mixed $message): void
|
||||||
|
{
|
||||||
|
$this->flashes['new'][$type][] = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function peek(string $type, array $default = []): array
|
||||||
|
{
|
||||||
|
return $this->has($type) ? $this->flashes['display'][$type] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function peekAll(): array
|
||||||
|
{
|
||||||
|
return \array_key_exists('display', $this->flashes) ? $this->flashes['display'] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $type, array $default = []): array
|
||||||
|
{
|
||||||
|
$return = $default;
|
||||||
|
|
||||||
|
if (!$this->has($type)) {
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->flashes['display'][$type])) {
|
||||||
|
$return = $this->flashes['display'][$type];
|
||||||
|
unset($this->flashes['display'][$type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(): array
|
||||||
|
{
|
||||||
|
$return = $this->flashes['display'];
|
||||||
|
$this->flashes['display'] = [];
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAll(array $messages): void
|
||||||
|
{
|
||||||
|
$this->flashes['new'] = $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $type, string|array $messages): void
|
||||||
|
{
|
||||||
|
$this->flashes['new'][$type] = (array) $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has(string $type): bool
|
||||||
|
{
|
||||||
|
return \array_key_exists($type, $this->flashes['display']) && $this->flashes['display'][$type];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function keys(): array
|
||||||
|
{
|
||||||
|
return array_keys($this->flashes['display']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStorageKey(): string
|
||||||
|
{
|
||||||
|
return $this->storageKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear(): mixed
|
||||||
|
{
|
||||||
|
return $this->all();
|
||||||
|
}
|
||||||
|
}
|
||||||
112
vendor/symfony/http-foundation/Session/Flash/FlashBag.php
vendored
Normal file
112
vendor/symfony/http-foundation/Session/Flash/FlashBag.php
vendored
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session\Flash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FlashBag flash message container.
|
||||||
|
*
|
||||||
|
* @author Drak <drak@zikula.org>
|
||||||
|
*/
|
||||||
|
class FlashBag implements FlashBagInterface
|
||||||
|
{
|
||||||
|
private string $name = 'flashes';
|
||||||
|
private array $flashes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $storageKey The key used to store flashes in the session
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private string $storageKey = '_symfony_flashes',
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(string $name): void
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initialize(array &$flashes): void
|
||||||
|
{
|
||||||
|
$this->flashes = &$flashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add(string $type, mixed $message): void
|
||||||
|
{
|
||||||
|
$this->flashes[$type][] = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function peek(string $type, array $default = []): array
|
||||||
|
{
|
||||||
|
return $this->has($type) ? $this->flashes[$type] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function peekAll(): array
|
||||||
|
{
|
||||||
|
return $this->flashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $type, array $default = []): array
|
||||||
|
{
|
||||||
|
if (!$this->has($type)) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = $this->flashes[$type];
|
||||||
|
|
||||||
|
unset($this->flashes[$type]);
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(): array
|
||||||
|
{
|
||||||
|
$return = $this->peekAll();
|
||||||
|
$this->flashes = [];
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $type, string|array $messages): void
|
||||||
|
{
|
||||||
|
$this->flashes[$type] = (array) $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAll(array $messages): void
|
||||||
|
{
|
||||||
|
$this->flashes = $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has(string $type): bool
|
||||||
|
{
|
||||||
|
return \array_key_exists($type, $this->flashes) && $this->flashes[$type];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function keys(): array
|
||||||
|
{
|
||||||
|
return array_keys($this->flashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStorageKey(): string
|
||||||
|
{
|
||||||
|
return $this->storageKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear(): mixed
|
||||||
|
{
|
||||||
|
return $this->all();
|
||||||
|
}
|
||||||
|
}
|
||||||
72
vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php
vendored
Normal file
72
vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session\Flash;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FlashBagInterface.
|
||||||
|
*
|
||||||
|
* @author Drak <drak@zikula.org>
|
||||||
|
*/
|
||||||
|
interface FlashBagInterface extends SessionBagInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Adds a flash message for the given type.
|
||||||
|
*/
|
||||||
|
public function add(string $type, mixed $message): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers one or more messages for a given type.
|
||||||
|
*/
|
||||||
|
public function set(string $type, string|array $messages): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets flash messages for a given type.
|
||||||
|
*
|
||||||
|
* @param string $type Message category type
|
||||||
|
* @param array $default Default value if $type does not exist
|
||||||
|
*/
|
||||||
|
public function peek(string $type, array $default = []): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all flash messages.
|
||||||
|
*/
|
||||||
|
public function peekAll(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets and clears flash from the stack.
|
||||||
|
*
|
||||||
|
* @param array $default Default value if $type does not exist
|
||||||
|
*/
|
||||||
|
public function get(string $type, array $default = []): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets and clears flashes from the stack.
|
||||||
|
*/
|
||||||
|
public function all(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets all flash messages.
|
||||||
|
*/
|
||||||
|
public function setAll(array $messages): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has flash messages for a given type?
|
||||||
|
*/
|
||||||
|
public function has(string $type): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all defined types.
|
||||||
|
*/
|
||||||
|
public function keys(): array;
|
||||||
|
}
|
||||||
22
vendor/symfony/http-foundation/Session/FlashBagAwareSessionInterface.php
vendored
Normal file
22
vendor/symfony/http-foundation/Session/FlashBagAwareSessionInterface.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for session with a flashbag.
|
||||||
|
*/
|
||||||
|
interface FlashBagAwareSessionInterface extends SessionInterface
|
||||||
|
{
|
||||||
|
public function getFlashBag(): FlashBagInterface;
|
||||||
|
}
|
||||||
223
vendor/symfony/http-foundation/Session/Session.php
vendored
Normal file
223
vendor/symfony/http-foundation/Session/Session.php
vendored
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
|
||||||
|
|
||||||
|
// Help opcache.preload discover always-needed symbols
|
||||||
|
class_exists(AttributeBag::class);
|
||||||
|
class_exists(FlashBag::class);
|
||||||
|
class_exists(SessionBagProxy::class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Drak <drak@zikula.org>
|
||||||
|
*
|
||||||
|
* @implements \IteratorAggregate<string, mixed>
|
||||||
|
*/
|
||||||
|
class Session implements FlashBagAwareSessionInterface, \IteratorAggregate, \Countable
|
||||||
|
{
|
||||||
|
protected SessionStorageInterface $storage;
|
||||||
|
|
||||||
|
private string $flashName;
|
||||||
|
private string $attributeName;
|
||||||
|
private array $data = [];
|
||||||
|
private int $usageIndex = 0;
|
||||||
|
private ?\Closure $usageReporter;
|
||||||
|
|
||||||
|
public function __construct(?SessionStorageInterface $storage = null, ?AttributeBagInterface $attributes = null, ?FlashBagInterface $flashes = null, ?callable $usageReporter = null)
|
||||||
|
{
|
||||||
|
$this->storage = $storage ?? new NativeSessionStorage();
|
||||||
|
$this->usageReporter = null === $usageReporter ? null : $usageReporter(...);
|
||||||
|
|
||||||
|
$attributes ??= new AttributeBag();
|
||||||
|
$this->attributeName = $attributes->getName();
|
||||||
|
$this->registerBag($attributes);
|
||||||
|
|
||||||
|
$flashes ??= new FlashBag();
|
||||||
|
$this->flashName = $flashes->getName();
|
||||||
|
$this->registerBag($flashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start(): bool
|
||||||
|
{
|
||||||
|
return $this->storage->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has(string $name): bool
|
||||||
|
{
|
||||||
|
return $this->getAttributeBag()->has($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $name, mixed $default = null): mixed
|
||||||
|
{
|
||||||
|
return $this->getAttributeBag()->get($name, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $name, mixed $value): void
|
||||||
|
{
|
||||||
|
$this->getAttributeBag()->set($name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(): array
|
||||||
|
{
|
||||||
|
return $this->getAttributeBag()->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function replace(array $attributes): void
|
||||||
|
{
|
||||||
|
$this->getAttributeBag()->replace($attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove(string $name): mixed
|
||||||
|
{
|
||||||
|
return $this->getAttributeBag()->remove($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear(): void
|
||||||
|
{
|
||||||
|
$this->getAttributeBag()->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isStarted(): bool
|
||||||
|
{
|
||||||
|
return $this->storage->isStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator for attributes.
|
||||||
|
*
|
||||||
|
* @return \ArrayIterator<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getIterator(): \ArrayIterator
|
||||||
|
{
|
||||||
|
return new \ArrayIterator($this->getAttributeBag()->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of attributes.
|
||||||
|
*/
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return \count($this->getAttributeBag()->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function &getUsageIndex(): int
|
||||||
|
{
|
||||||
|
return $this->usageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public function isEmpty(): bool
|
||||||
|
{
|
||||||
|
if ($this->isStarted()) {
|
||||||
|
++$this->usageIndex;
|
||||||
|
if ($this->usageReporter && 0 <= $this->usageIndex) {
|
||||||
|
($this->usageReporter)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($this->data as &$data) {
|
||||||
|
if ($data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invalidate(?int $lifetime = null): bool
|
||||||
|
{
|
||||||
|
$this->storage->clear();
|
||||||
|
|
||||||
|
return $this->migrate(true, $lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function migrate(bool $destroy = false, ?int $lifetime = null): bool
|
||||||
|
{
|
||||||
|
return $this->storage->regenerate($destroy, $lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(): void
|
||||||
|
{
|
||||||
|
$this->storage->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): string
|
||||||
|
{
|
||||||
|
return $this->storage->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setId(string $id): void
|
||||||
|
{
|
||||||
|
if ($this->storage->getId() !== $id) {
|
||||||
|
$this->storage->setId($id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->storage->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(string $name): void
|
||||||
|
{
|
||||||
|
$this->storage->setName($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataBag(): MetadataBag
|
||||||
|
{
|
||||||
|
++$this->usageIndex;
|
||||||
|
if ($this->usageReporter && 0 <= $this->usageIndex) {
|
||||||
|
($this->usageReporter)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->storage->getMetadataBag();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerBag(SessionBagInterface $bag): void
|
||||||
|
{
|
||||||
|
$this->storage->registerBag(new SessionBagProxy($bag, $this->data, $this->usageIndex, $this->usageReporter));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBag(string $name): SessionBagInterface
|
||||||
|
{
|
||||||
|
$bag = $this->storage->getBag($name);
|
||||||
|
|
||||||
|
return method_exists($bag, 'getBag') ? $bag->getBag() : $bag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the flashbag interface.
|
||||||
|
*/
|
||||||
|
public function getFlashBag(): FlashBagInterface
|
||||||
|
{
|
||||||
|
return $this->getBag($this->flashName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the attributebag interface.
|
||||||
|
*
|
||||||
|
* Note that this method was added to help with IDE autocompletion.
|
||||||
|
*/
|
||||||
|
private function getAttributeBag(): AttributeBagInterface
|
||||||
|
{
|
||||||
|
return $this->getBag($this->attributeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
vendor/symfony/http-foundation/Session/SessionBagInterface.php
vendored
Normal file
42
vendor/symfony/http-foundation/Session/SessionBagInterface.php
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session Bag store.
|
||||||
|
*
|
||||||
|
* @author Drak <drak@zikula.org>
|
||||||
|
*/
|
||||||
|
interface SessionBagInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Gets this bag's name.
|
||||||
|
*/
|
||||||
|
public function getName(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Bag.
|
||||||
|
*/
|
||||||
|
public function initialize(array &$array): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the storage key for this bag.
|
||||||
|
*/
|
||||||
|
public function getStorageKey(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears out data from bag.
|
||||||
|
*
|
||||||
|
* @return mixed Whatever data was contained
|
||||||
|
*/
|
||||||
|
public function clear(): mixed;
|
||||||
|
}
|
||||||
86
vendor/symfony/http-foundation/Session/SessionBagProxy.php
vendored
Normal file
86
vendor/symfony/http-foundation/Session/SessionBagProxy.php
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class SessionBagProxy implements SessionBagInterface
|
||||||
|
{
|
||||||
|
private array $data;
|
||||||
|
private ?int $usageIndex;
|
||||||
|
private ?\Closure $usageReporter;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private SessionBagInterface $bag,
|
||||||
|
array &$data,
|
||||||
|
?int &$usageIndex,
|
||||||
|
?callable $usageReporter,
|
||||||
|
) {
|
||||||
|
$this->bag = $bag;
|
||||||
|
$this->data = &$data;
|
||||||
|
$this->usageIndex = &$usageIndex;
|
||||||
|
$this->usageReporter = null === $usageReporter ? null : $usageReporter(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBag(): SessionBagInterface
|
||||||
|
{
|
||||||
|
++$this->usageIndex;
|
||||||
|
if ($this->usageReporter && 0 <= $this->usageIndex) {
|
||||||
|
($this->usageReporter)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->bag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmpty(): bool
|
||||||
|
{
|
||||||
|
if (!isset($this->data[$this->bag->getStorageKey()])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++$this->usageIndex;
|
||||||
|
if ($this->usageReporter && 0 <= $this->usageIndex) {
|
||||||
|
($this->usageReporter)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return empty($this->data[$this->bag->getStorageKey()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->bag->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initialize(array &$array): void
|
||||||
|
{
|
||||||
|
++$this->usageIndex;
|
||||||
|
if ($this->usageReporter && 0 <= $this->usageIndex) {
|
||||||
|
($this->usageReporter)();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->data[$this->bag->getStorageKey()] = &$array;
|
||||||
|
|
||||||
|
$this->bag->initialize($array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStorageKey(): string
|
||||||
|
{
|
||||||
|
return $this->bag->getStorageKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear(): mixed
|
||||||
|
{
|
||||||
|
return $this->bag->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
39
vendor/symfony/http-foundation/Session/SessionFactory.php
vendored
Normal file
39
vendor/symfony/http-foundation/Session/SessionFactory.php
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageFactoryInterface;
|
||||||
|
|
||||||
|
// Help opcache.preload discover always-needed symbols
|
||||||
|
class_exists(Session::class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||||
|
*/
|
||||||
|
class SessionFactory implements SessionFactoryInterface
|
||||||
|
{
|
||||||
|
private ?\Closure $usageReporter;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private RequestStack $requestStack,
|
||||||
|
private SessionStorageFactoryInterface $storageFactory,
|
||||||
|
?callable $usageReporter = null,
|
||||||
|
) {
|
||||||
|
$this->usageReporter = null === $usageReporter ? null : $usageReporter(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createSession(): SessionInterface
|
||||||
|
{
|
||||||
|
return new Session($this->storageFactory->createStorage($this->requestStack->getMainRequest()), null, null, $this->usageReporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
vendor/symfony/http-foundation/Session/SessionFactoryInterface.php
vendored
Normal file
20
vendor/symfony/http-foundation/Session/SessionFactoryInterface.php
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kevin Bond <kevinbond@gmail.com>
|
||||||
|
*/
|
||||||
|
interface SessionFactoryInterface
|
||||||
|
{
|
||||||
|
public function createSession(): SessionInterface;
|
||||||
|
}
|
||||||
140
vendor/symfony/http-foundation/Session/SessionInterface.php
vendored
Normal file
140
vendor/symfony/http-foundation/Session/SessionInterface.php
vendored
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for the session.
|
||||||
|
*
|
||||||
|
* @author Drak <drak@zikula.org>
|
||||||
|
*/
|
||||||
|
interface SessionInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Starts the session storage.
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException if session fails to start
|
||||||
|
*/
|
||||||
|
public function start(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the session ID.
|
||||||
|
*/
|
||||||
|
public function getId(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the session ID.
|
||||||
|
*/
|
||||||
|
public function setId(string $id): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the session name.
|
||||||
|
*/
|
||||||
|
public function getName(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the session name.
|
||||||
|
*/
|
||||||
|
public function setName(string $name): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the current session.
|
||||||
|
*
|
||||||
|
* Clears all session attributes and flashes and regenerates the
|
||||||
|
* session and deletes the old session from persistence.
|
||||||
|
*
|
||||||
|
* @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||||
|
* will leave the system settings unchanged, 0 sets the cookie
|
||||||
|
* to expire with browser session. Time is in seconds, and is
|
||||||
|
* not a Unix timestamp.
|
||||||
|
*/
|
||||||
|
public function invalidate(?int $lifetime = null): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrates the current session to a new session id while maintaining all
|
||||||
|
* session attributes.
|
||||||
|
*
|
||||||
|
* @param bool $destroy Whether to delete the old session or leave it to garbage collection
|
||||||
|
* @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||||
|
* will leave the system settings unchanged, 0 sets the cookie
|
||||||
|
* to expire with browser session. Time is in seconds, and is
|
||||||
|
* not a Unix timestamp.
|
||||||
|
*/
|
||||||
|
public function migrate(bool $destroy = false, ?int $lifetime = null): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force the session to be saved and closed.
|
||||||
|
*
|
||||||
|
* This method is generally not required for real sessions as
|
||||||
|
* the session will be automatically saved at the end of
|
||||||
|
* code execution.
|
||||||
|
*/
|
||||||
|
public function save(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an attribute is defined.
|
||||||
|
*/
|
||||||
|
public function has(string $name): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an attribute.
|
||||||
|
*/
|
||||||
|
public function get(string $name, mixed $default = null): mixed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an attribute.
|
||||||
|
*/
|
||||||
|
public function set(string $name, mixed $value): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns attributes.
|
||||||
|
*/
|
||||||
|
public function all(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets attributes.
|
||||||
|
*/
|
||||||
|
public function replace(array $attributes): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an attribute.
|
||||||
|
*
|
||||||
|
* @return mixed The removed value or null when it does not exist
|
||||||
|
*/
|
||||||
|
public function remove(string $name): mixed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all attributes.
|
||||||
|
*/
|
||||||
|
public function clear(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the session was started.
|
||||||
|
*/
|
||||||
|
public function isStarted(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a SessionBagInterface with the session.
|
||||||
|
*/
|
||||||
|
public function registerBag(SessionBagInterface $bag): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a bag instance by name.
|
||||||
|
*/
|
||||||
|
public function getBag(string $name): SessionBagInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets session meta.
|
||||||
|
*/
|
||||||
|
public function getMetadataBag(): MetadataBag;
|
||||||
|
}
|
||||||
59
vendor/symfony/http-foundation/Session/SessionUtils.php
vendored
Normal file
59
vendor/symfony/http-foundation/Session/SessionUtils.php
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session utility functions.
|
||||||
|
*
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
* @author Rémon van de Kamp <rpkamp@gmail.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class SessionUtils
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Finds the session header amongst the headers that are to be sent, removes it, and returns
|
||||||
|
* it so the caller can process it further.
|
||||||
|
*/
|
||||||
|
public static function popSessionCookie(string $sessionName, #[\SensitiveParameter] string $sessionId): ?string
|
||||||
|
{
|
||||||
|
$sessionCookie = null;
|
||||||
|
$sessionCookiePrefix = \sprintf(' %s=', urlencode($sessionName));
|
||||||
|
$sessionCookieWithId = \sprintf('%s%s;', $sessionCookiePrefix, urlencode($sessionId));
|
||||||
|
$otherCookies = [];
|
||||||
|
foreach (headers_list() as $h) {
|
||||||
|
if (0 !== stripos($h, 'Set-Cookie:')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (11 === strpos($h, $sessionCookiePrefix, 11)) {
|
||||||
|
$sessionCookie = $h;
|
||||||
|
|
||||||
|
if (11 !== strpos($h, $sessionCookieWithId, 11)) {
|
||||||
|
$otherCookies[] = $h;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$otherCookies[] = $h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (null === $sessionCookie) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
header_remove('Set-Cookie');
|
||||||
|
foreach ($otherCookies as $h) {
|
||||||
|
header($h, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sessionCookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
111
vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php
vendored
Normal file
111
vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Session\SessionUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This abstract session handler provides a generic implementation
|
||||||
|
* of the PHP 7.0 SessionUpdateTimestampHandlerInterface,
|
||||||
|
* enabling strict and lazy session handling.
|
||||||
|
*
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
abstract class AbstractSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
|
||||||
|
{
|
||||||
|
private string $sessionName;
|
||||||
|
private string $prefetchId;
|
||||||
|
private string $prefetchData;
|
||||||
|
private ?string $newSessionId = null;
|
||||||
|
private string $igbinaryEmptyData;
|
||||||
|
|
||||||
|
public function open(string $savePath, string $sessionName): bool
|
||||||
|
{
|
||||||
|
$this->sessionName = $sessionName;
|
||||||
|
if (!headers_sent() && !\ini_get('session.cache_limiter') && '0' !== \ini_get('session.cache_limiter')) {
|
||||||
|
header(\sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function doRead(#[\SensitiveParameter] string $sessionId): string;
|
||||||
|
|
||||||
|
abstract protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool;
|
||||||
|
|
||||||
|
abstract protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool;
|
||||||
|
|
||||||
|
public function validateId(#[\SensitiveParameter] string $sessionId): bool
|
||||||
|
{
|
||||||
|
$this->prefetchData = $this->read($sessionId);
|
||||||
|
$this->prefetchId = $sessionId;
|
||||||
|
|
||||||
|
return '' !== $this->prefetchData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read(#[\SensitiveParameter] string $sessionId): string
|
||||||
|
{
|
||||||
|
if (isset($this->prefetchId)) {
|
||||||
|
$prefetchId = $this->prefetchId;
|
||||||
|
$prefetchData = $this->prefetchData;
|
||||||
|
unset($this->prefetchId, $this->prefetchData);
|
||||||
|
|
||||||
|
if ($prefetchId === $sessionId || '' === $prefetchData) {
|
||||||
|
$this->newSessionId = '' === $prefetchData ? $sessionId : null;
|
||||||
|
|
||||||
|
return $prefetchData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->doRead($sessionId);
|
||||||
|
$this->newSessionId = '' === $data ? $sessionId : null;
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(#[\SensitiveParameter] string $sessionId, string $data): bool
|
||||||
|
{
|
||||||
|
// see https://github.com/igbinary/igbinary/issues/146
|
||||||
|
$this->igbinaryEmptyData ??= \function_exists('igbinary_serialize') ? igbinary_serialize([]) : '';
|
||||||
|
if ('' === $data || $this->igbinaryEmptyData === $data) {
|
||||||
|
return $this->destroy($sessionId);
|
||||||
|
}
|
||||||
|
$this->newSessionId = null;
|
||||||
|
|
||||||
|
return $this->doWrite($sessionId, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(#[\SensitiveParameter] string $sessionId): bool
|
||||||
|
{
|
||||||
|
if (!headers_sent() && filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOL)) {
|
||||||
|
if (!isset($this->sessionName)) {
|
||||||
|
throw new \LogicException(\sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class));
|
||||||
|
}
|
||||||
|
$cookie = SessionUtils::popSessionCookie($this->sessionName, $sessionId);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We send an invalidation Set-Cookie header (zero lifetime)
|
||||||
|
* when either the session was started or a cookie with
|
||||||
|
* the session name was sent by the client (in which case
|
||||||
|
* we know it's invalid as a valid session cookie would've
|
||||||
|
* started the session).
|
||||||
|
*/
|
||||||
|
if (null === $cookie || isset($_COOKIE[$this->sessionName])) {
|
||||||
|
$params = session_get_cookie_params();
|
||||||
|
unset($params['lifetime']);
|
||||||
|
setcookie($this->sessionName, '', $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newSessionId === $sessionId || $this->doDestroy($sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
vendor/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php
vendored
Normal file
36
vendor/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
||||||
|
|
||||||
|
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
|
||||||
|
*/
|
||||||
|
class IdentityMarshaller implements MarshallerInterface
|
||||||
|
{
|
||||||
|
public function marshall(array $values, ?array &$failed): array
|
||||||
|
{
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
if (!\is_string($value)) {
|
||||||
|
throw new \LogicException(\sprintf('%s accepts only string as data.', __METHOD__));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unmarshall(string $value): string
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
73
vendor/symfony/http-foundation/Session/Storage/Handler/MarshallingSessionHandler.php
vendored
Normal file
73
vendor/symfony/http-foundation/Session/Storage/Handler/MarshallingSessionHandler.php
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
||||||
|
|
||||||
|
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
|
||||||
|
*/
|
||||||
|
class MarshallingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private AbstractSessionHandler $handler,
|
||||||
|
private MarshallerInterface $marshaller,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function open(string $savePath, string $name): bool
|
||||||
|
{
|
||||||
|
return $this->handler->open($savePath, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close(): bool
|
||||||
|
{
|
||||||
|
return $this->handler->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(#[\SensitiveParameter] string $sessionId): bool
|
||||||
|
{
|
||||||
|
return $this->handler->destroy($sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gc(int $maxlifetime): int|false
|
||||||
|
{
|
||||||
|
return $this->handler->gc($maxlifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read(#[\SensitiveParameter] string $sessionId): string
|
||||||
|
{
|
||||||
|
return $this->marshaller->unmarshall($this->handler->read($sessionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(#[\SensitiveParameter] string $sessionId, string $data): bool
|
||||||
|
{
|
||||||
|
$failed = [];
|
||||||
|
$marshalledData = $this->marshaller->marshall(['data' => $data], $failed);
|
||||||
|
|
||||||
|
if (isset($failed['data'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handler->write($sessionId, $marshalledData['data']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateId(#[\SensitiveParameter] string $sessionId): bool
|
||||||
|
{
|
||||||
|
return $this->handler->validateId($sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool
|
||||||
|
{
|
||||||
|
return $this->handler->updateTimestamp($sessionId, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user