- */
-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(static 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);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/File/Stream.php b/plugins/vendor/symfony/http-foundation/File/Stream.php
deleted file mode 100644
index 2c156b2e..00000000
--- a/plugins/vendor/symfony/http-foundation/File/Stream.php
+++ /dev/null
@@ -1,25 +0,0 @@
-
- *
- * 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
- */
-class Stream extends File
-{
- public function getSize(): int|false
- {
- return false;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/File/UploadedFile.php b/plugins/vendor/symfony/http-foundation/File/UploadedFile.php
deleted file mode 100644
index 09e623c4..00000000
--- a/plugins/vendor/symfony/http-foundation/File/UploadedFile.php
+++ /dev/null
@@ -1,297 +0,0 @@
-
- *
- * 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
- * @author Florian Eckerstorfer
- * @author Fabien Potencier
- */
-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(static 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->getExceptionMessage());
- case \UPLOAD_ERR_FORM_SIZE:
- throw new FormSizeFileException($this->getExceptionMessage());
- case \UPLOAD_ERR_PARTIAL:
- throw new PartialFileException($this->getExceptionMessage());
- case \UPLOAD_ERR_NO_FILE:
- throw new NoFileException($this->getExceptionMessage());
- case \UPLOAD_ERR_CANT_WRITE:
- throw new CannotWriteFileException($this->getExceptionMessage());
- case \UPLOAD_ERR_NO_TMP_DIR:
- throw new NoTmpDirFileException($this->getExceptionMessage());
- case \UPLOAD_ERR_EXTENSION:
- throw new ExtensionFileException($this->getExceptionMessage());
- }
-
- throw new FileException($this->getExceptionMessage());
- }
-
- /**
- * Retrieves a user-friendly error message for file upload issues, if any.
- */
- public function getErrorMessage(): string
- {
- return \UPLOAD_ERR_OK !== $this->error ? $this->getExceptionMessage() : '';
- }
-
- /**
- * 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.
- */
- private function getExceptionMessage(): 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);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/FileBag.php b/plugins/vendor/symfony/http-foundation/FileBag.php
deleted file mode 100644
index 561e7cde..00000000
--- a/plugins/vendor/symfony/http-foundation/FileBag.php
+++ /dev/null
@@ -1,127 +0,0 @@
-
- *
- * 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
- * @author Bulat Shakirzyanov
- */
-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;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/HeaderBag.php b/plugins/vendor/symfony/http-foundation/HeaderBag.php
deleted file mode 100644
index c2ede560..00000000
--- a/plugins/vendor/symfony/http-foundation/HeaderBag.php
+++ /dev/null
@@ -1,273 +0,0 @@
-
- *
- * 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
- *
- * @implements \IteratorAggregate>
- */
-class HeaderBag implements \IteratorAggregate, \Countable, \Stringable
-{
- protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ';
- protected const LOWER = '-abcdefghijklmnopqrstuvwxyz';
-
- /**
- * @var array>
- */
- 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> : list)
- */
- 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>
- */
- 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);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/HeaderUtils.php b/plugins/vendor/symfony/http-foundation/HeaderUtils.php
deleted file mode 100644
index 37953af4..00000000
--- a/plugins/vendor/symfony/http-foundation/HeaderUtils.php
+++ /dev/null
@@ -1,298 +0,0 @@
-
- *
- * 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
- */
-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.']+
- )+
- (?['.$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;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/InputBag.php b/plugins/vendor/symfony/http-foundation/InputBag.php
deleted file mode 100644
index 8c153dc3..00000000
--- a/plugins/vendor/symfony/http-foundation/InputBag.php
+++ /dev/null
@@ -1,152 +0,0 @@
-
- *
- * 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
- */
-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 $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));
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/IpUtils.php b/plugins/vendor/symfony/http-foundation/IpUtils.php
deleted file mode 100644
index fa5e634d..00000000
--- a/plugins/vendor/symfony/http-foundation/IpUtils.php
+++ /dev/null
@@ -1,278 +0,0 @@
-
- *
- * 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
- */
-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-mapped IPv6 addresses (RFC 4291 section 2.5.5.2)
- '::/128', // Unspecified address
- '::/96', // IPv4-compatible IPv6 addresses (RFC 4291 section 2.5.5.1)
- '2002::/16', // 6to4 (RFC 3056)
- '2001::/32', // Teredo tunneling (RFC 4380)
- '64:ff9b::/96', // NAT64 well-known prefix (RFC 6052)
- '64:ff9b:1::/48', // NAT64 local-use prefix (RFC 8215)
- ];
-
- 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
- *
- * @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
- {
- $v4Bytes = 1 < \func_num_args() ? func_get_arg(1) : 1;
- $v6Bytes = 2 < \func_num_args() ? func_get_arg(2) : 8;
-
- 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 = static 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;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/JsonResponse.php b/plugins/vendor/symfony/http-foundation/JsonResponse.php
deleted file mode 100644
index 187173b6..00000000
--- a/plugins/vendor/symfony/http-foundation/JsonResponse.php
+++ /dev/null
@@ -1,187 +0,0 @@
-
- *
- * 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
- */
-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
- $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);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/LICENSE b/plugins/vendor/symfony/http-foundation/LICENSE
deleted file mode 100644
index 0138f8f0..00000000
--- a/plugins/vendor/symfony/http-foundation/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-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.
diff --git a/plugins/vendor/symfony/http-foundation/ParameterBag.php b/plugins/vendor/symfony/http-foundation/ParameterBag.php
deleted file mode 100644
index 5e36cf2f..00000000
--- a/plugins/vendor/symfony/http-foundation/ParameterBag.php
+++ /dev/null
@@ -1,271 +0,0 @@
-
- *
- * 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
- *
- * @implements \IteratorAggregate
- */
-class ParameterBag implements \IteratorAggregate, \Countable
-{
- /**
- * @param array $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 : array)
- *
- * @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
- */
- public function keys(): array
- {
- return array_keys($this->parameters);
- }
-
- /**
- * Replaces the current parameters by a new set.
- *
- * @param array $parameters
- */
- public function replace(array $parameters = []): void
- {
- $this->parameters = $parameters;
- }
-
- /**
- * Adds parameters.
- *
- * @param array $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 $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
- */
- public function getIterator(): \ArrayIterator
- {
- return new \ArrayIterator($this->parameters);
- }
-
- /**
- * Returns the number of parameters.
- */
- public function count(): int
- {
- return \count($this->parameters);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/README.md b/plugins/vendor/symfony/http-foundation/README.md
deleted file mode 100644
index 5cf90074..00000000
--- a/plugins/vendor/symfony/http-foundation/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
-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)
diff --git a/plugins/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php b/plugins/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php
deleted file mode 100644
index 550090f9..00000000
--- a/plugins/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php
+++ /dev/null
@@ -1,81 +0,0 @@
-
- *
- * 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
- */
-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;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php b/plugins/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php
deleted file mode 100644
index 63471af2..00000000
--- a/plugins/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php
+++ /dev/null
@@ -1,35 +0,0 @@
-
- *
- * 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
- */
-interface PeekableRequestRateLimiterInterface extends RequestRateLimiterInterface
-{
- public function peek(Request $request): RateLimit;
-}
diff --git a/plugins/vendor/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php b/plugins/vendor/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php
deleted file mode 100644
index 4c87a40a..00000000
--- a/plugins/vendor/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- *
- * 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
- */
-interface RequestRateLimiterInterface
-{
- public function consume(Request $request): RateLimit;
-
- public function reset(Request $request): void;
-}
diff --git a/plugins/vendor/symfony/http-foundation/RedirectResponse.php b/plugins/vendor/symfony/http-foundation/RedirectResponse.php
deleted file mode 100644
index b1b1cf3c..00000000
--- a/plugins/vendor/symfony/http-foundation/RedirectResponse.php
+++ /dev/null
@@ -1,92 +0,0 @@
-
- *
- * 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
- */
-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('
-
-
-
-
-
- Redirecting to %1$s
-
-
- Redirecting to %1$s.
-
-', htmlspecialchars($url, \ENT_QUOTES, 'UTF-8')));
-
- $this->headers->set('Location', $url);
- $this->headers->set('Content-Type', 'text/html; charset=utf-8');
-
- return $this;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/Request.php b/plugins/vendor/symfony/http-foundation/Request.php
deleted file mode 100644
index 479c4a43..00000000
--- a/plugins/vendor/symfony/http-foundation/Request.php
+++ /dev/null
@@ -1,2267 +0,0 @@
-
- *
- * 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\ConflictingHeadersException;
-use Symfony\Component\HttpFoundation\Exception\JsonException;
-use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
-use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
-use Symfony\Component\HttpFoundation\Session\SessionInterface;
-
-// Help opcache.preload discover always-needed symbols
-class_exists(AcceptHeader::class);
-class_exists(FileBag::class);
-class_exists(HeaderBag::class);
-class_exists(HeaderUtils::class);
-class_exists(InputBag::class);
-class_exists(ParameterBag::class);
-class_exists(ServerBag::class);
-
-/**
- * Request represents an HTTP request.
- *
- * The methods dealing with URL accept / return a raw path (% encoded):
- * * getBasePath
- * * getBaseUrl
- * * getPathInfo
- * * getRequestUri
- * * getUri
- * * getUriForPath
- *
- * @author Fabien Potencier
- */
-class Request
-{
- public const HEADER_FORWARDED = 0b000001; // When using RFC 7239
- public const HEADER_X_FORWARDED_FOR = 0b000010;
- public const HEADER_X_FORWARDED_HOST = 0b000100;
- public const HEADER_X_FORWARDED_PROTO = 0b001000;
- public const HEADER_X_FORWARDED_PORT = 0b010000;
- public const HEADER_X_FORWARDED_PREFIX = 0b100000;
-
- public const HEADER_X_FORWARDED_AWS_ELB = 0b0011010; // AWS ELB doesn't send X-Forwarded-Host
- public const HEADER_X_FORWARDED_TRAEFIK = 0b0111110; // All "X-Forwarded-*" headers sent by Traefik reverse proxy
-
- public const METHOD_HEAD = 'HEAD';
- public const METHOD_GET = 'GET';
- public const METHOD_POST = 'POST';
- public const METHOD_PUT = 'PUT';
- public const METHOD_PATCH = 'PATCH';
- public const METHOD_DELETE = 'DELETE';
- public const METHOD_PURGE = 'PURGE';
- public const METHOD_OPTIONS = 'OPTIONS';
- public const METHOD_TRACE = 'TRACE';
- public const METHOD_CONNECT = 'CONNECT';
- public const METHOD_QUERY = 'QUERY';
-
- /**
- * @var string[]
- */
- protected static array $trustedProxies = [];
-
- /**
- * @var string[]
- */
- protected static array $trustedHostPatterns = [];
-
- /**
- * @var string[]
- */
- protected static array $trustedHosts = [];
-
- protected static bool $httpMethodParameterOverride = false;
-
- /**
- * The HTTP methods that can be overridden.
- *
- * @var uppercase-string[]|null
- */
- protected static ?array $allowedHttpMethodOverride = null;
-
- /**
- * Custom parameters.
- */
- public ParameterBag $attributes;
-
- /**
- * Request body parameters ($_POST).
- *
- * @see getPayload() for portability between content types
- */
- public InputBag $request;
-
- /**
- * Query string parameters ($_GET).
- *
- * @var InputBag
- */
- public InputBag $query;
-
- /**
- * Server and execution environment parameters ($_SERVER).
- */
- public ServerBag $server;
-
- /**
- * Uploaded files ($_FILES).
- */
- public FileBag $files;
-
- /**
- * Cookies ($_COOKIE).
- *
- * @var InputBag
- */
- public InputBag $cookies;
-
- /**
- * Headers (taken from the $_SERVER).
- */
- public HeaderBag $headers;
-
- /**
- * @var string|resource|false|null
- */
- protected $content;
-
- /**
- * @var string[]|null
- */
- protected ?array $languages = null;
-
- /**
- * @var string[]|null
- */
- protected ?array $charsets = null;
-
- /**
- * @var string[]|null
- */
- protected ?array $encodings = null;
-
- /**
- * @var string[]|null
- */
- protected ?array $acceptableContentTypes = null;
-
- protected ?string $pathInfo = null;
- protected ?string $requestUri = null;
- protected ?string $baseUrl = null;
- protected ?string $basePath = null;
- protected ?string $method = null;
- protected ?string $format = null;
- protected SessionInterface|\Closure|null $session = null;
- protected ?string $locale = null;
- protected string $defaultLocale = 'en';
-
- /**
- * @var array|null
- */
- protected static ?array $formats = null;
-
- protected static ?\Closure $requestFactory = null;
-
- private ?string $preferredFormat = null;
-
- private bool $isHostValid = true;
- private bool $isForwardedValid = true;
- private bool $isSafeContentPreferred;
-
- private array $trustedValuesCache = [];
-
- private static int $trustedHeaderSet = -1;
-
- private const FORWARDED_PARAMS = [
- self::HEADER_X_FORWARDED_FOR => 'for',
- self::HEADER_X_FORWARDED_HOST => 'host',
- self::HEADER_X_FORWARDED_PROTO => 'proto',
- self::HEADER_X_FORWARDED_PORT => 'host',
- ];
-
- /**
- * Names for headers that can be trusted when
- * using trusted proxies.
- *
- * The FORWARDED header is the standard as of rfc7239.
- *
- * The other headers are non-standard, but widely used
- * by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
- */
- private const TRUSTED_HEADERS = [
- self::HEADER_FORWARDED => 'FORWARDED',
- self::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
- self::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
- self::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
- self::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
- self::HEADER_X_FORWARDED_PREFIX => 'X_FORWARDED_PREFIX',
- ];
-
- /**
- * This mapping is used when no exact MIME match is found in $formats.
- *
- * It enables mappings like application/soap+xml -> xml.
- *
- * @see https://datatracker.ietf.org/doc/html/rfc6839
- * @see https://datatracker.ietf.org/doc/html/rfc7303
- * @see https://www.iana.org/assignments/media-types/media-types.xhtml
- */
- private const STRUCTURED_SUFFIX_FORMATS = [
- 'json' => 'json',
- 'xml' => 'xml',
- 'xhtml' => 'html',
- 'cbor' => 'cbor',
- 'zip' => 'zip',
- 'ber' => 'asn1',
- 'der' => 'asn1',
- 'tlv' => 'tlv',
- 'wbxml' => 'xml',
- 'yaml' => 'yaml',
- ];
-
- private bool $isIisRewrite = false;
-
- /**
- * @param array $query The GET parameters
- * @param array $request The POST parameters
- * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
- * @param array $cookies The COOKIE parameters
- * @param array $files The FILES parameters
- * @param array $server The SERVER parameters
- * @param string|resource|null $content The raw body data
- */
- public function __construct(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
- {
- $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
- }
-
- /**
- * Sets the parameters for this request.
- *
- * This method also re-initializes all properties.
- *
- * @param array $query The GET parameters
- * @param array $request The POST parameters
- * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
- * @param array $cookies The COOKIE parameters
- * @param array $files The FILES parameters
- * @param array $server The SERVER parameters
- * @param string|resource|null $content The raw body data
- */
- public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null): void
- {
- $this->request = new InputBag($request);
- $this->query = new InputBag($query);
- $this->attributes = new ParameterBag($attributes);
- $this->cookies = new InputBag($cookies);
- $this->files = new FileBag($files);
- $this->server = new ServerBag($server);
- $this->headers = new HeaderBag($this->server->getHeaders());
-
- $this->content = $content;
- $this->languages = null;
- $this->charsets = null;
- $this->encodings = null;
- $this->acceptableContentTypes = null;
- $this->pathInfo = null;
- $this->requestUri = null;
- $this->baseUrl = null;
- $this->basePath = null;
- $this->method = null;
- $this->format = null;
- }
-
- /**
- * Creates a new request with values from PHP's super globals.
- */
- public static function createFromGlobals(): static
- {
- if (!\in_array($_SERVER['REQUEST_METHOD'] ?? null, ['PUT', 'DELETE', 'PATCH', 'QUERY'], true)) {
- return self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);
- }
-
- if (\PHP_VERSION_ID < 80400) {
- if (!isset($_SERVER['CONTENT_TYPE']) || str_starts_with($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded')) {
- $content = file_get_contents('php://input');
- parse_str($content, $post);
- } else {
- $content = null;
- $post = $_POST;
- }
-
- return self::createRequestFromFactory($_GET, $post, [], $_COOKIE, $_FILES, $_SERVER, $content);
- }
-
- try {
- [$post, $files] = request_parse_body();
- } catch (\RequestParseBodyException) {
- $post = $_POST;
- $files = $_FILES;
- }
-
- return self::createRequestFromFactory($_GET, $post, [], $_COOKIE, $files, $_SERVER);
- }
-
- /**
- * Creates a Request based on a given URI and configuration.
- *
- * The information contained in the URI always take precedence
- * over the other information (server and parameters).
- *
- * @param string $uri The URI
- * @param string $method The HTTP method
- * @param array $parameters The query (GET) or request (POST) parameters
- * @param array $cookies The request cookies ($_COOKIE)
- * @param array $files The request files ($_FILES)
- * @param array $server The server parameters ($_SERVER)
- * @param string|resource|null $content The raw body data
- *
- * @throws BadRequestException When the URI is invalid
- */
- public static function create(string $uri, string $method = 'GET', array $parameters = [], array $cookies = [], array $files = [], array $server = [], $content = null): static
- {
- $server = array_replace([
- 'SERVER_NAME' => 'localhost',
- 'SERVER_PORT' => 80,
- 'HTTP_HOST' => 'localhost',
- 'HTTP_USER_AGENT' => 'Symfony',
- 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
- 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
- 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '',
- 'SCRIPT_FILENAME' => '',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- 'REQUEST_TIME' => time(),
- 'REQUEST_TIME_FLOAT' => microtime(true),
- ], $server);
-
- $server['PATH_INFO'] = '';
- $server['REQUEST_METHOD'] = strtoupper($method);
-
- if (($i = strcspn($uri, ':/?#')) && ':' === ($uri[$i] ?? null) && (strspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-.') !== $i || strcspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'))) {
- throw new BadRequestException('Invalid URI: Scheme is malformed.');
- }
- if (false === $components = parse_url(\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#')) {
- throw new BadRequestException('Invalid URI.');
- }
-
- $part = ($components['user'] ?? '').':'.($components['pass'] ?? '');
-
- if (':' !== $part && \strlen($part) !== strcspn($part, '[]')) {
- throw new BadRequestException('Invalid URI: Userinfo is malformed.');
- }
- if (($part = $components['host'] ?? '') && !self::isHostValid($part)) {
- throw new BadRequestException('Invalid URI: Host is malformed.');
- }
- if (false !== ($i = strpos($uri, '\\')) && $i < strcspn($uri, '?#')) {
- throw new BadRequestException('Invalid URI: A URI cannot contain a backslash.');
- }
- if (\strlen($uri) !== strcspn($uri, "\r\n\t")) {
- throw new BadRequestException('Invalid URI: A URI cannot contain CR/LF/TAB characters.');
- }
- if ('' !== $uri && (\ord($uri[0]) <= 32 || \ord($uri[-1]) <= 32)) {
- throw new BadRequestException('Invalid URI: A URI must not start nor end with ASCII control characters or spaces.');
- }
-
- if (isset($components['host'])) {
- $server['SERVER_NAME'] = $components['host'];
- $server['HTTP_HOST'] = $components['host'];
- }
-
- if (isset($components['scheme'])) {
- if ('https' === $components['scheme']) {
- $server['HTTPS'] = 'on';
- $server['SERVER_PORT'] = 443;
- } else {
- unset($server['HTTPS']);
- $server['SERVER_PORT'] = 80;
- }
- }
-
- if (isset($components['port'])) {
- $server['SERVER_PORT'] = $components['port'];
- $server['HTTP_HOST'] .= ':'.$components['port'];
- }
-
- if (isset($components['user'])) {
- $server['PHP_AUTH_USER'] = $components['user'];
- }
-
- if (isset($components['pass'])) {
- $server['PHP_AUTH_PW'] = $components['pass'];
- }
-
- if ('' === $path = $components['path'] ?? '') {
- $components['path'] = '/';
- } elseif (!isset($components['scheme']) && !isset($components['host']) && '/' !== $path[0]) {
- if (false !== $pos = strpos($path, '/')) {
- $path = substr($path, 0, $pos);
- }
-
- if (str_contains($path, ':')) {
- throw new BadRequestException('Invalid URI: Path is malformed.');
- }
- }
-
- switch (strtoupper($method)) {
- case 'POST':
- case 'PUT':
- case 'DELETE':
- case 'QUERY':
- if (!isset($server['CONTENT_TYPE'])) {
- $server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
- }
- // no break
- case 'PATCH':
- $request = $parameters;
- $query = [];
- break;
- default:
- $request = [];
- $query = $parameters;
- break;
- }
-
- $queryString = '';
- if (isset($components['query'])) {
- parse_str(html_entity_decode($components['query']), $qs);
-
- if ($query) {
- $query = array_replace($qs, $query);
- $queryString = http_build_query($query, '', '&');
- } else {
- $query = $qs;
- $queryString = $components['query'];
- }
- } elseif ($query) {
- $queryString = http_build_query($query, '', '&');
- }
-
- $server['REQUEST_URI'] = $components['path'].('' !== $queryString ? '?'.$queryString : '');
- $server['QUERY_STRING'] = $queryString;
-
- return self::createRequestFromFactory($query, $request, [], $cookies, $files, $server, $content);
- }
-
- /**
- * Sets a callable able to create a Request instance.
- *
- * This is mainly useful when you need to override the Request class
- * to keep BC with an existing system. It should not be used for any
- * other purpose.
- */
- public static function setFactory(?callable $callable): void
- {
- self::$requestFactory = null === $callable ? null : $callable(...);
- }
-
- /**
- * Clones a request and overrides some of its parameters.
- *
- * @param array|null $query The GET parameters
- * @param array|null $request The POST parameters
- * @param array|null $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
- * @param array|null $cookies The COOKIE parameters
- * @param array|null $files The FILES parameters
- * @param array|null $server The SERVER parameters
- */
- public function duplicate(?array $query = null, ?array $request = null, ?array $attributes = null, ?array $cookies = null, ?array $files = null, ?array $server = null): static
- {
- $dup = clone $this;
- if (null !== $query) {
- $dup->query = new InputBag($query);
- }
- if (null !== $request) {
- $dup->request = new InputBag($request);
- }
- if (null !== $attributes) {
- $dup->attributes = new ParameterBag($attributes);
- }
- if (null !== $cookies) {
- $dup->cookies = new InputBag($cookies);
- }
- if (null !== $files) {
- $dup->files = new FileBag($files);
- }
- if (null !== $server) {
- $dup->server = new ServerBag($server);
- $dup->headers = new HeaderBag($dup->server->getHeaders());
- }
- $dup->languages = null;
- $dup->charsets = null;
- $dup->encodings = null;
- $dup->acceptableContentTypes = null;
- $dup->pathInfo = null;
- $dup->requestUri = null;
- $dup->baseUrl = null;
- $dup->basePath = null;
- $dup->method = null;
- $dup->format = null;
-
- if (!$dup->attributes->has('_format') && $this->attributes->has('_format')) {
- $dup->attributes->set('_format', $this->attributes->get('_format'));
- }
-
- if (!$dup->getRequestFormat(null)) {
- $dup->setRequestFormat($this->getRequestFormat(null));
- }
-
- return $dup;
- }
-
- /**
- * Clones the current request.
- *
- * Note that the session is not cloned as duplicated requests
- * are most of the time sub-requests of the main one.
- */
- public function __clone()
- {
- $this->query = clone $this->query;
- $this->request = clone $this->request;
- $this->attributes = clone $this->attributes;
- $this->cookies = clone $this->cookies;
- $this->files = clone $this->files;
- $this->server = clone $this->server;
- $this->headers = clone $this->headers;
- }
-
- public function __toString(): string
- {
- $content = $this->getContent();
-
- $cookieHeader = '';
- $cookies = [];
-
- foreach ($this->cookies as $k => $v) {
- $cookies[] = \is_array($v) ? http_build_query([$k => $v], '', '; ', \PHP_QUERY_RFC3986) : "$k=$v";
- }
-
- if ($cookies) {
- $cookieHeader = 'Cookie: '.implode('; ', $cookies)."\r\n";
- }
-
- return
- \sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n".
- $this->headers.
- $cookieHeader."\r\n".
- $content;
- }
-
- /**
- * Overrides the PHP global variables according to this request instance.
- *
- * It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIE.
- * $_FILES is never overridden, see rfc1867
- */
- public function overrideGlobals(): void
- {
- $this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), '', '&')));
-
- $_GET = $this->query->all();
- $_POST = $this->request->all();
- $_SERVER = $this->server->all();
- $_COOKIE = $this->cookies->all();
-
- foreach ($this->headers->all() as $key => $value) {
- $key = strtoupper(str_replace('-', '_', $key));
- if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) {
- $_SERVER[$key] = implode(', ', $value);
- } else {
- $_SERVER['HTTP_'.$key] = implode(', ', $value);
- }
- }
-
- $request = ['g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE];
-
- $requestOrder = \ini_get('request_order') ?: \ini_get('variables_order');
- $requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp';
-
- $_REQUEST = [[]];
-
- foreach (str_split($requestOrder) as $order) {
- $_REQUEST[] = $request[$order];
- }
-
- $_REQUEST = array_merge(...$_REQUEST);
- }
-
- /**
- * Sets a list of trusted proxies.
- *
- * You should only list the reverse proxies that you manage directly.
- *
- * @param array $proxies A list of trusted proxies, the string 'REMOTE_ADDR' will be replaced with $_SERVER['REMOTE_ADDR'] and 'PRIVATE_SUBNETS' by IpUtils::PRIVATE_SUBNETS
- * @param int-mask-of $trustedHeaderSet A bit field to set which headers to trust from your proxies
- */
- public static function setTrustedProxies(array $proxies, int $trustedHeaderSet): void
- {
- if (false !== $i = array_search('REMOTE_ADDR', $proxies, true)) {
- if (isset($_SERVER['REMOTE_ADDR'])) {
- $proxies[$i] = $_SERVER['REMOTE_ADDR'];
- } else {
- unset($proxies[$i]);
- $proxies = array_values($proxies);
- }
- }
-
- if (false !== ($i = array_search('PRIVATE_SUBNETS', $proxies, true)) || false !== ($i = array_search('private_ranges', $proxies, true))) {
- unset($proxies[$i]);
- $proxies = array_merge($proxies, IpUtils::PRIVATE_SUBNETS);
- }
-
- self::$trustedProxies = $proxies;
- self::$trustedHeaderSet = $trustedHeaderSet;
- }
-
- /**
- * Gets the list of trusted proxies.
- *
- * @return string[]
- */
- public static function getTrustedProxies(): array
- {
- return self::$trustedProxies;
- }
-
- /**
- * Gets the set of trusted headers from trusted proxies.
- *
- * @return int A bit field of Request::HEADER_* that defines which headers are trusted from your proxies
- */
- public static function getTrustedHeaderSet(): int
- {
- return self::$trustedHeaderSet;
- }
-
- /**
- * Sets a list of trusted host patterns.
- *
- * You should only list the hosts you manage using regexs.
- *
- * @param array $hostPatterns A list of trusted host patterns
- */
- public static function setTrustedHosts(array $hostPatterns): void
- {
- self::$trustedHostPatterns = array_map(static fn ($hostPattern) => \sprintf('{%s}i', $hostPattern), $hostPatterns);
- // we need to reset trusted hosts on trusted host patterns change
- self::$trustedHosts = [];
- }
-
- /**
- * Gets the list of trusted host patterns.
- *
- * @return string[]
- */
- public static function getTrustedHosts(): array
- {
- return self::$trustedHostPatterns;
- }
-
- /**
- * Normalizes a query string.
- *
- * It builds a normalized query string, where keys/value pairs are alphabetized,
- * have consistent escaping and unneeded delimiters are removed.
- */
- public static function normalizeQueryString(?string $qs): string
- {
- if ('' === ($qs ?? '')) {
- return '';
- }
-
- $qs = HeaderUtils::parseQuery($qs);
- ksort($qs);
-
- return http_build_query($qs, '', '&', \PHP_QUERY_RFC3986);
- }
-
- /**
- * Enables support for the _method request parameter to determine the intended HTTP method.
- *
- * Be warned that enabling this feature might lead to CSRF issues in your code.
- * Check that you are using CSRF tokens when required.
- * If the HTTP method parameter override is enabled, an html-form with method "POST" can be altered
- * and used to send a "PUT" or "DELETE" request via the _method request parameter.
- * If these methods are not protected against CSRF, this presents a possible vulnerability.
- *
- * The HTTP method can only be overridden when the real HTTP method is POST.
- */
- public static function enableHttpMethodParameterOverride(): void
- {
- self::$httpMethodParameterOverride = true;
- }
-
- /**
- * Checks whether support for the _method request parameter is enabled.
- */
- public static function getHttpMethodParameterOverride(): bool
- {
- return self::$httpMethodParameterOverride;
- }
-
- /**
- * Sets the list of HTTP methods that can be overridden.
- *
- * Set to null to allow all methods to be overridden (default). Set to an
- * empty array to disallow overrides entirely. Otherwise, provide the list
- * of uppercased method names that are allowed.
- *
- * @param uppercase-string[]|null $methods
- */
- public static function setAllowedHttpMethodOverride(?array $methods): void
- {
- if (array_intersect($methods ?? [], ['GET', 'HEAD', 'CONNECT', 'TRACE'])) {
- throw new \InvalidArgumentException('The HTTP methods "GET", "HEAD", "CONNECT", and "TRACE" cannot be overridden.');
- }
-
- self::$allowedHttpMethodOverride = $methods;
- }
-
- /**
- * Gets the list of HTTP methods that can be overridden.
- *
- * @return uppercase-string[]|null
- */
- public static function getAllowedHttpMethodOverride(): ?array
- {
- return self::$allowedHttpMethodOverride;
- }
-
- /**
- * Gets a "parameter" value from any bag.
- *
- * This method is mainly useful for libraries that want to provide some flexibility. If you don't need the
- * flexibility in controllers, it is better to explicitly get request parameters from the appropriate
- * public property instead (attributes, query, request).
- *
- * Order of precedence: PATH (routing placeholders or custom attributes), GET, POST
- *
- * @deprecated since Symfony 7.4, use properties `->attributes`, `query` or `request` directly instead
- */
- public function get(string $key, mixed $default = null): mixed
- {
- trigger_deprecation('symfony/http-foundation', '7.4', 'Request::get() is deprecated, use properties ->attributes, query or request directly instead.');
-
- if ($this !== $result = $this->attributes->get($key, $this)) {
- return $result;
- }
-
- if ($this->query->has($key)) {
- return $this->query->all()[$key];
- }
-
- if ($this->request->has($key)) {
- return $this->request->all()[$key];
- }
-
- return $default;
- }
-
- /**
- * Gets the Session.
- *
- * @throws SessionNotFoundException When session is not set properly
- */
- public function getSession(): SessionInterface
- {
- $session = $this->session;
- if (!$session instanceof SessionInterface && null !== $session) {
- $this->setSession($session = $session());
- }
-
- if (null === $session) {
- throw new SessionNotFoundException('Session has not been set.');
- }
-
- return $session;
- }
-
- /**
- * Whether the request contains a Session which was started in one of the
- * previous requests.
- */
- public function hasPreviousSession(): bool
- {
- // the check for $this->session avoids malicious users trying to fake a session cookie with proper name
- return $this->hasSession() && $this->cookies->has($this->getSession()->getName());
- }
-
- /**
- * Whether the request contains a Session object.
- *
- * This method does not give any information about the state of the session object,
- * like whether the session is started or not. It is just a way to check if this Request
- * is associated with a Session instance.
- *
- * @param bool $skipIfUninitialized When true, ignores factories injected by `setSessionFactory`
- */
- public function hasSession(bool $skipIfUninitialized = false): bool
- {
- return null !== $this->session && (!$skipIfUninitialized || $this->session instanceof SessionInterface);
- }
-
- public function setSession(SessionInterface $session): void
- {
- $this->session = $session;
- }
-
- /**
- * @internal
- *
- * @param callable(): SessionInterface $factory
- */
- public function setSessionFactory(callable $factory): void
- {
- $this->session = $factory(...);
- }
-
- /**
- * Returns the client IP addresses.
- *
- * In the returned array the most trusted IP address is first, and the
- * least trusted one last. The "real" client IP address is the last one,
- * but this is also the least trusted one. Trusted proxies are stripped.
- *
- * Use this method carefully; you should use getClientIp() instead.
- *
- * @see getClientIp()
- */
- public function getClientIps(): array
- {
- $ip = $this->server->get('REMOTE_ADDR');
-
- if (!$this->isFromTrustedProxy()) {
- return [$ip];
- }
-
- return $this->getTrustedValues(self::HEADER_X_FORWARDED_FOR, $ip) ?: [$ip];
- }
-
- /**
- * Returns the client IP address.
- *
- * This method can read the client IP address from the "X-Forwarded-For" header
- * when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For"
- * header value is a comma+space separated list of IP addresses, the left-most
- * being the original client, and each successive proxy that passed the request
- * adding the IP address where it received the request from.
- *
- * @see getClientIps()
- * @see https://wikipedia.org/wiki/X-Forwarded-For
- */
- public function getClientIp(): ?string
- {
- return $this->getClientIps()[0];
- }
-
- /**
- * Returns current script name.
- */
- public function getScriptName(): string
- {
- return $this->server->get('SCRIPT_NAME', $this->server->get('ORIG_SCRIPT_NAME', ''));
- }
-
- /**
- * Returns the path being requested relative to the executed script.
- *
- * The path info always starts with a /.
- *
- * Suppose this request is instantiated from /mysite on localhost:
- *
- * * http://localhost/mysite returns '/'
- * * http://localhost/mysite/about returns '/about'
- * * http://localhost/mysite/enco%20ded returns '/enco%20ded'
- * * http://localhost/mysite/about?var=1 returns '/about'
- *
- * @return string The raw path (i.e. not urldecoded)
- */
- public function getPathInfo(): string
- {
- return $this->pathInfo ??= $this->preparePathInfo();
- }
-
- /**
- * Returns the root path from which this request is executed.
- *
- * Suppose that an index.php file instantiates this request object:
- *
- * * http://localhost/index.php returns an empty string
- * * http://localhost/index.php/page returns an empty string
- * * http://localhost/web/index.php returns '/web'
- * * http://localhost/we%20b/index.php returns '/we%20b'
- *
- * @return string The raw path (i.e. not urldecoded)
- */
- public function getBasePath(): string
- {
- return $this->basePath ??= $this->prepareBasePath();
- }
-
- /**
- * Returns the root URL from which this request is executed.
- *
- * The base URL never ends with a /.
- *
- * This is similar to getBasePath(), except that it also includes the
- * script filename (e.g. index.php) if one exists.
- *
- * @return string The raw URL (i.e. not urldecoded)
- */
- public function getBaseUrl(): string
- {
- $trustedPrefix = '';
-
- // the proxy prefix must be prepended to any prefix being needed at the webserver level
- if ($this->isFromTrustedProxy() && $trustedPrefixValues = $this->getTrustedValues(self::HEADER_X_FORWARDED_PREFIX)) {
- $trustedPrefix = rtrim($trustedPrefixValues[0], '/');
- }
-
- return $trustedPrefix.$this->getBaseUrlReal();
- }
-
- /**
- * Returns the real base URL received by the webserver from which this request is executed.
- * The URL does not include trusted reverse proxy prefix.
- *
- * @return string The raw URL (i.e. not urldecoded)
- */
- private function getBaseUrlReal(): string
- {
- return $this->baseUrl ??= $this->prepareBaseUrl();
- }
-
- /**
- * Gets the request's scheme.
- */
- public function getScheme(): string
- {
- return $this->isSecure() ? 'https' : 'http';
- }
-
- /**
- * Returns the port on which the request is made.
- *
- * This method can read the client port from the "X-Forwarded-Port" header
- * when trusted proxies were set via "setTrustedProxies()".
- *
- * The "X-Forwarded-Port" header must contain the client port.
- *
- * @return int|string|null Can be a string if fetched from the server bag
- */
- public function getPort(): int|string|null
- {
- if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_PORT)) {
- $host = $host[0];
- } elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
- $host = $host[0];
- } elseif (!$host = $this->headers->get('HOST')) {
- return $this->server->get('SERVER_PORT');
- }
-
- if ('[' === $host[0]) {
- $pos = strpos($host, ':', strrpos($host, ']'));
- } else {
- $pos = strrpos($host, ':');
- }
-
- if (false !== $pos && $port = substr($host, $pos + 1)) {
- return (int) $port;
- }
-
- return 'https' === $this->getScheme() ? 443 : 80;
- }
-
- /**
- * Returns the user.
- */
- public function getUser(): ?string
- {
- return $this->headers->get('PHP_AUTH_USER');
- }
-
- /**
- * Returns the password.
- */
- public function getPassword(): ?string
- {
- return $this->headers->get('PHP_AUTH_PW');
- }
-
- /**
- * Gets the user info.
- *
- * @return string|null A user name if any and, optionally, scheme-specific information about how to gain authorization to access the server
- */
- public function getUserInfo(): ?string
- {
- $userinfo = $this->getUser();
-
- $pass = $this->getPassword();
- if ('' != $pass) {
- $userinfo .= ":$pass";
- }
-
- return $userinfo;
- }
-
- /**
- * Returns the HTTP host being requested.
- *
- * The port name will be appended to the host if it's non-standard.
- */
- public function getHttpHost(): string
- {
- $scheme = $this->getScheme();
- $port = $this->getPort();
-
- if (('http' === $scheme && 80 == $port) || ('https' === $scheme && 443 == $port)) {
- return $this->getHost();
- }
-
- return $this->getHost().':'.$port;
- }
-
- /**
- * Returns the requested URI (path and query string).
- *
- * @return string The raw URI (i.e. not URI decoded)
- */
- public function getRequestUri(): string
- {
- return $this->requestUri ??= $this->prepareRequestUri();
- }
-
- /**
- * Gets the scheme and HTTP host.
- *
- * If the URL was called with basic authentication, the user
- * and the password are not added to the generated string.
- */
- public function getSchemeAndHttpHost(): string
- {
- return $this->getScheme().'://'.$this->getHttpHost();
- }
-
- /**
- * Generates a normalized URI (URL) for the Request.
- *
- * @see getQueryString()
- */
- public function getUri(): string
- {
- if (null !== $qs = $this->getQueryString()) {
- $qs = '?'.$qs;
- }
-
- return $this->getSchemeAndHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs;
- }
-
- /**
- * Generates a normalized URI for the given path.
- *
- * @param string $path A path to use instead of the current one
- */
- public function getUriForPath(string $path): string
- {
- return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path;
- }
-
- /**
- * Returns the path as relative reference from the current Request path.
- *
- * Only the URIs path component (no schema, host etc.) is relevant and must be given.
- * Both paths must be absolute and not contain relative parts.
- * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
- * Furthermore, they can be used to reduce the link size in documents.
- *
- * Example target paths, given a base path of "/a/b/c/d":
- * - "/a/b/c/d" -> ""
- * - "/a/b/c/" -> "./"
- * - "/a/b/" -> "../"
- * - "/a/b/c/other" -> "other"
- * - "/a/x/y" -> "../../x/y"
- */
- public function getRelativeUriForPath(string $path): string
- {
- // be sure that we are dealing with an absolute path
- if (!isset($path[0]) || '/' !== $path[0]) {
- return $path;
- }
-
- if ($path === $basePath = $this->getPathInfo()) {
- return '';
- }
-
- $sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
- $targetDirs = explode('/', substr($path, 1));
- array_pop($sourceDirs);
- $targetFile = array_pop($targetDirs);
-
- foreach ($sourceDirs as $i => $dir) {
- if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
- unset($sourceDirs[$i], $targetDirs[$i]);
- } else {
- break;
- }
- }
-
- $targetDirs[] = $targetFile;
- $path = str_repeat('../', \count($sourceDirs)).implode('/', $targetDirs);
-
- // A reference to the same base directory or an empty subdirectory must be prefixed with "./".
- // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
- // as the first segment of a relative-path reference, as it would be mistaken for a scheme name
- // (see https://tools.ietf.org/html/rfc3986#section-4.2).
- return !isset($path[0]) || '/' === $path[0]
- || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
- ? "./$path" : $path;
- }
-
- /**
- * Generates the normalized query string for the Request.
- *
- * It builds a normalized query string, where keys/value pairs are alphabetized
- * and have consistent escaping.
- */
- public function getQueryString(): ?string
- {
- $qs = static::normalizeQueryString($this->server->get('QUERY_STRING'));
-
- return '' === $qs ? null : $qs;
- }
-
- /**
- * Checks whether the request is secure or not.
- *
- * This method can read the client protocol from the "X-Forwarded-Proto" header
- * when trusted proxies were set via "setTrustedProxies()".
- *
- * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
- */
- public function isSecure(): bool
- {
- if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_X_FORWARDED_PROTO)) {
- return \in_array(strtolower($proto[0]), ['https', 'on', 'ssl', '1'], true);
- }
-
- $https = $this->server->get('HTTPS');
-
- return $https && (!\is_string($https) || 'off' !== strtolower($https));
- }
-
- /**
- * Returns the host name.
- *
- * This method can read the client host name from the "X-Forwarded-Host" header
- * when trusted proxies were set via "setTrustedProxies()".
- *
- * The "X-Forwarded-Host" header must contain the client host name.
- *
- * @throws SuspiciousOperationException when the host name is invalid or not trusted
- */
- public function getHost(): string
- {
- if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
- $host = $host[0];
- } else {
- $host = $this->headers->get('HOST') ?: $this->server->get('SERVER_NAME') ?: $this->server->get('SERVER_ADDR', '');
- }
-
- // trim and remove port number from host
- // host is lowercase as per RFC 952/2181
- $host = strtolower(preg_replace('/:\d+$/', '', trim($host)));
-
- // the host can come from the user (HTTP_HOST and depending on the configuration, SERVER_NAME too can come from the user)
- if ($host && !self::isHostValid($host)) {
- if (!$this->isHostValid) {
- return '';
- }
- $this->isHostValid = false;
-
- throw new SuspiciousOperationException(\sprintf('Invalid Host "%s".', $host));
- }
-
- if (\count(self::$trustedHostPatterns) > 0) {
- // to avoid host header injection attacks, you should provide a list of trusted host patterns
-
- if (\in_array($host, self::$trustedHosts, true)) {
- return $host;
- }
-
- foreach (self::$trustedHostPatterns as $pattern) {
- if (preg_match($pattern, $host)) {
- self::$trustedHosts[] = $host;
-
- return $host;
- }
- }
-
- if (!$this->isHostValid) {
- return '';
- }
- $this->isHostValid = false;
-
- throw new SuspiciousOperationException(\sprintf('Untrusted Host "%s".', $host));
- }
-
- return $host;
- }
-
- /**
- * Sets the request method.
- */
- public function setMethod(string $method): void
- {
- $this->method = null;
- $this->server->set('REQUEST_METHOD', $method);
- }
-
- /**
- * Gets the request "intended" method.
- *
- * If the X-HTTP-Method-Override header is set, and if the method is a POST,
- * then it is used to determine the "real" intended HTTP method.
- *
- * The _method request parameter can also be used to determine the HTTP method,
- * but only if enableHttpMethodParameterOverride() has been called.
- *
- * The method is always an uppercased string.
- *
- * @see getRealMethod()
- */
- public function getMethod(): string
- {
- if (null !== $this->method) {
- return $this->method;
- }
-
- $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
-
- if ('POST' !== $this->method || !(self::$allowedHttpMethodOverride ?? true)) {
- return $this->method;
- }
-
- $method = $this->headers->get('X-HTTP-METHOD-OVERRIDE');
-
- if (!$method && self::$httpMethodParameterOverride) {
- $method = $this->request->get('_method', $this->query->get('_method', 'POST'));
- }
-
- if (!\is_string($method)) {
- return $this->method;
- }
-
- $method = strtoupper($method);
-
- if (\in_array($method, ['GET', 'HEAD', 'CONNECT', 'TRACE'], true)) {
- trigger_deprecation('symfony/http-foundation', '7.4', 'HTTP method override is deprecated for methods GET, HEAD, CONNECT and TRACE; it will be ignored in Symfony 8.0.', $method);
- }
-
- if (self::$allowedHttpMethodOverride && !\in_array($method, self::$allowedHttpMethodOverride, true)) {
- return $this->method;
- }
-
- if (\strlen($method) !== strspn($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) {
- throw new SuspiciousOperationException('Invalid HTTP method override.');
- }
-
- return $this->method = $method;
- }
-
- /**
- * Gets the "real" request method.
- *
- * @see getMethod()
- */
- public function getRealMethod(): string
- {
- return strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
- }
-
- /**
- * Gets the mime type associated with the format.
- */
- public function getMimeType(string $format): ?string
- {
- if (null === static::$formats) {
- static::initializeFormats();
- }
-
- return isset(static::$formats[$format]) ? static::$formats[$format][0] : null;
- }
-
- /**
- * Gets the mime types associated with the format.
- *
- * @return string[]
- */
- public static function getMimeTypes(string $format): array
- {
- if (null === static::$formats) {
- static::initializeFormats();
- }
-
- return static::$formats[$format] ?? [];
- }
-
- /**
- * Gets the format associated with the mime type.
- *
- * Resolution order:
- * 1) Exact match on the full MIME type (e.g. "application/json").
- * 2) Match on the canonical MIME type (i.e. before the first ";" parameter).
- * 3) If the type is "application/*+suffix", use the structured syntax suffix
- * mapping (e.g. "application/foo+json" → "json"), when available.
- * 4) If $subtypeFallback is true and no match was found:
- * - return the MIME subtype (without "x-" prefix), provided it does not
- * contain a "+" (e.g. "application/x-yaml" → "yaml", "text/csv" → "csv").
- *
- * @param string|null $mimeType The mime type to check
- * @param bool $subtypeFallback Whether to fall back to the subtype if no exact match is found
- */
- public function getFormat(?string $mimeType/* , bool $subtypeFallback = false */): ?string
- {
- $subtypeFallback = 2 <= \func_num_args() ? func_get_arg(1) : false;
- $canonicalMimeType = null;
- if ($mimeType && false !== $pos = strpos($mimeType, ';')) {
- $canonicalMimeType = trim(substr($mimeType, 0, $pos));
- }
-
- if (null === static::$formats) {
- static::initializeFormats();
- }
-
- $exactFormat = null;
- $canonicalFormat = null;
-
- foreach (static::$formats as $format => $mimeTypes) {
- if (\in_array($mimeType, $mimeTypes, true)) {
- $exactFormat = $format;
- }
- if (null !== $canonicalMimeType && \in_array($canonicalMimeType, $mimeTypes, true)) {
- $canonicalFormat = $format;
- }
- }
-
- if ($format = $exactFormat ?? $canonicalFormat) {
- return $format;
- }
-
- if (!$canonicalMimeType ??= $mimeType) {
- return null;
- }
-
- if (str_starts_with($canonicalMimeType, 'application/') && str_contains($canonicalMimeType, '+')) {
- $suffix = substr(strrchr($canonicalMimeType, '+'), 1);
- if (isset(self::STRUCTURED_SUFFIX_FORMATS[$suffix])) {
- return self::STRUCTURED_SUFFIX_FORMATS[$suffix];
- }
- }
-
- if ($subtypeFallback && str_contains($canonicalMimeType, '/')) {
- [, $subtype] = explode('/', $canonicalMimeType, 2);
- if (str_starts_with($subtype, 'x-')) {
- $subtype = substr($subtype, 2);
- }
- if (!str_contains($subtype, '+')) {
- return $subtype;
- }
- }
-
- return null;
- }
-
- /**
- * Associates a format with mime types.
- *
- * @param string $format The format to set
- * @param string|string[] $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type)
- */
- public function setFormat(?string $format, string|array $mimeTypes): void
- {
- if (null === $format) {
- trigger_deprecation('symfony/http-foundation', '7.4', 'Passing "null" as the first argument of "%s()" is deprecated. The argument will be non-nullable in Symfony 8.0.', __METHOD__);
- $format = '';
- }
-
- if (null === static::$formats) {
- static::initializeFormats();
- }
-
- static::$formats[$format] = (array) $mimeTypes;
- }
-
- /**
- * Gets the request format.
- *
- * Here is the process to determine the format:
- *
- * * format defined by the user (with setRequestFormat())
- * * _format request attribute
- * * $default
- *
- * @see getPreferredFormat
- */
- public function getRequestFormat(?string $default = 'html'): ?string
- {
- $this->format ??= $this->attributes->get('_format');
-
- return $this->format ?? $default;
- }
-
- /**
- * Sets the request format.
- */
- public function setRequestFormat(?string $format): void
- {
- $this->format = $format;
- }
-
- /**
- * Gets the usual name of the format associated with the request's media type (provided in the Content-Type header).
- *
- * @see Request::$formats
- */
- public function getContentTypeFormat(): ?string
- {
- return $this->getFormat($this->headers->get('CONTENT_TYPE', ''));
- }
-
- /**
- * Sets the default locale.
- */
- public function setDefaultLocale(string $locale): void
- {
- $this->defaultLocale = $locale;
-
- if (null === $this->locale) {
- $this->setPhpDefaultLocale($locale);
- }
- }
-
- /**
- * Get the default locale.
- */
- public function getDefaultLocale(): string
- {
- return $this->defaultLocale;
- }
-
- /**
- * Sets the locale.
- */
- public function setLocale(string $locale): void
- {
- $this->setPhpDefaultLocale($this->locale = $locale);
- }
-
- /**
- * Get the locale.
- */
- public function getLocale(): string
- {
- return $this->locale ?? $this->defaultLocale;
- }
-
- /**
- * Checks if the request method is of specified type.
- *
- * @param string $method Uppercase request method (GET, POST etc)
- */
- public function isMethod(string $method): bool
- {
- return $this->getMethod() === strtoupper($method);
- }
-
- /**
- * Checks whether or not the method is safe.
- *
- * @see https://tools.ietf.org/html/rfc7231#section-4.2.1
- */
- public function isMethodSafe(): bool
- {
- return \in_array($this->getMethod(), ['GET', 'HEAD', 'OPTIONS', 'TRACE', 'QUERY'], true);
- }
-
- /**
- * Checks whether or not the method is idempotent.
- */
- public function isMethodIdempotent(): bool
- {
- return \in_array($this->getMethod(), ['HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE', 'QUERY'], true);
- }
-
- /**
- * Checks whether the method is cacheable or not.
- *
- * @see https://tools.ietf.org/html/rfc7231#section-4.2.3
- */
- public function isMethodCacheable(): bool
- {
- return \in_array($this->getMethod(), ['GET', 'HEAD', 'QUERY'], true);
- }
-
- /**
- * Returns the protocol version.
- *
- * If the application is behind a proxy, the protocol version used in the
- * requests between the client and the proxy and between the proxy and the
- * server might be different. This returns the former (from the "Via" header)
- * if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns
- * the latter (from the "SERVER_PROTOCOL" server parameter).
- */
- public function getProtocolVersion(): ?string
- {
- if ($this->isFromTrustedProxy()) {
- preg_match('~^(HTTP/)?([1-9]\.[0-9])\b~', $this->headers->get('Via') ?? '', $matches);
-
- if ($matches) {
- return 'HTTP/'.$matches[2];
- }
- }
-
- return $this->server->get('SERVER_PROTOCOL');
- }
-
- /**
- * Returns the request body content.
- *
- * @param bool $asResource If true, a resource will be returned
- *
- * @return string|resource
- *
- * @psalm-return ($asResource is true ? resource : string)
- */
- public function getContent(bool $asResource = false)
- {
- if ($asResource) {
- if (\is_resource($this->content)) {
- rewind($this->content);
-
- return $this->content;
- }
-
- // Content passed in parameter (test)
- if (\is_string($this->content)) {
- $resource = fopen('php://temp', 'r+');
- fwrite($resource, $this->content);
- rewind($resource);
-
- return $resource;
- }
-
- $this->content = false;
-
- return fopen('php://input', 'r');
- }
-
- if (\is_resource($this->content)) {
- rewind($this->content);
-
- return stream_get_contents($this->content);
- }
-
- if (null === $this->content || false === $this->content) {
- $this->content = file_get_contents('php://input');
- }
-
- return $this->content;
- }
-
- /**
- * Gets the decoded form or json request body.
- *
- * @throws JsonException When the body cannot be decoded to an array
- */
- public function getPayload(): InputBag
- {
- if ($this->request->count()) {
- return clone $this->request;
- }
-
- if ('' === $content = $this->getContent()) {
- return new InputBag([]);
- }
-
- try {
- $content = json_decode($content, true, 512, \JSON_BIGINT_AS_STRING | \JSON_THROW_ON_ERROR);
- } catch (\JsonException $e) {
- throw new JsonException('Could not decode request body.', $e->getCode(), $e);
- }
-
- if (!\is_array($content)) {
- throw new JsonException(\sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content)));
- }
-
- return new InputBag($content);
- }
-
- /**
- * Gets the request body decoded as array, typically from a JSON payload.
- *
- * @see getPayload() for portability between content types
- *
- * @throws JsonException When the body cannot be decoded to an array
- */
- public function toArray(): array
- {
- if ('' === $content = $this->getContent()) {
- throw new JsonException('Request body is empty.');
- }
-
- try {
- $content = json_decode($content, true, 512, \JSON_BIGINT_AS_STRING | \JSON_THROW_ON_ERROR);
- } catch (\JsonException $e) {
- throw new JsonException('Could not decode request body.', $e->getCode(), $e);
- }
-
- if (!\is_array($content)) {
- throw new JsonException(\sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content)));
- }
-
- return $content;
- }
-
- /**
- * Gets the Etags.
- */
- public function getETags(): array
- {
- return preg_split('/\s*,\s*/', $this->headers->get('If-None-Match', ''), -1, \PREG_SPLIT_NO_EMPTY);
- }
-
- public function isNoCache(): bool
- {
- return $this->headers->hasCacheControlDirective('no-cache') || 'no-cache' == $this->headers->get('Pragma');
- }
-
- /**
- * Gets the preferred format for the response by inspecting, in the following order:
- * * the request format set using setRequestFormat;
- * * the values of the Accept HTTP header.
- *
- * Note that if you use this method, you should send the "Vary: Accept" header
- * in the response to prevent any issues with intermediary HTTP caches.
- */
- public function getPreferredFormat(?string $default = 'html'): ?string
- {
- if (!isset($this->preferredFormat) && null !== $preferredFormat = $this->getRequestFormat(null)) {
- $this->preferredFormat = $preferredFormat;
- }
-
- if ($this->preferredFormat ?? null) {
- return $this->preferredFormat;
- }
-
- foreach ($this->getAcceptableContentTypes() as $mimeType) {
- if ($this->preferredFormat = $this->getFormat($mimeType)) {
- return $this->preferredFormat;
- }
- }
-
- return $default;
- }
-
- /**
- * Returns the preferred language.
- *
- * @param string[] $locales An array of ordered available locales
- */
- public function getPreferredLanguage(?array $locales = null): ?string
- {
- $preferredLanguages = $this->getLanguages();
-
- if (!$locales) {
- return $preferredLanguages[0] ?? null;
- }
-
- $locales = array_map($this->formatLocale(...), $locales);
- if (!$preferredLanguages) {
- return $locales[0];
- }
-
- $combinations = array_merge(...array_map($this->getLanguageCombinations(...), $preferredLanguages));
- foreach ($combinations as $combination) {
- foreach ($locales as $locale) {
- if (str_starts_with($locale, $combination)) {
- return $locale;
- }
- }
- }
-
- return $locales[0];
- }
-
- /**
- * Gets a list of languages acceptable by the client browser ordered in the user browser preferences.
- *
- * @return string[]
- */
- public function getLanguages(): array
- {
- if (null !== $this->languages) {
- return $this->languages;
- }
-
- $languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
- $this->languages = [];
- foreach ($languages as $acceptHeaderItem) {
- $lang = $acceptHeaderItem->getValue();
- $this->languages[] = self::formatLocale($lang);
- }
- $this->languages = array_unique($this->languages);
-
- return $this->languages;
- }
-
- /**
- * Strips the locale to only keep the canonicalized language value.
- *
- * Depending on the $locale value, this method can return values like :
- * - language_Script_REGION: "fr_Latn_FR", "zh_Hans_TW"
- * - language_Script: "fr_Latn", "zh_Hans"
- * - language_REGION: "fr_FR", "zh_TW"
- * - language: "fr", "zh"
- *
- * Invalid locale values are returned as is.
- *
- * @see https://wikipedia.org/wiki/IETF_language_tag
- * @see https://datatracker.ietf.org/doc/html/rfc5646
- */
- private static function formatLocale(string $locale): string
- {
- [$language, $script, $region] = self::getLanguageComponents($locale);
-
- return implode('_', array_filter([$language, $script, $region]));
- }
-
- /**
- * Returns an array of all possible combinations of the language components.
- *
- * For instance, if the locale is "fr_Latn_FR", this method will return:
- * - "fr_Latn_FR"
- * - "fr_Latn"
- * - "fr_FR"
- * - "fr"
- *
- * @return string[]
- */
- private static function getLanguageCombinations(string $locale): array
- {
- [$language, $script, $region] = self::getLanguageComponents($locale);
-
- return array_unique([
- implode('_', array_filter([$language, $script, $region])),
- implode('_', array_filter([$language, $script])),
- implode('_', array_filter([$language, $region])),
- $language,
- ]);
- }
-
- /**
- * Returns an array with the language components of the locale.
- *
- * For example:
- * - If the locale is "fr_Latn_FR", this method will return "fr", "Latn", "FR"
- * - If the locale is "fr_FR", this method will return "fr", null, "FR"
- * - If the locale is "zh_Hans", this method will return "zh", "Hans", null
- *
- * @see https://wikipedia.org/wiki/IETF_language_tag
- * @see https://datatracker.ietf.org/doc/html/rfc5646
- *
- * @return array{string, string|null, string|null}
- */
- private static function getLanguageComponents(string $locale): array
- {
- $locale = str_replace('_', '-', strtolower($locale));
- $pattern = '/^([a-zA-Z]{2,3}|i-[a-zA-Z]{5,})(?:-([a-zA-Z]{4}))?(?:-([a-zA-Z]{2}))?(?:-(.+))?$/';
- if (!preg_match($pattern, $locale, $matches)) {
- return [$locale, null, null];
- }
- if (str_starts_with($matches[1], 'i-')) {
- // Language not listed in ISO 639 that are not variants
- // of any listed language, which can be registered with the
- // i-prefix, such as i-cherokee
- $matches[1] = substr($matches[1], 2);
- }
-
- return [
- $matches[1],
- isset($matches[2]) ? ucfirst(strtolower($matches[2])) : null,
- isset($matches[3]) ? strtoupper($matches[3]) : null,
- ];
- }
-
- /**
- * Gets a list of charsets acceptable by the client browser in preferable order.
- *
- * @return string[]
- */
- public function getCharsets(): array
- {
- return $this->charsets ??= array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all()));
- }
-
- /**
- * Gets a list of encodings acceptable by the client browser in preferable order.
- *
- * @return string[]
- */
- public function getEncodings(): array
- {
- return $this->encodings ??= array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all()));
- }
-
- /**
- * Gets a list of content types acceptable by the client browser in preferable order.
- *
- * @return string[]
- */
- public function getAcceptableContentTypes(): array
- {
- return $this->acceptableContentTypes ??= array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all()));
- }
-
- /**
- * Returns true if the request is an XMLHttpRequest.
- *
- * It works if your JavaScript library sets an X-Requested-With HTTP header.
- * It is known to work with common JavaScript frameworks:
- *
- * @see https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
- */
- public function isXmlHttpRequest(): bool
- {
- return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
- }
-
- /**
- * Checks whether the client browser prefers safe content or not according to RFC8674.
- *
- * @see https://tools.ietf.org/html/rfc8674
- */
- public function preferSafeContent(): bool
- {
- if (isset($this->isSafeContentPreferred)) {
- return $this->isSafeContentPreferred;
- }
-
- if (!$this->isSecure()) {
- // see https://tools.ietf.org/html/rfc8674#section-3
- return $this->isSafeContentPreferred = false;
- }
-
- return $this->isSafeContentPreferred = AcceptHeader::fromString($this->headers->get('Prefer'))->has('safe');
- }
-
- /*
- * The following methods are derived from code of the Zend Framework (1.10dev - 2010-01-24)
- *
- * Code subject to the new BSD license (https://framework.zend.com/license).
- *
- * Copyright (c) 2005-2010 Zend Technologies USA Inc. (https://www.zend.com/)
- */
-
- protected function prepareRequestUri(): string
- {
- $requestUri = '';
-
- if ($this->isIisRewrite() && '' != $this->server->get('UNENCODED_URL')) {
- // IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem)
- $requestUri = $this->server->get('UNENCODED_URL');
- $this->server->remove('UNENCODED_URL');
- } elseif ($this->server->has('REQUEST_URI')) {
- $requestUri = $this->server->get('REQUEST_URI');
-
- if ('' !== $requestUri && '/' === $requestUri[0]) {
- // To only use path and query remove the fragment.
- if (false !== $pos = strpos($requestUri, '#')) {
- $requestUri = substr($requestUri, 0, $pos);
- }
- } else {
- // HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path,
- // only use URL path.
- $uriComponents = parse_url($requestUri);
-
- if (isset($uriComponents['path'])) {
- $requestUri = $uriComponents['path'];
- }
-
- if (isset($uriComponents['query'])) {
- $requestUri .= '?'.$uriComponents['query'];
- }
- }
- } elseif ($this->server->has('ORIG_PATH_INFO')) {
- // IIS 5.0, PHP as CGI
- $requestUri = $this->server->get('ORIG_PATH_INFO');
- if ('' != $this->server->get('QUERY_STRING')) {
- $requestUri .= '?'.$this->server->get('QUERY_STRING');
- }
- $this->server->remove('ORIG_PATH_INFO');
- }
-
- // normalize the request URI to ease creating sub-requests from this request
- $this->server->set('REQUEST_URI', $requestUri);
-
- return $requestUri;
- }
-
- /**
- * Prepares the base URL.
- */
- protected function prepareBaseUrl(): string
- {
- $filename = basename($this->server->get('SCRIPT_FILENAME', ''));
-
- if (basename($this->server->get('SCRIPT_NAME', '')) === $filename) {
- $baseUrl = $this->server->get('SCRIPT_NAME');
- } elseif (basename($this->server->get('PHP_SELF', '')) === $filename) {
- $baseUrl = $this->server->get('PHP_SELF');
- } elseif (basename($this->server->get('ORIG_SCRIPT_NAME', '')) === $filename) {
- $baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); // 1and1 shared hosting compatibility
- } else {
- // Backtrack up the script_filename to find the portion matching
- // php_self
- $path = $this->server->get('PHP_SELF', '');
- $file = $this->server->get('SCRIPT_FILENAME', '');
- $segs = explode('/', trim($file, '/'));
- $segs = array_reverse($segs);
- $index = 0;
- $last = \count($segs);
- $baseUrl = '';
- do {
- $seg = $segs[$index];
- $baseUrl = '/'.$seg.$baseUrl;
- ++$index;
- } while ($last > $index && (false !== $pos = strpos($path, $baseUrl)) && 0 != $pos);
- }
-
- // Does the baseUrl have anything in common with the request_uri?
- $requestUri = $this->getRequestUri();
- if ('' !== $requestUri && '/' !== $requestUri[0]) {
- $requestUri = '/'.$requestUri;
- }
-
- if ($baseUrl && null !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) {
- // full $baseUrl matches
- return $prefix;
- }
-
- if ($baseUrl && null !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(\dirname($baseUrl), '/'.\DIRECTORY_SEPARATOR).'/')) {
- // directory portion of $baseUrl matches
- return rtrim($prefix, '/'.\DIRECTORY_SEPARATOR);
- }
-
- $truncatedRequestUri = $requestUri;
- if (false !== $pos = strpos($requestUri, '?')) {
- $truncatedRequestUri = substr($requestUri, 0, $pos);
- }
-
- $basename = basename($baseUrl ?? '');
- if (!$basename || !strpos(rawurldecode($truncatedRequestUri), $basename)) {
- // no match whatsoever; set it blank
- return '';
- }
-
- // If using mod_rewrite or ISAPI_Rewrite strip the script filename
- // out of baseUrl. $pos !== 0 makes sure it is not matching a value
- // from PATH_INFO or QUERY_STRING
- if (\strlen($requestUri) >= \strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && 0 !== $pos) {
- $baseUrl = substr($requestUri, 0, $pos + \strlen($baseUrl));
- }
-
- return rtrim($baseUrl, '/'.\DIRECTORY_SEPARATOR);
- }
-
- /**
- * Prepares the base path.
- */
- protected function prepareBasePath(): string
- {
- $baseUrl = $this->getBaseUrl();
- if (!$baseUrl) {
- return '';
- }
-
- $filename = basename($this->server->get('SCRIPT_FILENAME'));
- if (basename($baseUrl) === $filename) {
- $basePath = \dirname($baseUrl);
- } else {
- $basePath = $baseUrl;
- }
-
- if ('\\' === \DIRECTORY_SEPARATOR) {
- $basePath = str_replace('\\', '/', $basePath);
- }
-
- return rtrim($basePath, '/');
- }
-
- /**
- * Prepares the path info.
- */
- protected function preparePathInfo(): string
- {
- if (null === ($requestUri = $this->getRequestUri())) {
- return '/';
- }
-
- // Remove the query string from REQUEST_URI
- if (false !== $pos = strpos($requestUri, '?')) {
- $requestUri = substr($requestUri, 0, $pos);
- }
- if ('' !== $requestUri && '/' !== $requestUri[0]) {
- $requestUri = '/'.$requestUri;
- }
-
- if (null === ($baseUrl = $this->getBaseUrlReal())) {
- return $requestUri;
- }
-
- $pathInfo = substr($requestUri, \strlen($baseUrl));
- if ('' === $pathInfo || '/' !== $pathInfo[0]) {
- return '/'.$pathInfo;
- }
-
- return $pathInfo;
- }
-
- /**
- * Initializes HTTP request formats.
- */
- protected static function initializeFormats(): void
- {
- static::$formats = [
- 'html' => ['text/html', 'application/xhtml+xml'],
- 'txt' => ['text/plain'],
- 'js' => ['application/javascript', 'application/x-javascript', 'text/javascript'],
- 'css' => ['text/css'],
- 'json' => ['application/json', 'application/x-json'],
- 'jsonld' => ['application/ld+json'],
- 'xml' => ['text/xml', 'application/xml', 'application/x-xml'],
- 'rdf' => ['application/rdf+xml'],
- 'atom' => ['application/atom+xml'],
- 'rss' => ['application/rss+xml'],
- 'form' => ['application/x-www-form-urlencoded', 'multipart/form-data'],
- 'soap' => ['application/soap+xml'],
- 'problem' => ['application/problem+json'],
- 'hal' => ['application/hal+json', 'application/hal+xml'],
- 'jsonapi' => ['application/vnd.api+json'],
- 'yaml' => ['text/yaml', 'application/x-yaml'],
- 'wbxml' => ['application/vnd.wap.wbxml'],
- 'pdf' => ['application/pdf'],
- 'csv' => ['text/csv'],
- ];
- }
-
- private function setPhpDefaultLocale(string $locale): void
- {
- // if either the class Locale doesn't exist, or an exception is thrown when
- // setting the default locale, the intl module is not installed, and
- // the call can be ignored:
- try {
- if (class_exists(\Locale::class, false)) {
- \Locale::setDefault($locale);
- }
- } catch (\Exception) {
- }
- }
-
- /**
- * Returns the prefix as encoded in the string when the string starts with
- * the given prefix, null otherwise.
- */
- private function getUrlencodedPrefix(string $string, string $prefix): ?string
- {
- if ($this->isIisRewrite()) {
- // ISS with UrlRewriteModule might report SCRIPT_NAME/PHP_SELF with wrong case
- // see https://github.com/php/php-src/issues/11981
- if (0 !== stripos(rawurldecode($string), $prefix)) {
- return null;
- }
- } elseif (!str_starts_with(rawurldecode($string), $prefix)) {
- return null;
- }
-
- $len = \strlen($prefix);
-
- if (preg_match(\sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) {
- return $match[0];
- }
-
- return null;
- }
-
- private static function createRequestFromFactory(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null): static
- {
- if (self::$requestFactory) {
- $request = (self::$requestFactory)($query, $request, $attributes, $cookies, $files, $server, $content);
-
- if (!$request instanceof self) {
- throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.');
- }
-
- return $request;
- }
-
- return new static($query, $request, $attributes, $cookies, $files, $server, $content);
- }
-
- /**
- * Indicates whether this request originated from a trusted proxy.
- *
- * This can be useful to determine whether or not to trust the
- * contents of a proxy-specific header.
- */
- public function isFromTrustedProxy(): bool
- {
- return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR', ''), self::$trustedProxies);
- }
-
- /**
- * This method is rather heavy because it splits and merges headers, and it's called by many other methods such as
- * getPort(), isSecure(), getHost(), getClientIps(), getBaseUrl() etc. Thus, we try to cache the results for
- * best performance.
- */
- private function getTrustedValues(int $type, ?string $ip = null): array
- {
- $cacheKey = $type."\0".((self::$trustedHeaderSet & $type) ? $this->headers->get(self::TRUSTED_HEADERS[$type]) : '');
- $cacheKey .= "\0".$ip."\0".$this->headers->get(self::TRUSTED_HEADERS[self::HEADER_FORWARDED]);
-
- if (isset($this->trustedValuesCache[$cacheKey])) {
- return $this->trustedValuesCache[$cacheKey];
- }
-
- $clientValues = [];
- $forwardedValues = [];
-
- if ((self::$trustedHeaderSet & $type) && $this->headers->has(self::TRUSTED_HEADERS[$type])) {
- foreach (explode(',', $this->headers->get(self::TRUSTED_HEADERS[$type])) as $v) {
- $clientValues[] = (self::HEADER_X_FORWARDED_PORT === $type ? '0.0.0.0:' : '').trim($v);
- }
- }
-
- if ((self::$trustedHeaderSet & self::HEADER_FORWARDED) && (isset(self::FORWARDED_PARAMS[$type])) && $this->headers->has(self::TRUSTED_HEADERS[self::HEADER_FORWARDED])) {
- $forwarded = $this->headers->get(self::TRUSTED_HEADERS[self::HEADER_FORWARDED]);
- $parts = HeaderUtils::split($forwarded, ',;=');
- $param = self::FORWARDED_PARAMS[$type];
- foreach ($parts as $subParts) {
- if (null === $v = HeaderUtils::combine($subParts)[$param] ?? null) {
- continue;
- }
- if (self::HEADER_X_FORWARDED_PORT === $type) {
- if (str_ends_with($v, ']') || false === $v = strrchr($v, ':')) {
- $v = $this->isSecure() ? ':443' : ':80';
- }
- $v = '0.0.0.0'.$v;
- }
- $forwardedValues[] = $v;
- }
- }
-
- if (null !== $ip) {
- $clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip);
- $forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip);
- }
-
- if ($forwardedValues === $clientValues || !$clientValues) {
- return $this->trustedValuesCache[$cacheKey] = $forwardedValues;
- }
-
- if (!$forwardedValues) {
- return $this->trustedValuesCache[$cacheKey] = $clientValues;
- }
-
- if (!$this->isForwardedValid) {
- return $this->trustedValuesCache[$cacheKey] = null !== $ip ? ['0.0.0.0', $ip] : [];
- }
- $this->isForwardedValid = false;
-
- throw new ConflictingHeadersException(\sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.', self::TRUSTED_HEADERS[self::HEADER_FORWARDED], self::TRUSTED_HEADERS[$type]));
- }
-
- private function normalizeAndFilterClientIps(array $clientIps, string $ip): array
- {
- if (!$clientIps) {
- return [];
- }
- $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
- $firstTrustedIp = null;
-
- foreach ($clientIps as $key => $clientIp) {
- if (strpos($clientIp, '.')) {
- // Strip :port from IPv4 addresses. This is allowed in Forwarded
- // and may occur in X-Forwarded-For.
- $i = strpos($clientIp, ':');
- if ($i) {
- $clientIps[$key] = $clientIp = substr($clientIp, 0, $i);
- }
- } elseif (str_starts_with($clientIp, '[')) {
- // Strip brackets and :port from IPv6 addresses.
- $i = strpos($clientIp, ']', 1);
- $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1);
- }
-
- if (!filter_var($clientIp, \FILTER_VALIDATE_IP)) {
- unset($clientIps[$key]);
-
- continue;
- }
-
- if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
- unset($clientIps[$key]);
-
- // Fallback to this when the client IP falls into the range of trusted proxies
- $firstTrustedIp ??= $clientIp;
- }
- }
-
- // Now the IP chain contains only untrusted proxies and the client IP
- return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp];
- }
-
- /**
- * Is this IIS with UrlRewriteModule?
- *
- * This method consumes, caches and removed the IIS_WasUrlRewritten env var,
- * so we don't inherit it to sub-requests.
- */
- private function isIisRewrite(): bool
- {
- if (1 === $this->server->getInt('IIS_WasUrlRewritten')) {
- $this->isIisRewrite = true;
- $this->server->remove('IIS_WasUrlRewritten');
- }
-
- return $this->isIisRewrite;
- }
-
- /**
- * See https://url.spec.whatwg.org/.
- */
- private static function isHostValid(string $host): bool
- {
- if ('[' === $host[0]) {
- return ']' === $host[-1] && filter_var(substr($host, 1, -1), \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6);
- }
-
- if (preg_match('/\.[0-9]++\.?$/D', $host)) {
- return null !== filter_var($host, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4 | \FILTER_NULL_ON_FAILURE);
- }
-
- // use preg_replace() instead of preg_match() to prevent DoS attacks with long host names
- return '' === preg_replace('/[-a-zA-Z0-9_]++\.?/', '', $host);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php
deleted file mode 100644
index 09d6f49d..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php
+++ /dev/null
@@ -1,45 +0,0 @@
-
- *
- * 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
- */
-class AttributesRequestMatcher implements RequestMatcherInterface
-{
- /**
- * @param array $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;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php
deleted file mode 100644
index 935853f1..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php
+++ /dev/null
@@ -1,43 +0,0 @@
-
- *
- * 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
- */
-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(),
- ]);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/HeaderRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/HeaderRequestMatcher.php
deleted file mode 100644
index 8617a8ac..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/HeaderRequestMatcher.php
+++ /dev/null
@@ -1,52 +0,0 @@
-
- *
- * 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
- */
-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;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php
deleted file mode 100644
index 2836759c..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- *
- * 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
- */
-class HostRequestMatcher implements RequestMatcherInterface
-{
- public function __construct(private string $regexp)
- {
- }
-
- public function matches(Request $request): bool
- {
- return preg_match('{'.$this->regexp.'}i', $request->getHost());
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php
deleted file mode 100644
index 333612e2..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php
+++ /dev/null
@@ -1,44 +0,0 @@
-
- *
- * 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
- */
-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);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php
deleted file mode 100644
index 875f992b..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php
+++ /dev/null
@@ -1,28 +0,0 @@
-
- *
- * 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
- */
-class IsJsonRequestMatcher implements RequestMatcherInterface
-{
- public function matches(Request $request): bool
- {
- return json_validate($request->getContent());
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/MethodRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/MethodRequestMatcher.php
deleted file mode 100644
index b37f6e3c..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/MethodRequestMatcher.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
- *
- * 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
- */
-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);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php
deleted file mode 100644
index c7c7a02c..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- *
- * 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
- */
-class PathRequestMatcher implements RequestMatcherInterface
-{
- public function __construct(private string $regexp)
- {
- }
-
- public function matches(Request $request): bool
- {
- return preg_match('{'.$this->regexp.'}', rawurldecode($request->getPathInfo()));
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php
deleted file mode 100644
index 5a01ce95..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- *
- * 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
- */
-class PortRequestMatcher implements RequestMatcherInterface
-{
- public function __construct(private int $port)
- {
- }
-
- public function matches(Request $request): bool
- {
- return $request->getPort() === $this->port;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/QueryParameterRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/QueryParameterRequestMatcher.php
deleted file mode 100644
index 86161e7c..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/QueryParameterRequestMatcher.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
- *
- * 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
- */
-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()));
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php b/plugins/vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php
deleted file mode 100644
index 9c9cd58b..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
- *
- * 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
- */
-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);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestMatcherInterface.php b/plugins/vendor/symfony/http-foundation/RequestMatcherInterface.php
deleted file mode 100644
index 6dcc3e0f..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestMatcherInterface.php
+++ /dev/null
@@ -1,25 +0,0 @@
-
- *
- * 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
- */
-interface RequestMatcherInterface
-{
- /**
- * Decides whether the rule(s) implemented by the strategy matches the supplied request.
- */
- public function matches(Request $request): bool;
-}
diff --git a/plugins/vendor/symfony/http-foundation/RequestStack.php b/plugins/vendor/symfony/http-foundation/RequestStack.php
deleted file mode 100644
index 153bd9ad..00000000
--- a/plugins/vendor/symfony/http-foundation/RequestStack.php
+++ /dev/null
@@ -1,124 +0,0 @@
-
- *
- * 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
- */
-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();
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/Response.php b/plugins/vendor/symfony/http-foundation/Response.php
deleted file mode 100644
index a2022976..00000000
--- a/plugins/vendor/symfony/http-foundation/Response.php
+++ /dev/null
@@ -1,1323 +0,0 @@
-
- *
- * 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(ResponseHeaderBag::class);
-
-/**
- * Response represents an HTTP response.
- *
- * @author Fabien Potencier
- */
-class Response
-{
- public const HTTP_CONTINUE = 100;
- public const HTTP_SWITCHING_PROTOCOLS = 101;
- public const HTTP_PROCESSING = 102; // RFC2518
- public const HTTP_EARLY_HINTS = 103; // RFC8297
- public const HTTP_OK = 200;
- public const HTTP_CREATED = 201;
- public const HTTP_ACCEPTED = 202;
- public const HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
- public const HTTP_NO_CONTENT = 204;
- public const HTTP_RESET_CONTENT = 205;
- public const HTTP_PARTIAL_CONTENT = 206;
- public const HTTP_MULTI_STATUS = 207; // RFC4918
- public const HTTP_ALREADY_REPORTED = 208; // RFC5842
- public const HTTP_IM_USED = 226; // RFC3229
- public const HTTP_MULTIPLE_CHOICES = 300;
- public const HTTP_MOVED_PERMANENTLY = 301;
- public const HTTP_FOUND = 302;
- public const HTTP_SEE_OTHER = 303;
- public const HTTP_NOT_MODIFIED = 304;
- public const HTTP_USE_PROXY = 305;
- public const HTTP_RESERVED = 306;
- public const HTTP_TEMPORARY_REDIRECT = 307;
- public const HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238
- public const HTTP_BAD_REQUEST = 400;
- public const HTTP_UNAUTHORIZED = 401;
- public const HTTP_PAYMENT_REQUIRED = 402;
- public const HTTP_FORBIDDEN = 403;
- public const HTTP_NOT_FOUND = 404;
- public const HTTP_METHOD_NOT_ALLOWED = 405;
- public const HTTP_NOT_ACCEPTABLE = 406;
- public const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
- public const HTTP_REQUEST_TIMEOUT = 408;
- public const HTTP_CONFLICT = 409;
- public const HTTP_GONE = 410;
- public const HTTP_LENGTH_REQUIRED = 411;
- public const HTTP_PRECONDITION_FAILED = 412;
- public const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
- public const HTTP_REQUEST_URI_TOO_LONG = 414;
- public const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
- public const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
- public const HTTP_EXPECTATION_FAILED = 417;
- public const HTTP_I_AM_A_TEAPOT = 418; // RFC2324
- public const HTTP_MISDIRECTED_REQUEST = 421; // RFC7540
- public const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
- public const HTTP_LOCKED = 423; // RFC4918
- public const HTTP_FAILED_DEPENDENCY = 424; // RFC4918
- public const HTTP_TOO_EARLY = 425; // RFC-ietf-httpbis-replay-04
- public const HTTP_UPGRADE_REQUIRED = 426; // RFC2817
- public const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
- public const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
- public const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
- public const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; // RFC7725
- public const HTTP_INTERNAL_SERVER_ERROR = 500;
- public const HTTP_NOT_IMPLEMENTED = 501;
- public const HTTP_BAD_GATEWAY = 502;
- public const HTTP_SERVICE_UNAVAILABLE = 503;
- public const HTTP_GATEWAY_TIMEOUT = 504;
- public const HTTP_VERSION_NOT_SUPPORTED = 505;
- public const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295
- public const HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918
- public const HTTP_LOOP_DETECTED = 508; // RFC5842
- public const HTTP_NOT_EXTENDED = 510; // RFC2774
- public const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; // RFC6585
-
- /**
- * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
- */
- private const HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES = [
- 'must_revalidate' => false,
- 'no_cache' => false,
- 'no_store' => false,
- 'no_transform' => false,
- 'public' => false,
- 'private' => false,
- 'proxy_revalidate' => false,
- 'max_age' => true,
- 's_maxage' => true,
- 'stale_if_error' => true, // RFC5861
- 'stale_while_revalidate' => true, // RFC5861
- 'immutable' => false,
- 'last_modified' => true,
- 'etag' => true,
- ];
-
- public ResponseHeaderBag $headers;
-
- protected string $content;
- protected string $version;
- protected int $statusCode;
- protected string $statusText;
- protected ?string $charset = null;
-
- /**
- * Status codes translation table.
- *
- * The list of codes is complete according to the
- * {@link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml Hypertext Transfer Protocol (HTTP) Status Code Registry}
- * (last updated 2021-10-01).
- *
- * Unless otherwise noted, the status code is defined in RFC2616.
- *
- * @var array
- */
- public static array $statusTexts = [
- 100 => 'Continue',
- 101 => 'Switching Protocols',
- 102 => 'Processing', // RFC2518
- 103 => 'Early Hints',
- 200 => 'OK',
- 201 => 'Created',
- 202 => 'Accepted',
- 203 => 'Non-Authoritative Information',
- 204 => 'No Content',
- 205 => 'Reset Content',
- 206 => 'Partial Content',
- 207 => 'Multi-Status', // RFC4918
- 208 => 'Already Reported', // RFC5842
- 226 => 'IM Used', // RFC3229
- 300 => 'Multiple Choices',
- 301 => 'Moved Permanently',
- 302 => 'Found',
- 303 => 'See Other',
- 304 => 'Not Modified',
- 305 => 'Use Proxy',
- 307 => 'Temporary Redirect',
- 308 => 'Permanent Redirect', // RFC7238
- 400 => 'Bad Request',
- 401 => 'Unauthorized',
- 402 => 'Payment Required',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 406 => 'Not Acceptable',
- 407 => 'Proxy Authentication Required',
- 408 => 'Request Timeout',
- 409 => 'Conflict',
- 410 => 'Gone',
- 411 => 'Length Required',
- 412 => 'Precondition Failed',
- 413 => 'Content Too Large', // RFC-ietf-httpbis-semantics
- 414 => 'URI Too Long',
- 415 => 'Unsupported Media Type',
- 416 => 'Range Not Satisfiable',
- 417 => 'Expectation Failed',
- 418 => 'I\'m a teapot', // RFC2324
- 421 => 'Misdirected Request', // RFC7540
- 422 => 'Unprocessable Content', // RFC-ietf-httpbis-semantics
- 423 => 'Locked', // RFC4918
- 424 => 'Failed Dependency', // RFC4918
- 425 => 'Too Early', // RFC-ietf-httpbis-replay-04
- 426 => 'Upgrade Required', // RFC2817
- 428 => 'Precondition Required', // RFC6585
- 429 => 'Too Many Requests', // RFC6585
- 431 => 'Request Header Fields Too Large', // RFC6585
- 451 => 'Unavailable For Legal Reasons', // RFC7725
- 500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Timeout',
- 505 => 'HTTP Version Not Supported',
- 506 => 'Variant Also Negotiates', // RFC2295
- 507 => 'Insufficient Storage', // RFC4918
- 508 => 'Loop Detected', // RFC5842
- 510 => 'Not Extended', // RFC2774
- 511 => 'Network Authentication Required', // RFC6585
- ];
-
- /**
- * Tracks headers already sent in informational responses.
- */
- private array $sentHeaders;
-
- /**
- * @param int $status The HTTP status code (200 "OK" by default)
- *
- * @throws \InvalidArgumentException When the HTTP status code is not valid
- */
- public function __construct(?string $content = '', int $status = 200, array $headers = [])
- {
- $this->headers = new ResponseHeaderBag($headers);
- $this->setContent($content);
- $this->setStatusCode($status);
- $this->setProtocolVersion('1.0');
- }
-
- /**
- * Returns the Response as an HTTP string.
- *
- * The string representation of the Response is the same as the
- * one that will be sent to the client only if the prepare() method
- * has been called before.
- *
- * @see prepare()
- */
- public function __toString(): string
- {
- return
- \sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
- $this->headers."\r\n".
- $this->getContent();
- }
-
- /**
- * Clones the current Response instance.
- */
- public function __clone()
- {
- $this->headers = clone $this->headers;
- }
-
- /**
- * Prepares the Response before it is sent to the client.
- *
- * This method tweaks the Response to ensure that it is
- * compliant with RFC 2616. Most of the changes are based on
- * the Request that is "associated" with this Response.
- *
- * @return $this
- */
- public function prepare(Request $request): static
- {
- $headers = $this->headers;
-
- if ($this->isInformational() || $this->isEmpty()) {
- $this->setContent(null);
- $headers->remove('Content-Type');
- $headers->remove('Content-Length');
- // prevent PHP from sending the Content-Type header based on default_mimetype
- ini_set('default_mimetype', '');
- } else {
- // Content-type based on the Request
- if (!$headers->has('Content-Type')) {
- $format = $request->getRequestFormat(null);
- if (null !== $format && $mimeType = $request->getMimeType($format)) {
- $headers->set('Content-Type', $mimeType);
- }
- }
-
- // Fix Content-Type
- $charset = $this->charset ?: 'utf-8';
- if (!$headers->has('Content-Type')) {
- $headers->set('Content-Type', 'text/html; charset='.$charset);
- } elseif (0 === stripos($headers->get('Content-Type') ?? '', 'text/') && false === stripos($headers->get('Content-Type') ?? '', 'charset')) {
- // add the charset
- $headers->set('Content-Type', $headers->get('Content-Type').'; charset='.$charset);
- }
-
- // Fix Content-Length
- if ($headers->has('Transfer-Encoding')) {
- $headers->remove('Content-Length');
- }
-
- if ($request->isMethod('HEAD')) {
- // cf. RFC2616 14.13
- $length = $headers->get('Content-Length');
- $this->setContent(null);
- if ($length) {
- $headers->set('Content-Length', $length);
- }
- }
- }
-
- // Fix protocol
- if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) {
- $this->setProtocolVersion('1.1');
- }
-
- // Check if we need to send extra expire info headers
- if ('1.0' == $this->getProtocolVersion() && str_contains($headers->get('Cache-Control', ''), 'no-cache')) {
- $headers->set('pragma', 'no-cache');
- $headers->set('expires', -1);
- }
-
- $this->ensureIEOverSSLCompatibility($request);
-
- if ($request->isSecure()) {
- foreach ($headers->getCookies() as $cookie) {
- $cookie->setSecureDefault(true);
- }
- }
-
- return $this;
- }
-
- /**
- * Sends HTTP headers.
- *
- * @param positive-int|null $statusCode The status code to use, override the statusCode property if set and not null
- *
- * @return $this
- */
- public function sendHeaders(?int $statusCode = null): static
- {
- // headers have already been sent by the developer
- if (headers_sent()) {
- if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
- $statusCode ??= $this->statusCode;
- trigger_deprecation('symfony/http-foundation', '7.4', 'Trying to use "%s::sendHeaders()" after headers have already been sent is deprecated and will throw a PHP warning in 8.0. Use a "StreamedResponse" instead.', static::class);
- // header(\sprintf('HTTP/%s %s %s', $this->version, $statusCode, $this->statusText), true, $statusCode);
- }
-
- return $this;
- }
-
- $informationalResponse = $statusCode >= 100 && $statusCode < 200;
- if ($informationalResponse && !\function_exists('headers_send')) {
- // skip informational responses if not supported by the SAPI
- return $this;
- }
-
- // headers
- foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
- // As recommended by RFC 8297, PHP automatically copies headers from previous 103 responses, we need to deal with that if headers changed
- $previousValues = $this->sentHeaders[$name] ?? null;
- if ($previousValues === $values) {
- // Header already sent in a previous response, it will be automatically copied in this response by PHP
- continue;
- }
-
- $replace = 0 === strcasecmp($name, 'Content-Type');
-
- if (null !== $previousValues && array_diff($previousValues, $values)) {
- header_remove($name);
- $previousValues = null;
- }
-
- $newValues = null === $previousValues ? $values : array_diff($values, $previousValues);
-
- foreach ($newValues as $value) {
- header($name.': '.$value, $replace, $this->statusCode);
- }
-
- if ($informationalResponse) {
- $this->sentHeaders[$name] = $values;
- }
- }
-
- // cookies
- foreach ($this->headers->getCookies() as $cookie) {
- header('Set-Cookie: '.$cookie, false, $this->statusCode);
- }
-
- if ($informationalResponse) {
- headers_send($statusCode);
-
- return $this;
- }
-
- $statusCode ??= $this->statusCode;
-
- // status
- header(\sprintf('HTTP/%s %s %s', $this->version, $statusCode, $this->statusText), true, $statusCode);
-
- return $this;
- }
-
- /**
- * Sends content for the current web response.
- *
- * @return $this
- */
- public function sendContent(): static
- {
- echo $this->content;
-
- return $this;
- }
-
- /**
- * Sends HTTP headers and content.
- *
- * @param bool $flush Whether output buffers should be flushed
- *
- * @return $this
- */
- public function send(bool $flush = true): static
- {
- $this->sendHeaders();
- $this->sendContent();
-
- if (!$flush) {
- return $this;
- }
-
- if (\function_exists('fastcgi_finish_request')) {
- fastcgi_finish_request();
- } elseif (\function_exists('litespeed_finish_request')) {
- litespeed_finish_request();
- } elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
- static::closeOutputBuffers(0, true);
- flush();
- }
-
- return $this;
- }
-
- /**
- * Sets the response content.
- *
- * @return $this
- */
- public function setContent(?string $content): static
- {
- $this->content = $content ?? '';
-
- return $this;
- }
-
- /**
- * Gets the current response content.
- */
- public function getContent(): string|false
- {
- return $this->content;
- }
-
- /**
- * Sets the HTTP protocol version (1.0 or 1.1).
- *
- * @return $this
- *
- * @final
- */
- public function setProtocolVersion(string $version): static
- {
- $this->version = $version;
-
- return $this;
- }
-
- /**
- * Gets the HTTP protocol version.
- *
- * @final
- */
- public function getProtocolVersion(): string
- {
- return $this->version;
- }
-
- /**
- * Sets the response status code.
- *
- * If the status text is null it will be automatically populated for the known
- * status codes and left empty otherwise.
- *
- * @return $this
- *
- * @throws \InvalidArgumentException When the HTTP status code is not valid
- *
- * @final
- */
- public function setStatusCode(int $code, ?string $text = null): static
- {
- $this->statusCode = $code;
- if ($this->isInvalid()) {
- throw new \InvalidArgumentException(\sprintf('The HTTP status code "%s" is not valid.', $code));
- }
-
- if (null === $text) {
- $this->statusText = self::$statusTexts[$code] ?? 'unknown status';
-
- return $this;
- }
-
- $this->statusText = $text;
-
- return $this;
- }
-
- /**
- * Retrieves the status code for the current web response.
- *
- * @final
- */
- public function getStatusCode(): int
- {
- return $this->statusCode;
- }
-
- /**
- * Sets the response charset.
- *
- * @return $this
- *
- * @final
- */
- public function setCharset(string $charset): static
- {
- $this->charset = $charset;
-
- return $this;
- }
-
- /**
- * Retrieves the response charset.
- *
- * @final
- */
- public function getCharset(): ?string
- {
- return $this->charset;
- }
-
- /**
- * Returns true if the response may safely be kept in a shared (surrogate) cache.
- *
- * Responses marked "private" with an explicit Cache-Control directive are
- * considered uncacheable.
- *
- * Responses with neither a freshness lifetime (Expires, max-age) nor cache
- * validator (Last-Modified, ETag) are considered uncacheable because there is
- * no way to tell when or how to remove them from the cache.
- *
- * Note that RFC 7231 and RFC 7234 possibly allow for a more permissive implementation,
- * for example "status codes that are defined as cacheable by default [...]
- * can be reused by a cache with heuristic expiration unless otherwise indicated"
- * (https://tools.ietf.org/html/rfc7231#section-6.1)
- *
- * @final
- */
- public function isCacheable(): bool
- {
- if (!\in_array($this->statusCode, [200, 203, 300, 301, 302, 404, 410], true)) {
- return false;
- }
-
- if ($this->headers->hasCacheControlDirective('no-store') || $this->headers->getCacheControlDirective('private')) {
- return false;
- }
-
- return $this->isValidateable() || $this->isFresh();
- }
-
- /**
- * Returns true if the response is "fresh".
- *
- * Fresh responses may be served from cache without any interaction with the
- * origin. A response is considered fresh when it includes a Cache-Control/max-age
- * indicator or Expires header and the calculated age is less than the freshness lifetime.
- *
- * @final
- */
- public function isFresh(): bool
- {
- return $this->getTtl() > 0;
- }
-
- /**
- * Returns true if the response includes headers that can be used to validate
- * the response with the origin server using a conditional GET request.
- *
- * @final
- */
- public function isValidateable(): bool
- {
- return $this->headers->has('Last-Modified') || $this->headers->has('ETag');
- }
-
- /**
- * Marks the response as "private".
- *
- * It makes the response ineligible for serving other clients.
- *
- * @return $this
- *
- * @final
- */
- public function setPrivate(): static
- {
- $this->headers->removeCacheControlDirective('public');
- $this->headers->addCacheControlDirective('private');
-
- return $this;
- }
-
- /**
- * Marks the response as "public".
- *
- * It makes the response eligible for serving other clients.
- *
- * @return $this
- *
- * @final
- */
- public function setPublic(): static
- {
- $this->headers->addCacheControlDirective('public');
- $this->headers->removeCacheControlDirective('private');
-
- return $this;
- }
-
- /**
- * Marks the response as "immutable".
- *
- * @return $this
- *
- * @final
- */
- public function setImmutable(bool $immutable = true): static
- {
- if ($immutable) {
- $this->headers->addCacheControlDirective('immutable');
- } else {
- $this->headers->removeCacheControlDirective('immutable');
- }
-
- return $this;
- }
-
- /**
- * Returns true if the response is marked as "immutable".
- *
- * @final
- */
- public function isImmutable(): bool
- {
- return $this->headers->hasCacheControlDirective('immutable');
- }
-
- /**
- * Returns true if the response must be revalidated by shared caches once it has become stale.
- *
- * This method indicates that the response must not be served stale by a
- * cache in any circumstance without first revalidating with the origin.
- * When present, the TTL of the response should not be overridden to be
- * greater than the value provided by the origin.
- *
- * @final
- */
- public function mustRevalidate(): bool
- {
- return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->hasCacheControlDirective('proxy-revalidate');
- }
-
- /**
- * Returns the Date header as a DateTime instance.
- *
- * @throws \RuntimeException When the header is not parseable
- *
- * @final
- */
- public function getDate(): ?\DateTimeImmutable
- {
- return $this->headers->getDate('Date');
- }
-
- /**
- * Sets the Date header.
- *
- * @return $this
- *
- * @final
- */
- public function setDate(\DateTimeInterface $date): static
- {
- $date = \DateTimeImmutable::createFromInterface($date);
- $date = $date->setTimezone(new \DateTimeZone('UTC'));
- $this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT');
-
- return $this;
- }
-
- /**
- * Returns the age of the response in seconds.
- *
- * @final
- */
- public function getAge(): int
- {
- if (null !== $age = $this->headers->get('Age')) {
- return (int) $age;
- }
-
- return max(time() - (int) $this->getDate()->format('U'), 0);
- }
-
- /**
- * Marks the response stale by setting the Age header to be equal to the maximum age of the response.
- *
- * @return $this
- */
- public function expire(): static
- {
- if ($this->isFresh()) {
- $this->headers->set('Age', $this->getMaxAge());
- $this->headers->remove('Expires');
- }
-
- return $this;
- }
-
- /**
- * Returns the value of the Expires header as a DateTime instance.
- *
- * @final
- */
- public function getExpires(): ?\DateTimeImmutable
- {
- try {
- return $this->headers->getDate('Expires');
- } catch (\RuntimeException) {
- // according to RFC 2616 invalid date formats (e.g. "0" and "-1") must be treated as in the past
- return \DateTimeImmutable::createFromFormat('U', time() - 172800);
- }
- }
-
- /**
- * Sets the Expires HTTP header with a DateTime instance.
- *
- * Passing null as value will remove the header.
- *
- * @return $this
- *
- * @final
- */
- public function setExpires(?\DateTimeInterface $date): static
- {
- if (null === $date) {
- $this->headers->remove('Expires');
-
- return $this;
- }
-
- $date = \DateTimeImmutable::createFromInterface($date);
- $date = $date->setTimezone(new \DateTimeZone('UTC'));
- $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT');
-
- return $this;
- }
-
- /**
- * Returns the number of seconds after the time specified in the response's Date
- * header when the response should no longer be considered fresh.
- *
- * First, it checks for a s-maxage directive, then a max-age directive, and then it falls
- * back on an expires header. It returns null when no maximum age can be established.
- *
- * @final
- */
- public function getMaxAge(): ?int
- {
- if ($this->headers->hasCacheControlDirective('s-maxage')) {
- return (int) $this->headers->getCacheControlDirective('s-maxage');
- }
-
- if ($this->headers->hasCacheControlDirective('max-age')) {
- return (int) $this->headers->getCacheControlDirective('max-age');
- }
-
- if (null !== $expires = $this->getExpires()) {
- $maxAge = (int) $expires->format('U') - (int) $this->getDate()->format('U');
-
- return max($maxAge, 0);
- }
-
- return null;
- }
-
- /**
- * Sets the number of seconds after which the response should no longer be considered fresh.
- *
- * This method sets the Cache-Control max-age directive.
- *
- * @return $this
- *
- * @final
- */
- public function setMaxAge(int $value): static
- {
- $this->headers->addCacheControlDirective('max-age', $value);
-
- return $this;
- }
-
- /**
- * Sets the number of seconds after which the response should no longer be returned by shared caches when backend is down.
- *
- * This method sets the Cache-Control stale-if-error directive.
- *
- * @return $this
- *
- * @final
- */
- public function setStaleIfError(int $value): static
- {
- $this->headers->addCacheControlDirective('stale-if-error', $value);
-
- return $this;
- }
-
- /**
- * Sets the number of seconds after which the response should no longer return stale content by shared caches.
- *
- * This method sets the Cache-Control stale-while-revalidate directive.
- *
- * @return $this
- *
- * @final
- */
- public function setStaleWhileRevalidate(int $value): static
- {
- $this->headers->addCacheControlDirective('stale-while-revalidate', $value);
-
- return $this;
- }
-
- /**
- * Sets the number of seconds after which the response should no longer be considered fresh by shared caches.
- *
- * This method sets the Cache-Control s-maxage directive.
- *
- * @return $this
- *
- * @final
- */
- public function setSharedMaxAge(int $value): static
- {
- $this->setPublic();
- $this->headers->addCacheControlDirective('s-maxage', $value);
-
- return $this;
- }
-
- /**
- * Returns the response's time-to-live in seconds.
- *
- * It returns null when no freshness information is present in the response.
- *
- * When the response's TTL is 0, the response may not be served from cache without first
- * revalidating with the origin.
- *
- * @final
- */
- public function getTtl(): ?int
- {
- $maxAge = $this->getMaxAge();
-
- return null !== $maxAge ? max($maxAge - $this->getAge(), 0) : null;
- }
-
- /**
- * Sets the response's time-to-live for shared caches in seconds.
- *
- * This method adjusts the Cache-Control/s-maxage directive.
- *
- * @return $this
- *
- * @final
- */
- public function setTtl(int $seconds): static
- {
- $this->setSharedMaxAge($this->getAge() + $seconds);
-
- return $this;
- }
-
- /**
- * Sets the response's time-to-live for private/client caches in seconds.
- *
- * This method adjusts the Cache-Control/max-age directive.
- *
- * @return $this
- *
- * @final
- */
- public function setClientTtl(int $seconds): static
- {
- $this->setMaxAge($this->getAge() + $seconds);
-
- return $this;
- }
-
- /**
- * Returns the Last-Modified HTTP header as a DateTime instance.
- *
- * @throws \RuntimeException When the HTTP header is not parseable
- *
- * @final
- */
- public function getLastModified(): ?\DateTimeImmutable
- {
- return $this->headers->getDate('Last-Modified');
- }
-
- /**
- * Sets the Last-Modified HTTP header with a DateTime instance.
- *
- * Passing null as value will remove the header.
- *
- * @return $this
- *
- * @final
- */
- public function setLastModified(?\DateTimeInterface $date): static
- {
- if (null === $date) {
- $this->headers->remove('Last-Modified');
-
- return $this;
- }
-
- $date = \DateTimeImmutable::createFromInterface($date);
- $date = $date->setTimezone(new \DateTimeZone('UTC'));
- $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT');
-
- return $this;
- }
-
- /**
- * Returns the literal value of the ETag HTTP header.
- *
- * @final
- */
- public function getEtag(): ?string
- {
- return $this->headers->get('ETag');
- }
-
- /**
- * Sets the ETag value.
- *
- * @param string|null $etag The ETag unique identifier or null to remove the header
- * @param bool $weak Whether you want a weak ETag or not
- *
- * @return $this
- *
- * @final
- */
- public function setEtag(?string $etag, bool $weak = false): static
- {
- if (null === $etag) {
- $this->headers->remove('Etag');
- } else {
- if (!str_starts_with($etag, '"')) {
- $etag = '"'.$etag.'"';
- }
-
- $this->headers->set('ETag', (true === $weak ? 'W/' : '').$etag);
- }
-
- return $this;
- }
-
- /**
- * Sets the response's cache headers (validation and/or expiration).
- *
- * Available options are: must_revalidate, no_cache, no_store, no_transform, public, private, proxy_revalidate, max_age, s_maxage, immutable, last_modified and etag.
- *
- * @return $this
- *
- * @throws \InvalidArgumentException
- *
- * @final
- */
- public function setCache(array $options): static
- {
- if ($diff = array_diff(array_keys($options), array_keys(self::HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES))) {
- throw new \InvalidArgumentException(\sprintf('Response does not support the following options: "%s".', implode('", "', $diff)));
- }
-
- if (isset($options['etag'])) {
- $this->setEtag($options['etag']);
- }
-
- if (isset($options['last_modified'])) {
- $this->setLastModified($options['last_modified']);
- }
-
- if (isset($options['max_age'])) {
- $this->setMaxAge($options['max_age']);
- }
-
- if (isset($options['s_maxage'])) {
- $this->setSharedMaxAge($options['s_maxage']);
- }
-
- if (isset($options['stale_while_revalidate'])) {
- $this->setStaleWhileRevalidate($options['stale_while_revalidate']);
- }
-
- if (isset($options['stale_if_error'])) {
- $this->setStaleIfError($options['stale_if_error']);
- }
-
- foreach (self::HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES as $directive => $hasValue) {
- if (!$hasValue && isset($options[$directive])) {
- if ($options[$directive]) {
- $this->headers->addCacheControlDirective(str_replace('_', '-', $directive));
- } else {
- $this->headers->removeCacheControlDirective(str_replace('_', '-', $directive));
- }
- }
- }
-
- if (isset($options['public'])) {
- if ($options['public']) {
- $this->setPublic();
- } else {
- $this->setPrivate();
- }
- }
-
- if (isset($options['private'])) {
- if ($options['private']) {
- $this->setPrivate();
- } else {
- $this->setPublic();
- }
- }
-
- return $this;
- }
-
- /**
- * Modifies the response so that it conforms to the rules defined for a 304 status code.
- *
- * This sets the status, removes the body, and discards any headers
- * that MUST NOT be included in 304 responses.
- *
- * @return $this
- *
- * @see https://tools.ietf.org/html/rfc2616#section-10.3.5
- *
- * @final
- */
- public function setNotModified(): static
- {
- $this->setStatusCode(304);
- $this->setContent(null);
-
- // remove headers that MUST NOT be included with 304 Not Modified responses
- foreach (['Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-MD5', 'Content-Type', 'Last-Modified'] as $header) {
- $this->headers->remove($header);
- }
-
- return $this;
- }
-
- /**
- * Returns true if the response includes a Vary header.
- *
- * @final
- */
- public function hasVary(): bool
- {
- return null !== $this->headers->get('Vary');
- }
-
- /**
- * Returns an array of header names given in the Vary header.
- *
- * @final
- */
- public function getVary(): array
- {
- if (!$vary = $this->headers->all('Vary')) {
- return [];
- }
-
- $ret = [];
- foreach ($vary as $item) {
- $ret[] = preg_split('/[\s,]+/', $item);
- }
-
- return array_merge([], ...$ret);
- }
-
- /**
- * Sets the Vary header.
- *
- * @param bool $replace Whether to replace the actual value or not (true by default)
- *
- * @return $this
- *
- * @final
- */
- public function setVary(string|array $headers, bool $replace = true): static
- {
- $this->headers->set('Vary', $headers, $replace);
-
- return $this;
- }
-
- /**
- * Determines if the Response validators (ETag, Last-Modified) match
- * a conditional value specified in the Request.
- *
- * If the Response is not modified, it sets the status code to 304 and
- * removes the actual content by calling the setNotModified() method.
- *
- * @final
- */
- public function isNotModified(Request $request): bool
- {
- if (!$request->isMethodCacheable()) {
- return false;
- }
-
- $notModified = false;
- $lastModified = $this->headers->get('Last-Modified');
- $modifiedSince = $request->headers->get('If-Modified-Since');
-
- if (($ifNoneMatchEtags = $request->getETags()) && (null !== $etag = $this->getEtag())) {
- if (0 == strncmp($etag, 'W/', 2)) {
- $etag = substr($etag, 2);
- }
-
- // Use weak comparison as per https://tools.ietf.org/html/rfc7232#section-3.2.
- foreach ($ifNoneMatchEtags as $ifNoneMatchEtag) {
- if (0 == strncmp($ifNoneMatchEtag, 'W/', 2)) {
- $ifNoneMatchEtag = substr($ifNoneMatchEtag, 2);
- }
-
- if ($ifNoneMatchEtag === $etag || '*' === $ifNoneMatchEtag) {
- $notModified = true;
- break;
- }
- }
- }
- // Only do If-Modified-Since date comparison when If-None-Match is not present as per https://tools.ietf.org/html/rfc7232#section-3.3.
- elseif ($modifiedSince && $lastModified) {
- $notModified = strtotime($modifiedSince) >= strtotime($lastModified);
- }
-
- if ($notModified) {
- $this->setNotModified();
- }
-
- return $notModified;
- }
-
- /**
- * Is response invalid?
- *
- * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- *
- * @final
- */
- public function isInvalid(): bool
- {
- return $this->statusCode < 100 || $this->statusCode >= 600;
- }
-
- /**
- * Is response informative?
- *
- * @final
- */
- public function isInformational(): bool
- {
- return $this->statusCode >= 100 && $this->statusCode < 200;
- }
-
- /**
- * Is response successful?
- *
- * @final
- */
- public function isSuccessful(): bool
- {
- return $this->statusCode >= 200 && $this->statusCode < 300;
- }
-
- /**
- * Is the response a redirect?
- *
- * @final
- */
- public function isRedirection(): bool
- {
- return $this->statusCode >= 300 && $this->statusCode < 400;
- }
-
- /**
- * Is there a client error?
- *
- * @final
- */
- public function isClientError(): bool
- {
- return $this->statusCode >= 400 && $this->statusCode < 500;
- }
-
- /**
- * Was there a server side error?
- *
- * @final
- */
- public function isServerError(): bool
- {
- return $this->statusCode >= 500 && $this->statusCode < 600;
- }
-
- /**
- * Is the response OK?
- *
- * @final
- */
- public function isOk(): bool
- {
- return 200 === $this->statusCode;
- }
-
- /**
- * Is the response forbidden?
- *
- * @final
- */
- public function isForbidden(): bool
- {
- return 403 === $this->statusCode;
- }
-
- /**
- * Is the response a not found error?
- *
- * @final
- */
- public function isNotFound(): bool
- {
- return 404 === $this->statusCode;
- }
-
- /**
- * Is the response a redirect of some form?
- *
- * @final
- */
- public function isRedirect(?string $location = null): bool
- {
- return \in_array($this->statusCode, [201, 301, 302, 303, 307, 308], true) && (null === $location ?: $location == $this->headers->get('Location'));
- }
-
- /**
- * Is the response empty?
- *
- * @final
- */
- public function isEmpty(): bool
- {
- return \in_array($this->statusCode, [204, 304], true);
- }
-
- /**
- * Cleans or flushes output buffers up to target level.
- *
- * Resulting level can be greater than target level if a non-removable buffer has been encountered.
- *
- * @final
- */
- public static function closeOutputBuffers(int $targetLevel, bool $flush): void
- {
- $status = ob_get_status(true);
- $level = \count($status);
- $flags = \PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? \PHP_OUTPUT_HANDLER_FLUSHABLE : \PHP_OUTPUT_HANDLER_CLEANABLE);
-
- while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || ($s['flags'] & $flags) === $flags : $s['del'])) {
- if ($flush) {
- ob_end_flush();
- } else {
- ob_end_clean();
- }
- }
- }
-
- /**
- * Marks a response as safe according to RFC8674.
- *
- * @see https://tools.ietf.org/html/rfc8674
- */
- public function setContentSafe(bool $safe = true): void
- {
- if ($safe) {
- $this->headers->set('Preference-Applied', 'safe');
- } elseif ('safe' === $this->headers->get('Preference-Applied')) {
- $this->headers->remove('Preference-Applied');
- }
-
- $this->setVary('Prefer', false);
- }
-
- /**
- * Checks if we need to remove Cache-Control for SSL encrypted downloads when using IE < 9.
- *
- * @see http://support.microsoft.com/kb/323308
- *
- * @final
- */
- protected function ensureIEOverSSLCompatibility(Request $request): void
- {
- if (false !== stripos($this->headers->get('Content-Disposition') ?? '', 'attachment') && 1 == preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT') ?? '', $match) && true === $request->isSecure()) {
- if ((int) preg_replace('/(MSIE )(.*?);/', '$2', $match[0]) < 9) {
- $this->headers->remove('Cache-Control');
- }
- }
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/ResponseHeaderBag.php b/plugins/vendor/symfony/http-foundation/ResponseHeaderBag.php
deleted file mode 100644
index ff6ae1ef..00000000
--- a/plugins/vendor/symfony/http-foundation/ResponseHeaderBag.php
+++ /dev/null
@@ -1,271 +0,0 @@
-
- *
- * 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
- */
-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.
- *
- * @param bool $partitioned
- */
- public function clearCookie(string $name, ?string $path = '/', ?string $domain = null, bool $secure = false, bool $httpOnly = true, ?string $sameSite = null /* , bool $partitioned = false */): void
- {
- $partitioned = 6 < \func_num_args() ? func_get_arg(6) : false;
-
- $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');
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/ServerBag.php b/plugins/vendor/symfony/http-foundation/ServerBag.php
deleted file mode 100644
index 09fc3866..00000000
--- a/plugins/vendor/symfony/http-foundation/ServerBag.php
+++ /dev/null
@@ -1,97 +0,0 @@
-
- *
- * 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
- * @author Bulat Shakirzyanov
- * @author Robert Kiss
- */
-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;
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/ServerEvent.php b/plugins/vendor/symfony/http-foundation/ServerEvent.php
deleted file mode 100644
index 7597058b..00000000
--- a/plugins/vendor/symfony/http-foundation/ServerEvent.php
+++ /dev/null
@@ -1,145 +0,0 @@
-
- *
- * 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
- *
- * @author Yonel Ceruto
- */
-class ServerEvent implements \IteratorAggregate
-{
- /**
- * @param string|iterable $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
- */
- 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";
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php b/plugins/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php
deleted file mode 100644
index e34a497c..00000000
--- a/plugins/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php
+++ /dev/null
@@ -1,117 +0,0 @@
-
- *
- * 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
- */
-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
- */
- public function getIterator(): \ArrayIterator
- {
- return new \ArrayIterator($this->attributes);
- }
-
- /**
- * Returns the number of attributes.
- */
- public function count(): int
- {
- return \count($this->attributes);
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php b/plugins/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php
deleted file mode 100644
index 39ec9d75..00000000
--- a/plugins/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php
+++ /dev/null
@@ -1,53 +0,0 @@
-
- *
- * 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
- */
-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
- */
- 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;
-}
diff --git a/plugins/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php b/plugins/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php
deleted file mode 100644
index bfb856d5..00000000
--- a/plugins/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php
+++ /dev/null
@@ -1,121 +0,0 @@
-
- *
- * 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
- */
-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();
- }
-}
diff --git a/plugins/vendor/symfony/http-foundation/Session/Flash/FlashBag.php b/plugins/vendor/symfony/http-foundation/Session/Flash/FlashBag.php
deleted file mode 100644
index 72753a66..00000000
--- a/plugins/vendor/symfony/http-foundation/Session/Flash/FlashBag.php
+++ /dev/null
@@ -1,112 +0,0 @@
-
- *
- * 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