Aggiornato Composer
This commit is contained in:
@@ -34,6 +34,7 @@ class BinaryFileResponse extends Response
|
||||
protected $offset = 0;
|
||||
protected $maxlen = -1;
|
||||
protected $deleteFileAfterSend = false;
|
||||
protected $chunkSize = 16 * 1024;
|
||||
|
||||
/**
|
||||
* @param \SplFileInfo|string $file The file to stream
|
||||
@@ -44,7 +45,7 @@ class BinaryFileResponse extends Response
|
||||
* @param bool $autoEtag Whether the ETag header should be automatically set
|
||||
* @param bool $autoLastModified Whether the Last-Modified header should be automatically set
|
||||
*/
|
||||
public function __construct($file, int $status = 200, array $headers = [], bool $public = true, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
|
||||
public function __construct($file, int $status = 200, array $headers = [], bool $public = true, ?string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
|
||||
{
|
||||
parent::__construct(null, $status, $headers);
|
||||
|
||||
@@ -68,7 +69,7 @@ class BinaryFileResponse extends Response
|
||||
*
|
||||
* @deprecated since Symfony 5.2, use __construct() instead.
|
||||
*/
|
||||
public static function create($file = null, int $status = 200, array $headers = [], bool $public = true, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
|
||||
public static function create($file = null, int $status = 200, array $headers = [], bool $public = true, ?string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
|
||||
{
|
||||
trigger_deprecation('symfony/http-foundation', '5.2', 'The "%s()" method is deprecated, use "new %s()" instead.', __METHOD__, static::class);
|
||||
|
||||
@@ -84,7 +85,7 @@ class BinaryFileResponse extends Response
|
||||
*
|
||||
* @throws FileException
|
||||
*/
|
||||
public function setFile($file, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
|
||||
public function setFile($file, ?string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
|
||||
{
|
||||
if (!$file instanceof File) {
|
||||
if ($file instanceof \SplFileInfo) {
|
||||
@@ -125,6 +126,22 @@ class BinaryFileResponse extends Response
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the response stream chunk size.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setChunkSize(int $chunkSize): self
|
||||
{
|
||||
if ($chunkSize < 1 || $chunkSize > \PHP_INT_MAX) {
|
||||
throw new \LogicException('The chunk size of a BinaryFileResponse cannot be less than 1 or greater than PHP_INT_MAX.');
|
||||
}
|
||||
|
||||
$this->chunkSize = $chunkSize;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically sets the Last-Modified header according the file modification date.
|
||||
*
|
||||
@@ -189,15 +206,19 @@ class BinaryFileResponse extends Response
|
||||
*/
|
||||
public function prepare(Request $request)
|
||||
{
|
||||
if ($this->isInformational() || $this->isEmpty()) {
|
||||
parent::prepare($request);
|
||||
|
||||
$this->maxlen = 0;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (!$this->headers->has('Content-Type')) {
|
||||
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
|
||||
}
|
||||
|
||||
if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) {
|
||||
$this->setProtocolVersion('1.1');
|
||||
}
|
||||
|
||||
$this->ensureIEOverSSLCompatibility($request);
|
||||
parent::prepare($request);
|
||||
|
||||
$this->offset = 0;
|
||||
$this->maxlen = -1;
|
||||
@@ -205,6 +226,7 @@ class BinaryFileResponse extends Response
|
||||
if (false === $fileSize = $this->file->getSize()) {
|
||||
return $this;
|
||||
}
|
||||
$this->headers->remove('Transfer-Encoding');
|
||||
$this->headers->set('Content-Length', $fileSize);
|
||||
|
||||
if (!$this->headers->has('Accept-Ranges')) {
|
||||
@@ -245,7 +267,7 @@ class BinaryFileResponse extends Response
|
||||
$range = $request->headers->get('Range');
|
||||
|
||||
if (str_starts_with($range, 'bytes=')) {
|
||||
[$start, $end] = explode('-', substr($range, 6), 2) + [0];
|
||||
[$start, $end] = explode('-', substr($range, 6), 2) + [1 => 0];
|
||||
|
||||
$end = ('' === $end) ? $fileSize - 1 : (int) $end;
|
||||
|
||||
@@ -274,6 +296,10 @@ class BinaryFileResponse extends Response
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->isMethod('HEAD')) {
|
||||
$this->maxlen = 0;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -295,24 +321,49 @@ class BinaryFileResponse extends Response
|
||||
*/
|
||||
public function sendContent()
|
||||
{
|
||||
if (!$this->isSuccessful()) {
|
||||
return parent::sendContent();
|
||||
}
|
||||
try {
|
||||
if (!$this->isSuccessful()) {
|
||||
return parent::sendContent();
|
||||
}
|
||||
|
||||
if (0 === $this->maxlen) {
|
||||
return $this;
|
||||
}
|
||||
if (0 === $this->maxlen) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$out = fopen('php://output', 'w');
|
||||
$file = fopen($this->file->getPathname(), 'r');
|
||||
$out = fopen('php://output', 'w');
|
||||
$file = fopen($this->file->getPathname(), 'r');
|
||||
|
||||
stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);
|
||||
ignore_user_abort(true);
|
||||
|
||||
fclose($out);
|
||||
fclose($file);
|
||||
if (0 !== $this->offset) {
|
||||
fseek($file, $this->offset);
|
||||
}
|
||||
|
||||
if ($this->deleteFileAfterSend && is_file($this->file->getPathname())) {
|
||||
unlink($this->file->getPathname());
|
||||
$length = $this->maxlen;
|
||||
while ($length && !feof($file)) {
|
||||
$read = $length > $this->chunkSize || 0 > $length ? $this->chunkSize : $length;
|
||||
|
||||
if (false === $data = fread($file, $read)) {
|
||||
break;
|
||||
}
|
||||
while ('' !== $data) {
|
||||
$read = fwrite($out, $data);
|
||||
if (false === $read || connection_aborted()) {
|
||||
break 2;
|
||||
}
|
||||
if (0 < $length) {
|
||||
$length -= $read;
|
||||
}
|
||||
$data = substr($data, $read);
|
||||
}
|
||||
}
|
||||
|
||||
fclose($out);
|
||||
fclose($file);
|
||||
} finally {
|
||||
if ($this->deleteFileAfterSend && is_file($this->file->getPathname())) {
|
||||
unlink($this->file->getPathname());
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
||||
6
vendor/symfony/http-foundation/Cookie.php
vendored
6
vendor/symfony/http-foundation/Cookie.php
vendored
@@ -71,7 +71,7 @@ class Cookie
|
||||
return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']);
|
||||
}
|
||||
|
||||
public static function create(string $name, string $value = null, $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX): self
|
||||
public static function create(string $name, ?string $value = null, $expire = 0, ?string $path = '/', ?string $domain = null, ?bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX): self
|
||||
{
|
||||
return new self($name, $value, $expire, $path, $domain, $secure, $httpOnly, $raw, $sameSite);
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class Cookie
|
||||
* @param string $name The name of the cookie
|
||||
* @param string|null $value The value of the cookie
|
||||
* @param int|string|\DateTimeInterface $expire The time the cookie expires
|
||||
* @param string $path The path on the server in which the cookie will be available on
|
||||
* @param string|null $path The path on the server in which the cookie will be available on
|
||||
* @param string|null $domain The domain that the cookie is available to
|
||||
* @param bool|null $secure Whether the client should send back the cookie only over HTTPS or null to auto-enable this when the request is already using HTTPS
|
||||
* @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
|
||||
@@ -89,7 +89,7 @@ class Cookie
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(string $name, string $value = null, $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = 'lax')
|
||||
public function __construct(string $name, ?string $value = null, $expire = 0, ?string $path = '/', ?string $domain = null, ?bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = 'lax')
|
||||
{
|
||||
// from PHP source code
|
||||
if ($raw && false !== strpbrk($name, self::RESERVED_CHARS_LIST)) {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace Symfony\Component\HttpFoundation\Exception;
|
||||
|
||||
/**
|
||||
* Raised when a session does not exists. This happens in the following cases:
|
||||
* Raised when a session does not exist. This happens in the following cases:
|
||||
* - the session is not enabled
|
||||
* - attempt to read a session outside a request context (ie. cli script).
|
||||
*
|
||||
@@ -20,7 +20,7 @@ namespace Symfony\Component\HttpFoundation\Exception;
|
||||
*/
|
||||
class SessionNotFoundException extends \LogicException implements RequestExceptionInterface
|
||||
{
|
||||
public function __construct(string $message = 'There is currently no session available.', int $code = 0, \Throwable $previous = null)
|
||||
public function __construct(string $message = 'There is currently no session available.', int $code = 0, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
4
vendor/symfony/http-foundation/File/File.php
vendored
4
vendor/symfony/http-foundation/File/File.php
vendored
@@ -88,7 +88,7 @@ class File extends \SplFileInfo
|
||||
*
|
||||
* @throws FileException if the target file could not be created
|
||||
*/
|
||||
public function move(string $directory, string $name = null)
|
||||
public function move(string $directory, ?string $name = null)
|
||||
{
|
||||
$target = $this->getTargetFile($directory, $name);
|
||||
|
||||
@@ -121,7 +121,7 @@ class File extends \SplFileInfo
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
protected function getTargetFile(string $directory, string $name = null)
|
||||
protected function getTargetFile(string $directory, ?string $name = null)
|
||||
{
|
||||
if (!is_dir($directory)) {
|
||||
if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) {
|
||||
|
||||
@@ -60,7 +60,7 @@ class UploadedFile extends File
|
||||
* @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, bool $test = false)
|
||||
public function __construct(string $path, string $originalName, ?string $mimeType = null, ?int $error = null, bool $test = false)
|
||||
{
|
||||
$this->originalName = $this->getName($originalName);
|
||||
$this->mimeType = $mimeType ?: 'application/octet-stream';
|
||||
@@ -74,7 +74,7 @@ class UploadedFile extends File
|
||||
* Returns the original file name.
|
||||
*
|
||||
* It is extracted from the request from which the file has been uploaded.
|
||||
* Then it should not be considered as a safe value.
|
||||
* This should not be considered as a safe value to use for a file name on your servers.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -87,7 +87,7 @@ class UploadedFile extends File
|
||||
* Returns the original file extension.
|
||||
*
|
||||
* It is extracted from the original file name that was uploaded.
|
||||
* Then it should not be considered as a safe value.
|
||||
* This should not be considered as a safe value to use for a file name on your servers.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -172,7 +172,7 @@ class UploadedFile extends File
|
||||
*
|
||||
* @throws FileException if, for any reason, the file could not have been moved
|
||||
*/
|
||||
public function move(string $directory, string $name = null)
|
||||
public function move(string $directory, ?string $name = null)
|
||||
{
|
||||
if ($this->isValid()) {
|
||||
if ($this->test) {
|
||||
@@ -223,8 +223,8 @@ class UploadedFile extends File
|
||||
*/
|
||||
public static function getMaxFilesize()
|
||||
{
|
||||
$sizePostMax = self::parseFilesize(ini_get('post_max_size'));
|
||||
$sizeUploadMax = self::parseFilesize(ini_get('upload_max_filesize'));
|
||||
$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);
|
||||
}
|
||||
@@ -253,11 +253,11 @@ class UploadedFile extends File
|
||||
|
||||
switch (substr($size, -1)) {
|
||||
case 't': $max *= 1024;
|
||||
// no break
|
||||
// no break
|
||||
case 'g': $max *= 1024;
|
||||
// no break
|
||||
// no break
|
||||
case 'm': $max *= 1024;
|
||||
// no break
|
||||
// no break
|
||||
case 'k': $max *= 1024;
|
||||
}
|
||||
|
||||
|
||||
6
vendor/symfony/http-foundation/HeaderBag.php
vendored
6
vendor/symfony/http-foundation/HeaderBag.php
vendored
@@ -67,7 +67,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
|
||||
*
|
||||
* @return array<string, array<int, string|null>>|array<int, string|null>
|
||||
*/
|
||||
public function all(string $key = null)
|
||||
public function all(?string $key = null)
|
||||
{
|
||||
if (null !== $key) {
|
||||
return $this->headers[strtr($key, self::UPPER, self::LOWER)] ?? [];
|
||||
@@ -110,7 +110,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get(string $key, string $default = null)
|
||||
public function get(string $key, ?string $default = null)
|
||||
{
|
||||
$headers = $this->all($key);
|
||||
|
||||
@@ -197,7 +197,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
|
||||
*
|
||||
* @throws \RuntimeException When the HTTP header is not parseable
|
||||
*/
|
||||
public function getDate(string $key, \DateTime $default = null)
|
||||
public function getDate(string $key, ?\DateTime $default = null)
|
||||
{
|
||||
if (null === $value = $this->get($key)) {
|
||||
return $default;
|
||||
|
||||
65
vendor/symfony/http-foundation/HeaderUtils.php
vendored
65
vendor/symfony/http-foundation/HeaderUtils.php
vendored
@@ -33,17 +33,21 @@ class HeaderUtils
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* HeaderUtils::split("da, en-gb;q=0.8", ",;")
|
||||
* HeaderUtils::split('da, en-gb;q=0.8', ',;')
|
||||
* // => ['da'], ['en-gb', 'q=0.8']]
|
||||
*
|
||||
* @param string $separators List of characters to split on, ordered by
|
||||
* precedence, e.g. ",", ";=", or ",;="
|
||||
* 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('
|
||||
@@ -77,8 +81,8 @@ class HeaderUtils
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* HeaderUtils::combine([["foo", "abc"], ["bar"]])
|
||||
* // => ["foo" => "abc", "bar" => true]
|
||||
* HeaderUtils::combine([['foo', 'abc'], ['bar']])
|
||||
* // => ['foo' => 'abc', 'bar' => true]
|
||||
*/
|
||||
public static function combine(array $parts): array
|
||||
{
|
||||
@@ -95,13 +99,13 @@ class HeaderUtils
|
||||
/**
|
||||
* 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
|
||||
* 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"], ",")
|
||||
* 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
|
||||
@@ -138,7 +142,7 @@ class HeaderUtils
|
||||
* Decodes a quoted string.
|
||||
*
|
||||
* If passed an unquoted string that matches the "token" construct (as
|
||||
* defined in the HTTP specification), it is passed through verbatimly.
|
||||
* defined in the HTTP specification), it is passed through verbatim.
|
||||
*/
|
||||
public static function unquote(string $s): string
|
||||
{
|
||||
@@ -252,40 +256,37 @@ class HeaderUtils
|
||||
private static function groupParts(array $matches, string $separators, bool $first = true): array
|
||||
{
|
||||
$separator = $separators[0];
|
||||
$partSeparators = substr($separators, 1);
|
||||
|
||||
$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 = [];
|
||||
$previousMatchWasSeparator = false;
|
||||
|
||||
foreach ($matches as $match) {
|
||||
if (!$first && $previousMatchWasSeparator && isset($match['separator']) && $match['separator'] === $separator) {
|
||||
$previousMatchWasSeparator = true;
|
||||
$partMatches[$i][] = $match;
|
||||
} elseif (isset($match['separator']) && $match['separator'] === $separator) {
|
||||
$previousMatchWasSeparator = true;
|
||||
if (($match['separator'] ?? null) === $separator) {
|
||||
++$i;
|
||||
} else {
|
||||
$previousMatchWasSeparator = false;
|
||||
$partMatches[$i][] = $match;
|
||||
}
|
||||
}
|
||||
|
||||
$parts = [];
|
||||
if ($partSeparators) {
|
||||
foreach ($partMatches as $matches) {
|
||||
$parts[] = self::groupParts($matches, $partSeparators, false);
|
||||
}
|
||||
} else {
|
||||
foreach ($partMatches as $matches) {
|
||||
$parts[] = self::unquote($matches[0][0]);
|
||||
}
|
||||
|
||||
if (!$first && 2 < \count($parts)) {
|
||||
$parts = [
|
||||
$parts[0],
|
||||
implode($separator, \array_slice($parts, 1)),
|
||||
];
|
||||
}
|
||||
foreach ($partMatches as $matches) {
|
||||
$parts[] = '' === $separators ? self::unquote($matches[0][0]) : self::groupParts($matches, $separators, false);
|
||||
}
|
||||
|
||||
return $parts;
|
||||
|
||||
10
vendor/symfony/http-foundation/InputBag.php
vendored
10
vendor/symfony/http-foundation/InputBag.php
vendored
@@ -29,14 +29,14 @@ final class InputBag extends ParameterBag
|
||||
*/
|
||||
public function get(string $key, $default = null)
|
||||
{
|
||||
if (null !== $default && !is_scalar($default) && !(\is_object($default) && method_exists($default, '__toString'))) {
|
||||
if (null !== $default && !\is_scalar($default) && !(\is_object($default) && method_exists($default, '__toString'))) {
|
||||
trigger_deprecation('symfony/http-foundation', '5.1', 'Passing a non-scalar value as 2nd argument to "%s()" is deprecated, pass a scalar or null instead.', __METHOD__);
|
||||
}
|
||||
|
||||
$value = parent::get($key, $this);
|
||||
|
||||
if (null !== $value && $this !== $value && !is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) {
|
||||
trigger_deprecation('symfony/http-foundation', '5.1', 'Retrieving a non-string value from "%s()" is deprecated, and will throw a "%s" exception in Symfony 6.0, use "%s::all($key)" instead.', __METHOD__, BadRequestException::class, __CLASS__);
|
||||
if (null !== $value && $this !== $value && !\is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) {
|
||||
trigger_deprecation('symfony/http-foundation', '5.1', 'Retrieving a non-scalar value from "%s()" is deprecated, and will throw a "%s" exception in Symfony 6.0, use "%s::all($key)" instead.', __METHOD__, BadRequestException::class, __CLASS__);
|
||||
}
|
||||
|
||||
return $this === $value ? $default : $value;
|
||||
@@ -45,7 +45,7 @@ final class InputBag extends ParameterBag
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function all(string $key = null): array
|
||||
public function all(?string $key = null): array
|
||||
{
|
||||
return parent::all($key);
|
||||
}
|
||||
@@ -76,7 +76,7 @@ final class InputBag extends ParameterBag
|
||||
*/
|
||||
public function set(string $key, $value)
|
||||
{
|
||||
if (null !== $value && !is_scalar($value) && !\is_array($value) && !method_exists($value, '__toString')) {
|
||||
if (null !== $value && !\is_scalar($value) && !\is_array($value) && !method_exists($value, '__toString')) {
|
||||
trigger_deprecation('symfony/http-foundation', '5.1', 'Passing "%s" as a 2nd Argument to "%s()" is deprecated, pass a scalar, array, or null instead.', get_debug_type($value), __METHOD__);
|
||||
}
|
||||
|
||||
|
||||
19
vendor/symfony/http-foundation/IpUtils.php
vendored
19
vendor/symfony/http-foundation/IpUtils.php
vendored
@@ -73,7 +73,7 @@ class IpUtils
|
||||
return false;
|
||||
}
|
||||
|
||||
$cacheKey = $requestIp.'-'.$ip;
|
||||
$cacheKey = $requestIp.'-'.$ip.'-v4';
|
||||
if (isset(self::$checkedIps[$cacheKey])) {
|
||||
return self::$checkedIps[$cacheKey];
|
||||
}
|
||||
@@ -86,7 +86,7 @@ class IpUtils
|
||||
[$address, $netmask] = explode('/', $ip, 2);
|
||||
|
||||
if ('0' === $netmask) {
|
||||
return self::$checkedIps[$cacheKey] = filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4);
|
||||
return self::$checkedIps[$cacheKey] = false !== filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4);
|
||||
}
|
||||
|
||||
if ($netmask < 0 || $netmask > 32) {
|
||||
@@ -126,7 +126,7 @@ class IpUtils
|
||||
return false;
|
||||
}
|
||||
|
||||
$cacheKey = $requestIp.'-'.$ip;
|
||||
$cacheKey = $requestIp.'-'.$ip.'-v6';
|
||||
if (isset(self::$checkedIps[$cacheKey])) {
|
||||
return self::$checkedIps[$cacheKey];
|
||||
}
|
||||
@@ -135,9 +135,18 @@ class IpUtils
|
||||
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::$checkedIps[$cacheKey] = false;
|
||||
}
|
||||
|
||||
if (str_contains($ip, '/')) {
|
||||
[$address, $netmask] = explode('/', $ip, 2);
|
||||
|
||||
if (!filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
|
||||
return self::$checkedIps[$cacheKey] = false;
|
||||
}
|
||||
|
||||
if ('0' === $netmask) {
|
||||
return (bool) unpack('n*', @inet_pton($address));
|
||||
}
|
||||
@@ -146,6 +155,10 @@ class IpUtils
|
||||
return self::$checkedIps[$cacheKey] = false;
|
||||
}
|
||||
} else {
|
||||
if (!filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
|
||||
return self::$checkedIps[$cacheKey] = false;
|
||||
}
|
||||
|
||||
$address = $ip;
|
||||
$netmask = 128;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class JsonResponse extends Response
|
||||
*
|
||||
* @throws \InvalidArgumentException When the callback name is not valid
|
||||
*/
|
||||
public function setCallback(string $callback = null)
|
||||
public function setCallback(?string $callback = null)
|
||||
{
|
||||
if (null !== $callback) {
|
||||
// partially taken from https://geekality.net/2011/08/03/valid-javascript-identifier/
|
||||
|
||||
2
vendor/symfony/http-foundation/LICENSE
vendored
2
vendor/symfony/http-foundation/LICENSE
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2022 Fabien Potencier
|
||||
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
|
||||
|
||||
@@ -39,7 +39,7 @@ class ParameterBag implements \IteratorAggregate, \Countable
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all(/*string $key = null*/)
|
||||
public function all(/* ?string $key = null */)
|
||||
{
|
||||
$key = \func_num_args() > 0 ? func_get_arg(0) : null;
|
||||
|
||||
|
||||
@@ -35,9 +35,7 @@ abstract class AbstractRequestRateLimiter implements RequestRateLimiterInterface
|
||||
foreach ($limiters as $limiter) {
|
||||
$rateLimit = $limiter->consume(1);
|
||||
|
||||
if (null === $minimalRateLimit || $rateLimit->getRemainingTokens() < $minimalRateLimit->getRemainingTokens()) {
|
||||
$minimalRateLimit = $rateLimit;
|
||||
}
|
||||
$minimalRateLimit = $minimalRateLimit ? self::getMinimalRateLimit($minimalRateLimit, $rateLimit) : $rateLimit;
|
||||
}
|
||||
|
||||
return $minimalRateLimit;
|
||||
@@ -54,4 +52,20 @@ abstract class AbstractRequestRateLimiter implements RequestRateLimiterInterface
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ class RedirectResponse extends Response
|
||||
</html>', htmlspecialchars($url, \ENT_QUOTES, 'UTF-8')));
|
||||
|
||||
$this->headers->set('Location', $url);
|
||||
$this->headers->set('Content-Type', 'text/html; charset=utf-8');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
71
vendor/symfony/http-foundation/Request.php
vendored
71
vendor/symfony/http-foundation/Request.php
vendored
@@ -191,7 +191,7 @@ class Request
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $locale;
|
||||
|
||||
@@ -246,6 +246,9 @@ class Request
|
||||
self::HEADER_X_FORWARDED_PREFIX => 'X_FORWARDED_PREFIX',
|
||||
];
|
||||
|
||||
/** @var bool */
|
||||
private $isIisRewrite = false;
|
||||
|
||||
/**
|
||||
* @param array $query The GET parameters
|
||||
* @param array $request The POST parameters
|
||||
@@ -439,16 +442,16 @@ class Request
|
||||
/**
|
||||
* Clones a request and overrides some of its parameters.
|
||||
*
|
||||
* @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 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
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
|
||||
public function duplicate(?array $query = null, ?array $request = null, ?array $attributes = null, ?array $cookies = null, ?array $files = null, ?array $server = null)
|
||||
{
|
||||
$dup = clone $this;
|
||||
if (null !== $query) {
|
||||
@@ -522,10 +525,10 @@ class Request
|
||||
$cookies = [];
|
||||
|
||||
foreach ($this->cookies as $k => $v) {
|
||||
$cookies[] = $k.'='.$v;
|
||||
$cookies[] = \is_array($v) ? http_build_query([$k => $v], '', '; ', \PHP_QUERY_RFC3986) : "$k=$v";
|
||||
}
|
||||
|
||||
if (!empty($cookies)) {
|
||||
if ($cookies) {
|
||||
$cookieHeader = 'Cookie: '.implode('; ', $cookies)."\r\n";
|
||||
}
|
||||
|
||||
@@ -562,7 +565,7 @@ class Request
|
||||
|
||||
$request = ['g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE];
|
||||
|
||||
$requestOrder = ini_get('request_order') ?: ini_get('variables_order');
|
||||
$requestOrder = \ini_get('request_order') ?: \ini_get('variables_order');
|
||||
$requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp';
|
||||
|
||||
$_REQUEST = [[]];
|
||||
@@ -1452,7 +1455,7 @@ class Request
|
||||
*/
|
||||
public function getLocale()
|
||||
{
|
||||
return null === $this->locale ? $this->defaultLocale : $this->locale;
|
||||
return $this->locale ?? $this->defaultLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1573,9 +1576,9 @@ class Request
|
||||
/**
|
||||
* Gets the request body decoded as array, typically from a JSON payload.
|
||||
*
|
||||
* @throws JsonException When the body cannot be decoded to an array
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws JsonException When the body cannot be decoded to an array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
@@ -1648,7 +1651,7 @@ class Request
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPreferredLanguage(array $locales = null)
|
||||
public function getPreferredLanguage(?array $locales = null)
|
||||
{
|
||||
$preferredLanguages = $this->getLanguages();
|
||||
|
||||
@@ -1689,7 +1692,8 @@ class Request
|
||||
|
||||
$languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
|
||||
$this->languages = [];
|
||||
foreach ($languages as $lang => $acceptHeaderItem) {
|
||||
foreach ($languages as $acceptHeaderItem) {
|
||||
$lang = $acceptHeaderItem->getValue();
|
||||
if (str_contains($lang, '-')) {
|
||||
$codes = explode('-', $lang);
|
||||
if ('i' === $codes[0]) {
|
||||
@@ -1727,7 +1731,7 @@ class Request
|
||||
return $this->charsets;
|
||||
}
|
||||
|
||||
return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all());
|
||||
return $this->charsets = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1741,7 +1745,7 @@ class Request
|
||||
return $this->encodings;
|
||||
}
|
||||
|
||||
return $this->encodings = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all());
|
||||
return $this->encodings = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1755,7 +1759,7 @@ class Request
|
||||
return $this->acceptableContentTypes;
|
||||
}
|
||||
|
||||
return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all());
|
||||
return $this->acceptableContentTypes = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1804,11 +1808,10 @@ class Request
|
||||
{
|
||||
$requestUri = '';
|
||||
|
||||
if ('1' == $this->server->get('IIS_WasUrlRewritten') && '' != $this->server->get('UNENCODED_URL')) {
|
||||
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');
|
||||
$this->server->remove('IIS_WasUrlRewritten');
|
||||
} elseif ($this->server->has('REQUEST_URI')) {
|
||||
$requestUri = $this->server->get('REQUEST_URI');
|
||||
|
||||
@@ -2011,7 +2014,13 @@ class Request
|
||||
*/
|
||||
private function getUrlencodedPrefix(string $string, string $prefix): ?string
|
||||
{
|
||||
if (!str_starts_with(rawurldecode($string), $prefix)) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2052,7 +2061,7 @@ class Request
|
||||
return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR', ''), self::$trustedProxies);
|
||||
}
|
||||
|
||||
private function getTrustedValues(int $type, string $ip = null): array
|
||||
private function getTrustedValues(int $type, ?string $ip = null): array
|
||||
{
|
||||
$clientValues = [];
|
||||
$forwardedValues = [];
|
||||
@@ -2144,4 +2153,20 @@ class Request
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class RequestMatcher implements RequestMatcherInterface
|
||||
* @param string|string[]|null $ips
|
||||
* @param string|string[]|null $schemes
|
||||
*/
|
||||
public function __construct(string $path = null, string $host = null, $methods = null, $ips = null, array $attributes = [], $schemes = null, int $port = null)
|
||||
public function __construct(?string $path = null, ?string $host = null, $methods = null, $ips = null, array $attributes = [], $schemes = null, ?int $port = null)
|
||||
{
|
||||
$this->matchPath($path);
|
||||
$this->matchHost($host);
|
||||
@@ -91,7 +91,7 @@ class RequestMatcher implements RequestMatcherInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a check for the the URL port.
|
||||
* Adds a check for the URL port.
|
||||
*
|
||||
* @param int|null $port The port number to connect to
|
||||
*/
|
||||
|
||||
25
vendor/symfony/http-foundation/Response.php
vendored
25
vendor/symfony/http-foundation/Response.php
vendored
@@ -72,7 +72,7 @@ class Response
|
||||
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;
|
||||
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;
|
||||
@@ -298,7 +298,7 @@ class Response
|
||||
$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')) {
|
||||
} 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);
|
||||
}
|
||||
@@ -399,6 +399,7 @@ class Response
|
||||
litespeed_finish_request();
|
||||
} elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
|
||||
static::closeOutputBuffers(0, true);
|
||||
flush();
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -462,7 +463,7 @@ class Response
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function setStatusCode(int $code, string $text = null): object
|
||||
public function setStatusCode(int $code, ?string $text = null): object
|
||||
{
|
||||
$this->statusCode = $code;
|
||||
if ($this->isInvalid()) {
|
||||
@@ -736,7 +737,7 @@ class Response
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function setExpires(\DateTimeInterface $date = null): object
|
||||
public function setExpires(?\DateTimeInterface $date = null): object
|
||||
{
|
||||
if (null === $date) {
|
||||
$this->headers->remove('Expires');
|
||||
@@ -773,8 +774,10 @@ class Response
|
||||
return (int) $this->headers->getCacheControlDirective('max-age');
|
||||
}
|
||||
|
||||
if (null !== $this->getExpires()) {
|
||||
return (int) $this->getExpires()->format('U') - (int) $this->getDate()->format('U');
|
||||
if (null !== $expires = $this->getExpires()) {
|
||||
$maxAge = (int) $expires->format('U') - (int) $this->getDate()->format('U');
|
||||
|
||||
return max($maxAge, 0);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -818,7 +821,7 @@ class Response
|
||||
*
|
||||
* It returns null when no freshness information is present in the response.
|
||||
*
|
||||
* When the responses TTL is <= 0, the response may not be served from cache without first
|
||||
* When the response's TTL is 0, the response may not be served from cache without first
|
||||
* revalidating with the origin.
|
||||
*
|
||||
* @final
|
||||
@@ -827,7 +830,7 @@ class Response
|
||||
{
|
||||
$maxAge = $this->getMaxAge();
|
||||
|
||||
return null !== $maxAge ? $maxAge - $this->getAge() : null;
|
||||
return null !== $maxAge ? max($maxAge - $this->getAge(), 0) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -883,7 +886,7 @@ class Response
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function setLastModified(\DateTimeInterface $date = null): object
|
||||
public function setLastModified(?\DateTimeInterface $date = null): object
|
||||
{
|
||||
if (null === $date) {
|
||||
$this->headers->remove('Last-Modified');
|
||||
@@ -921,7 +924,7 @@ class Response
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function setEtag(string $etag = null, bool $weak = false): object
|
||||
public function setEtag(?string $etag = null, bool $weak = false): object
|
||||
{
|
||||
if (null === $etag) {
|
||||
$this->headers->remove('Etag');
|
||||
@@ -1214,7 +1217,7 @@ class Response
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function isRedirect(string $location = null): bool
|
||||
public function isRedirect(?string $location = null): bool
|
||||
{
|
||||
return \in_array($this->statusCode, [201, 301, 302, 303, 307, 308]) && (null === $location ?: $location == $this->headers->get('Location'));
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ class ResponseHeaderBag extends HeaderBag
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function all(string $key = null)
|
||||
public function all(?string $key = null)
|
||||
{
|
||||
$headers = parent::all();
|
||||
|
||||
@@ -186,7 +186,7 @@ class ResponseHeaderBag extends HeaderBag
|
||||
/**
|
||||
* Removes a cookie from the array, but does not unset it in the browser.
|
||||
*/
|
||||
public function removeCookie(string $name, ?string $path = '/', string $domain = null)
|
||||
public function removeCookie(string $name, ?string $path = '/', ?string $domain = null)
|
||||
{
|
||||
if (null === $path) {
|
||||
$path = '/';
|
||||
@@ -239,7 +239,7 @@ class ResponseHeaderBag extends HeaderBag
|
||||
/**
|
||||
* Clears a cookie in the browser.
|
||||
*/
|
||||
public function clearCookie(string $name, ?string $path = '/', string $domain = null, bool $secure = false, bool $httpOnly = true, string $sameSite = null)
|
||||
public function clearCookie(string $name, ?string $path = '/', ?string $domain = null, bool $secure = false, bool $httpOnly = true, ?string $sameSite = null)
|
||||
{
|
||||
$this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, $sameSite));
|
||||
}
|
||||
|
||||
4
vendor/symfony/http-foundation/ServerBag.php
vendored
4
vendor/symfony/http-foundation/ServerBag.php
vendored
@@ -31,7 +31,7 @@ class ServerBag extends ParameterBag
|
||||
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)) {
|
||||
} elseif (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true) && '' !== $value) {
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class ServerBag extends ParameterBag
|
||||
* RewriteCond %{HTTP:Authorization} .+
|
||||
* RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
|
||||
* RewriteCond %{REQUEST_FILENAME} !-f
|
||||
* RewriteRule ^(.*)$ app.php [QSA,L]
|
||||
* RewriteRule ^(.*)$ index.php [QSA,L]
|
||||
*/
|
||||
|
||||
$authorizationHeader = null;
|
||||
|
||||
@@ -39,7 +39,7 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
|
||||
private $usageIndex = 0;
|
||||
private $usageReporter;
|
||||
|
||||
public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null, callable $usageReporter = null)
|
||||
public function __construct(?SessionStorageInterface $storage = null, ?AttributeBagInterface $attributes = null, ?FlashBagInterface $flashes = null, ?callable $usageReporter = null)
|
||||
{
|
||||
$this->storage = $storage ?? new NativeSessionStorage();
|
||||
$this->usageReporter = $usageReporter;
|
||||
@@ -175,7 +175,7 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invalidate(int $lifetime = null)
|
||||
public function invalidate(?int $lifetime = null)
|
||||
{
|
||||
$this->storage->clear();
|
||||
|
||||
@@ -185,7 +185,7 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function migrate(bool $destroy = false, int $lifetime = null)
|
||||
public function migrate(bool $destroy = false, ?int $lifetime = null)
|
||||
{
|
||||
return $this->storage->regenerate($destroy, $lifetime);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class SessionFactory implements SessionFactoryInterface
|
||||
private $storageFactory;
|
||||
private $usageReporter;
|
||||
|
||||
public function __construct(RequestStack $requestStack, SessionStorageFactoryInterface $storageFactory, callable $usageReporter = null)
|
||||
public function __construct(RequestStack $requestStack, SessionStorageFactoryInterface $storageFactory, ?callable $usageReporter = null)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
$this->storageFactory = $storageFactory;
|
||||
|
||||
@@ -59,28 +59,28 @@ interface SessionInterface
|
||||
* Clears all session attributes and flashes and regenerates the
|
||||
* session and deletes the old session from persistence.
|
||||
*
|
||||
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
* @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function invalidate(int $lifetime = null);
|
||||
public function invalidate(?int $lifetime = null);
|
||||
|
||||
/**
|
||||
* Migrates the current session to a new session id while maintaining all
|
||||
* session attributes.
|
||||
*
|
||||
* @param bool $destroy Whether to delete the old session or leave it to garbage collection
|
||||
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
* @param bool $destroy Whether to delete the old session or leave it to garbage collection
|
||||
* @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function migrate(bool $destroy = false, int $lifetime = null);
|
||||
public function migrate(bool $destroy = false, ?int $lifetime = null);
|
||||
|
||||
/**
|
||||
* Force the session to be saved and closed.
|
||||
|
||||
@@ -35,8 +35,8 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
|
||||
public function open($savePath, $sessionName)
|
||||
{
|
||||
$this->sessionName = $sessionName;
|
||||
if (!headers_sent() && !ini_get('session.cache_limiter') && '0' !== ini_get('session.cache_limiter')) {
|
||||
header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) ini_get('session.cache_expire')));
|
||||
if (!headers_sent() && !\ini_get('session.cache_limiter') && '0' !== \ini_get('session.cache_limiter')) {
|
||||
header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire')));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -126,7 +126,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
|
||||
#[\ReturnTypeWillChange]
|
||||
public function destroy($sessionId)
|
||||
{
|
||||
if (!headers_sent() && filter_var(ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN)) {
|
||||
if (!headers_sent() && filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN)) {
|
||||
if (!$this->sessionName) {
|
||||
throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class));
|
||||
}
|
||||
@@ -141,7 +141,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
|
||||
*/
|
||||
if (null === $cookie || isset($_COOKIE[$this->sessionName])) {
|
||||
if (\PHP_VERSION_ID < 70300) {
|
||||
setcookie($this->sessionName, '', 0, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), filter_var(ini_get('session.cookie_secure'), \FILTER_VALIDATE_BOOLEAN), filter_var(ini_get('session.cookie_httponly'), \FILTER_VALIDATE_BOOLEAN));
|
||||
setcookie($this->sessionName, '', 0, \ini_get('session.cookie_path'), \ini_get('session.cookie_domain'), filter_var(\ini_get('session.cookie_secure'), \FILTER_VALIDATE_BOOLEAN), filter_var(\ini_get('session.cookie_httponly'), \FILTER_VALIDATE_BOOLEAN));
|
||||
} else {
|
||||
$params = session_get_cookie_params();
|
||||
unset($params['lifetime']);
|
||||
|
||||
@@ -77,7 +77,7 @@ class MemcachedSessionHandler extends AbstractSessionHandler
|
||||
#[\ReturnTypeWillChange]
|
||||
public function updateTimestamp($sessionId, $data)
|
||||
{
|
||||
$this->memcached->touch($this->prefix.$sessionId, time() + (int) ($this->ttl ?? ini_get('session.gc_maxlifetime')));
|
||||
$this->memcached->touch($this->prefix.$sessionId, $this->getCompatibleTtl());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -87,7 +87,20 @@ class MemcachedSessionHandler extends AbstractSessionHandler
|
||||
*/
|
||||
protected function doWrite(string $sessionId, string $data)
|
||||
{
|
||||
return $this->memcached->set($this->prefix.$sessionId, $data, time() + (int) ($this->ttl ?? ini_get('session.gc_maxlifetime')));
|
||||
return $this->memcached->set($this->prefix.$sessionId, $data, $this->getCompatibleTtl());
|
||||
}
|
||||
|
||||
private function getCompatibleTtl(): int
|
||||
{
|
||||
$ttl = (int) ($this->ttl ?? \ini_get('session.gc_maxlifetime'));
|
||||
|
||||
// If the relative TTL that is used exceeds 30 days, memcached will treat the value as Unix time.
|
||||
// We have to convert it to an absolute Unix time at this point, to make sure the TTL is correct.
|
||||
if ($ttl > 60 * 60 * 24 * 30) {
|
||||
$ttl += time();
|
||||
}
|
||||
|
||||
return $ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -121,7 +121,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler
|
||||
*/
|
||||
protected function doWrite(string $sessionId, string $data)
|
||||
{
|
||||
$expiry = new UTCDateTime((time() + (int) ini_get('session.gc_maxlifetime')) * 1000);
|
||||
$expiry = new UTCDateTime((time() + (int) \ini_get('session.gc_maxlifetime')) * 1000);
|
||||
|
||||
$fields = [
|
||||
$this->options['time_field'] => new UTCDateTime(),
|
||||
@@ -144,7 +144,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler
|
||||
#[\ReturnTypeWillChange]
|
||||
public function updateTimestamp($sessionId, $data)
|
||||
{
|
||||
$expiry = new UTCDateTime((time() + (int) ini_get('session.gc_maxlifetime')) * 1000);
|
||||
$expiry = new UTCDateTime((time() + (int) \ini_get('session.gc_maxlifetime')) * 1000);
|
||||
|
||||
$this->getCollection()->updateOne(
|
||||
[$this->options['id_field'] => $sessionId],
|
||||
|
||||
@@ -19,19 +19,19 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
||||
class NativeFileSessionHandler extends \SessionHandler
|
||||
{
|
||||
/**
|
||||
* @param string $savePath Path of directory to save session files
|
||||
* Default null will leave setting as defined by PHP.
|
||||
* '/path', 'N;/path', or 'N;octal-mode;/path
|
||||
* @param string|null $savePath Path of directory to save session files
|
||||
* Default null will leave setting as defined by PHP.
|
||||
* '/path', 'N;/path', or 'N;octal-mode;/path
|
||||
*
|
||||
* @see https://php.net/session.configuration#ini.session.save-path for further details.
|
||||
*
|
||||
* @throws \InvalidArgumentException On invalid $savePath
|
||||
* @throws \RuntimeException When failing to create the save directory
|
||||
*/
|
||||
public function __construct(string $savePath = null)
|
||||
public function __construct(?string $savePath = null)
|
||||
{
|
||||
if (null === $savePath) {
|
||||
$savePath = ini_get('session.save_path');
|
||||
$savePath = \ini_get('session.save_path');
|
||||
}
|
||||
|
||||
$baseDir = $savePath;
|
||||
@@ -49,7 +49,11 @@ class NativeFileSessionHandler extends \SessionHandler
|
||||
throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $baseDir));
|
||||
}
|
||||
|
||||
ini_set('session.save_path', $savePath);
|
||||
ini_set('session.save_handler', 'files');
|
||||
if ($savePath !== \ini_get('session.save_path')) {
|
||||
ini_set('session.save_path', $savePath);
|
||||
}
|
||||
if ('files' !== \ini_get('session.save_handler')) {
|
||||
ini_set('session.save_handler', 'files');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,16 +112,16 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
/**
|
||||
* Username when lazy-connect.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
private $username = '';
|
||||
private $username = null;
|
||||
|
||||
/**
|
||||
* Password when lazy-connect.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
private $password = '';
|
||||
private $password = null;
|
||||
|
||||
/**
|
||||
* Connection options when lazy-connect.
|
||||
@@ -344,7 +344,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
*/
|
||||
protected function doWrite(string $sessionId, string $data)
|
||||
{
|
||||
$maxlifetime = (int) ini_get('session.gc_maxlifetime');
|
||||
$maxlifetime = (int) \ini_get('session.gc_maxlifetime');
|
||||
|
||||
try {
|
||||
// We use a single MERGE SQL query when supported by the database.
|
||||
@@ -391,14 +391,14 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
#[\ReturnTypeWillChange]
|
||||
public function updateTimestamp($sessionId, $data)
|
||||
{
|
||||
$expiry = time() + (int) ini_get('session.gc_maxlifetime');
|
||||
$expiry = time() + (int) \ini_get('session.gc_maxlifetime');
|
||||
|
||||
try {
|
||||
$updateStmt = $this->pdo->prepare(
|
||||
"UPDATE $this->table SET $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id"
|
||||
);
|
||||
$updateStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||
$updateStmt->bindParam(':expiry', $expiry, \PDO::PARAM_INT);
|
||||
$updateStmt->bindValue(':id', $sessionId, \PDO::PARAM_STR);
|
||||
$updateStmt->bindValue(':expiry', $expiry, \PDO::PARAM_INT);
|
||||
$updateStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||
$updateStmt->execute();
|
||||
} catch (\PDOException $e) {
|
||||
@@ -530,8 +530,8 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
return $dsn;
|
||||
}
|
||||
}
|
||||
// If "unix_socket" is not in the query, we continue with the same process as pgsql
|
||||
// no break
|
||||
// If "unix_socket" is not in the query, we continue with the same process as pgsql
|
||||
// no break
|
||||
case 'pgsql':
|
||||
$dsn ?? $dsn = 'pgsql:';
|
||||
|
||||
@@ -687,7 +687,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
throw new \RuntimeException('Failed to read session: INSERT reported a duplicate id but next SELECT did not return any data.');
|
||||
}
|
||||
|
||||
if (!filter_var(ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOLEAN) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) {
|
||||
if (!filter_var(\ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOLEAN) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) {
|
||||
// In strict mode, session fixation is not possible: new sessions always start with a unique
|
||||
// random id, so that concurrency is not possible and this code path can be skipped.
|
||||
// Exclusive-reading of non-existent rows does not block, so we need to do an insert to block
|
||||
@@ -935,7 +935,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
protected function getConnection()
|
||||
{
|
||||
if (null === $this->pdo) {
|
||||
$this->connect($this->dsn ?: ini_get('session.save_path'));
|
||||
$this->connect($this->dsn ?: \ini_get('session.save_path'));
|
||||
}
|
||||
|
||||
return $this->pdo;
|
||||
|
||||
@@ -79,7 +79,7 @@ class RedisSessionHandler extends AbstractSessionHandler
|
||||
*/
|
||||
protected function doWrite(string $sessionId, string $data): bool
|
||||
{
|
||||
$result = $this->redis->setEx($this->prefix.$sessionId, (int) ($this->ttl ?? ini_get('session.gc_maxlifetime')), $data);
|
||||
$result = $this->redis->setEx($this->prefix.$sessionId, (int) ($this->ttl ?? \ini_get('session.gc_maxlifetime')), $data);
|
||||
|
||||
return $result && !$result instanceof ErrorInterface;
|
||||
}
|
||||
@@ -132,6 +132,6 @@ class RedisSessionHandler extends AbstractSessionHandler
|
||||
#[\ReturnTypeWillChange]
|
||||
public function updateTimestamp($sessionId, $data)
|
||||
{
|
||||
return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ($this->ttl ?? ini_get('session.gc_maxlifetime')));
|
||||
return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ($this->ttl ?? \ini_get('session.gc_maxlifetime')));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
|
||||
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
||||
|
||||
use Doctrine\DBAL\Configuration;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
|
||||
use Doctrine\DBAL\Tools\DsnParser;
|
||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
||||
use Symfony\Component\Cache\Traits\RedisClusterProxy;
|
||||
use Symfony\Component\Cache\Traits\RedisProxy;
|
||||
@@ -60,7 +63,7 @@ class SessionHandlerFactory
|
||||
case str_starts_with($connection, 'rediss:'):
|
||||
case str_starts_with($connection, 'memcached:'):
|
||||
if (!class_exists(AbstractAdapter::class)) {
|
||||
throw new \InvalidArgumentException(sprintf('Unsupported DSN "%s". Try running "composer require symfony/cache".', $connection));
|
||||
throw new \InvalidArgumentException('Unsupported Redis or Memcached DSN. Try running "composer require symfony/cache".');
|
||||
}
|
||||
$handlerClass = str_starts_with($connection, 'memcached:') ? MemcachedSessionHandler::class : RedisSessionHandler::class;
|
||||
$connection = AbstractAdapter::createConnection($connection, ['lazy' => true]);
|
||||
@@ -69,9 +72,18 @@ class SessionHandlerFactory
|
||||
|
||||
case str_starts_with($connection, 'pdo_oci://'):
|
||||
if (!class_exists(DriverManager::class)) {
|
||||
throw new \InvalidArgumentException(sprintf('Unsupported DSN "%s". Try running "composer require doctrine/dbal".', $connection));
|
||||
throw new \InvalidArgumentException('Unsupported PDO OCI DSN. Try running "composer require doctrine/dbal".');
|
||||
}
|
||||
$connection = DriverManager::getConnection(['url' => $connection])->getWrappedConnection();
|
||||
$connection[3] = '-';
|
||||
$params = class_exists(DsnParser::class) ? (new DsnParser())->parse($connection) : ['url' => $connection];
|
||||
$config = new Configuration();
|
||||
if (class_exists(DefaultSchemaManagerFactory::class)) {
|
||||
$config->setSchemaManagerFactory(new DefaultSchemaManagerFactory());
|
||||
}
|
||||
|
||||
$connection = DriverManager::getConnection($params, $config);
|
||||
// The condition should be removed once support for DBAL <3.3 is dropped
|
||||
$connection = method_exists($connection, 'getNativeConnection') ? $connection->getNativeConnection() : $connection->getWrappedConnection();
|
||||
// no break;
|
||||
|
||||
case str_starts_with($connection, 'mssql://'):
|
||||
|
||||
@@ -30,6 +30,16 @@ class StrictSessionHandler extends AbstractSessionHandler
|
||||
$this->handler = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this handler wraps an internal PHP session save handler using \SessionHandler.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function isWrapper(): bool
|
||||
{
|
||||
return $this->handler instanceof \SessionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -95,12 +95,12 @@ class MetadataBag implements SessionBagInterface
|
||||
/**
|
||||
* Stamps a new session's metadata.
|
||||
*
|
||||
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
* @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
*/
|
||||
public function stampNew(int $lifetime = null)
|
||||
public function stampNew(?int $lifetime = null)
|
||||
{
|
||||
$this->stampCreated($lifetime);
|
||||
}
|
||||
@@ -158,10 +158,10 @@ class MetadataBag implements SessionBagInterface
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
private function stampCreated(int $lifetime = null): void
|
||||
private function stampCreated(?int $lifetime = null): void
|
||||
{
|
||||
$timeStamp = time();
|
||||
$this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp;
|
||||
$this->meta[self::LIFETIME] = $lifetime ?? (int) ini_get('session.cookie_lifetime');
|
||||
$this->meta[self::LIFETIME] = $lifetime ?? (int) \ini_get('session.cookie_lifetime');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class MockArraySessionStorage implements SessionStorageInterface
|
||||
*/
|
||||
protected $bags = [];
|
||||
|
||||
public function __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
|
||||
public function __construct(string $name = 'MOCKSESSID', ?MetadataBag $metaBag = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->setMetadataBag($metaBag);
|
||||
@@ -94,7 +94,7 @@ class MockArraySessionStorage implements SessionStorageInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function regenerate(bool $destroy = false, int $lifetime = null)
|
||||
public function regenerate(bool $destroy = false, ?int $lifetime = null)
|
||||
{
|
||||
if (!$this->started) {
|
||||
$this->start();
|
||||
@@ -204,7 +204,7 @@ class MockArraySessionStorage implements SessionStorageInterface
|
||||
return $this->started;
|
||||
}
|
||||
|
||||
public function setMetadataBag(MetadataBag $bag = null)
|
||||
public function setMetadataBag(?MetadataBag $bag = null)
|
||||
{
|
||||
if (null === $bag) {
|
||||
$bag = new MetadataBag();
|
||||
|
||||
@@ -30,7 +30,7 @@ class MockFileSessionStorage extends MockArraySessionStorage
|
||||
/**
|
||||
* @param string|null $savePath Path of directory to save session files
|
||||
*/
|
||||
public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
|
||||
public function __construct(?string $savePath = null, string $name = 'MOCKSESSID', ?MetadataBag $metaBag = null)
|
||||
{
|
||||
if (null === $savePath) {
|
||||
$savePath = sys_get_temp_dir();
|
||||
@@ -68,7 +68,7 @@ class MockFileSessionStorage extends MockArraySessionStorage
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function regenerate(bool $destroy = false, int $lifetime = null)
|
||||
public function regenerate(bool $destroy = false, ?int $lifetime = null)
|
||||
{
|
||||
if (!$this->started) {
|
||||
$this->start();
|
||||
|
||||
@@ -28,7 +28,7 @@ class MockFileSessionStorageFactory implements SessionStorageFactoryInterface
|
||||
/**
|
||||
* @see MockFileSessionStorage constructor.
|
||||
*/
|
||||
public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
|
||||
public function __construct(?string $savePath = null, string $name = 'MOCKSESSID', ?MetadataBag $metaBag = null)
|
||||
{
|
||||
$this->savePath = $savePath;
|
||||
$this->name = $name;
|
||||
|
||||
@@ -97,7 +97,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
*
|
||||
* @param AbstractProxy|\SessionHandlerInterface|null $handler
|
||||
*/
|
||||
public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null)
|
||||
public function __construct(array $options = [], $handler = null, ?MetadataBag $metaBag = null)
|
||||
{
|
||||
if (!\extension_loaded('session')) {
|
||||
throw new \LogicException('PHP extension "session" is required.');
|
||||
@@ -141,10 +141,46 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
throw new \RuntimeException('Failed to start the session: already started by PHP.');
|
||||
}
|
||||
|
||||
if (filter_var(ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) {
|
||||
if (filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) {
|
||||
throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
|
||||
}
|
||||
|
||||
$sessionId = $_COOKIE[session_name()] ?? null;
|
||||
/*
|
||||
* Explanation of the session ID regular expression: `/^[a-zA-Z0-9,-]{22,250}$/`.
|
||||
*
|
||||
* ---------- Part 1
|
||||
*
|
||||
* The part `[a-zA-Z0-9,-]` is related to the PHP ini directive `session.sid_bits_per_character` defined as 6.
|
||||
* See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-bits-per-character.
|
||||
* Allowed values are integers such as:
|
||||
* - 4 for range `a-f0-9`
|
||||
* - 5 for range `a-v0-9`
|
||||
* - 6 for range `a-zA-Z0-9,-`
|
||||
*
|
||||
* ---------- Part 2
|
||||
*
|
||||
* The part `{22,250}` is related to the PHP ini directive `session.sid_length`.
|
||||
* See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-length.
|
||||
* Allowed values are integers between 22 and 256, but we use 250 for the max.
|
||||
*
|
||||
* Where does the 250 come from?
|
||||
* - The length of Windows and Linux filenames is limited to 255 bytes. Then the max must not exceed 255.
|
||||
* - The session filename prefix is `sess_`, a 5 bytes string. Then the max must not exceed 255 - 5 = 250.
|
||||
*
|
||||
* ---------- Conclusion
|
||||
*
|
||||
* The parts 1 and 2 prevent the warning below:
|
||||
* `PHP Warning: SessionHandler::read(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed.`
|
||||
*
|
||||
* The part 2 prevents the warning below:
|
||||
* `PHP Warning: SessionHandler::read(): open(filepath, O_RDWR) failed: No such file or directory (2).`
|
||||
*/
|
||||
if ($sessionId && $this->saveHandler instanceof AbstractProxy && 'files' === $this->saveHandler->getSaveHandlerName() && !preg_match('/^[a-zA-Z0-9,-]{22,250}$/', $sessionId)) {
|
||||
// the session ID in the header is invalid, create a new one
|
||||
session_id(session_create_id());
|
||||
}
|
||||
|
||||
// ok to try and start the session
|
||||
if (!session_start()) {
|
||||
throw new \RuntimeException('Failed to start the session.');
|
||||
@@ -197,7 +233,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function regenerate(bool $destroy = false, int $lifetime = null)
|
||||
public function regenerate(bool $destroy = false, ?int $lifetime = null)
|
||||
{
|
||||
// Cannot regenerate the session ID for non-active sessions.
|
||||
if (\PHP_SESSION_ACTIVE !== session_status()) {
|
||||
@@ -208,7 +244,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null !== $lifetime && $lifetime != ini_get('session.cookie_lifetime')) {
|
||||
if (null !== $lifetime && $lifetime != \ini_get('session.cookie_lifetime')) {
|
||||
$this->save();
|
||||
ini_set('session.cookie_lifetime', $lifetime);
|
||||
$this->start();
|
||||
@@ -243,7 +279,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
}
|
||||
if ([$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) {
|
||||
if ($_SESSION && [$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) {
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
@@ -319,7 +355,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
return $this->bags[$name];
|
||||
}
|
||||
|
||||
public function setMetadataBag(MetadataBag $metaBag = null)
|
||||
public function setMetadataBag(?MetadataBag $metaBag = null)
|
||||
{
|
||||
if (null === $metaBag) {
|
||||
$metaBag = new MetadataBag();
|
||||
@@ -419,9 +455,10 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
*/
|
||||
public function setSaveHandler($saveHandler = null)
|
||||
{
|
||||
if (!$saveHandler instanceof AbstractProxy &&
|
||||
!$saveHandler instanceof \SessionHandlerInterface &&
|
||||
null !== $saveHandler) {
|
||||
if (!$saveHandler instanceof AbstractProxy
|
||||
&& !$saveHandler instanceof \SessionHandlerInterface
|
||||
&& null !== $saveHandler
|
||||
) {
|
||||
throw new \InvalidArgumentException('Must be instance of AbstractProxy; implement \SessionHandlerInterface; or be null.');
|
||||
}
|
||||
|
||||
@@ -450,7 +487,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
* PHP takes the return value from the read() handler, unserializes it
|
||||
* and populates $_SESSION with the result automatically.
|
||||
*/
|
||||
protected function loadSession(array &$session = null)
|
||||
protected function loadSession(?array &$session = null)
|
||||
{
|
||||
if (null === $session) {
|
||||
$session = &$_SESSION;
|
||||
|
||||
@@ -29,7 +29,7 @@ class NativeSessionStorageFactory implements SessionStorageFactoryInterface
|
||||
/**
|
||||
* @see NativeSessionStorage constructor.
|
||||
*/
|
||||
public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null, bool $secure = false)
|
||||
public function __construct(array $options = [], $handler = null, ?MetadataBag $metaBag = null, bool $secure = false)
|
||||
{
|
||||
$this->options = $options;
|
||||
$this->handler = $handler;
|
||||
|
||||
@@ -23,7 +23,7 @@ class PhpBridgeSessionStorage extends NativeSessionStorage
|
||||
/**
|
||||
* @param AbstractProxy|\SessionHandlerInterface|null $handler
|
||||
*/
|
||||
public function __construct($handler = null, MetadataBag $metaBag = null)
|
||||
public function __construct($handler = null, ?MetadataBag $metaBag = null)
|
||||
{
|
||||
if (!\extension_loaded('session')) {
|
||||
throw new \LogicException('PHP extension "session" is required.');
|
||||
|
||||
@@ -28,7 +28,7 @@ class PhpBridgeSessionStorageFactory implements SessionStorageFactoryInterface
|
||||
/**
|
||||
* @see PhpBridgeSessionStorage constructor.
|
||||
*/
|
||||
public function __construct($handler = null, MetadataBag $metaBag = null, bool $secure = false)
|
||||
public function __construct($handler = null, ?MetadataBag $metaBag = null, bool $secure = false)
|
||||
{
|
||||
$this->handler = $handler;
|
||||
$this->metaBag = $metaBag;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler;
|
||||
|
||||
/**
|
||||
* @author Drak <drak@zikula.org>
|
||||
*/
|
||||
@@ -22,7 +24,7 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf
|
||||
{
|
||||
$this->handler = $handler;
|
||||
$this->wrapper = $handler instanceof \SessionHandler;
|
||||
$this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user';
|
||||
$this->saveHandlerName = $this->wrapper || ($handler instanceof StrictSessionHandler && $handler->isWrapper()) ? \ini_get('session.save_handler') : 'user';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -80,17 +80,17 @@ interface SessionStorageInterface
|
||||
* Otherwise session data could get lost again for concurrent requests with the
|
||||
* new ID. One result could be that you get logged out after just logging in.
|
||||
*
|
||||
* @param bool $destroy Destroy session when regenerating?
|
||||
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
* @param bool $destroy Destroy session when regenerating?
|
||||
* @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \RuntimeException If an error occurs while regenerating this storage
|
||||
*/
|
||||
public function regenerate(bool $destroy = false, int $lifetime = null);
|
||||
public function regenerate(bool $destroy = false, ?int $lifetime = null);
|
||||
|
||||
/**
|
||||
* Force the session to be saved and closed.
|
||||
|
||||
@@ -30,7 +30,7 @@ class StreamedResponse extends Response
|
||||
protected $streamed;
|
||||
private $headersSent;
|
||||
|
||||
public function __construct(callable $callback = null, int $status = 200, array $headers = [])
|
||||
public function __construct(?callable $callback = null, int $status = 200, array $headers = [])
|
||||
{
|
||||
parent::__construct(null, $status, $headers);
|
||||
|
||||
@@ -114,9 +114,9 @@ class StreamedResponse extends Response
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws \LogicException when the content is not null
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws \LogicException when the content is not null
|
||||
*/
|
||||
public function setContent(?string $content)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ final class ResponseCookieValueSame extends Constraint
|
||||
private $path;
|
||||
private $domain;
|
||||
|
||||
public function __construct(string $name, string $value, string $path = '/', string $domain = null)
|
||||
public function __construct(string $name, string $value, string $path = '/', ?string $domain = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
@@ -59,7 +59,7 @@ final class ResponseCookieValueSame extends Constraint
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->value === $cookie->getValue();
|
||||
return $this->value === (string) $cookie->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ final class ResponseHasCookie extends Constraint
|
||||
private $path;
|
||||
private $domain;
|
||||
|
||||
public function __construct(string $name, string $path = '/', string $domain = null)
|
||||
public function __construct(string $name, string $path = '/', ?string $domain = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->path = $path;
|
||||
|
||||
38
vendor/symfony/http-foundation/UrlHelper.php
vendored
38
vendor/symfony/http-foundation/UrlHelper.php
vendored
@@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\HttpFoundation;
|
||||
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
use Symfony\Component\Routing\RequestContextAwareInterface;
|
||||
|
||||
/**
|
||||
* A helper service for manipulating URLs within and outside the request scope.
|
||||
@@ -23,8 +24,15 @@ final class UrlHelper
|
||||
private $requestStack;
|
||||
private $requestContext;
|
||||
|
||||
public function __construct(RequestStack $requestStack, RequestContext $requestContext = null)
|
||||
/**
|
||||
* @param RequestContextAwareInterface|RequestContext|null $requestContext
|
||||
*/
|
||||
public function __construct(RequestStack $requestStack, $requestContext = null)
|
||||
{
|
||||
if (null !== $requestContext && !$requestContext instanceof RequestContext && !$requestContext instanceof RequestContextAwareInterface) {
|
||||
throw new \TypeError(__METHOD__.': Argument #2 ($requestContext) must of type Symfony\Component\Routing\RequestContextAwareInterface|Symfony\Component\Routing\RequestContext|null, '.get_debug_type($requestContext).' given.');
|
||||
}
|
||||
|
||||
$this->requestStack = $requestStack;
|
||||
$this->requestContext = $requestContext;
|
||||
}
|
||||
@@ -73,28 +81,36 @@ final class UrlHelper
|
||||
|
||||
private function getAbsoluteUrlFromContext(string $path): string
|
||||
{
|
||||
if (null === $this->requestContext || '' === $host = $this->requestContext->getHost()) {
|
||||
if (null === $context = $this->requestContext) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$scheme = $this->requestContext->getScheme();
|
||||
if ($context instanceof RequestContextAwareInterface) {
|
||||
$context = $context->getContext();
|
||||
}
|
||||
|
||||
if ('' === $host = $context->getHost()) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$scheme = $context->getScheme();
|
||||
$port = '';
|
||||
|
||||
if ('http' === $scheme && 80 !== $this->requestContext->getHttpPort()) {
|
||||
$port = ':'.$this->requestContext->getHttpPort();
|
||||
} elseif ('https' === $scheme && 443 !== $this->requestContext->getHttpsPort()) {
|
||||
$port = ':'.$this->requestContext->getHttpsPort();
|
||||
if ('http' === $scheme && 80 !== $context->getHttpPort()) {
|
||||
$port = ':'.$context->getHttpPort();
|
||||
} elseif ('https' === $scheme && 443 !== $context->getHttpsPort()) {
|
||||
$port = ':'.$context->getHttpsPort();
|
||||
}
|
||||
|
||||
if ('#' === $path[0]) {
|
||||
$queryString = $this->requestContext->getQueryString();
|
||||
$path = $this->requestContext->getPathInfo().($queryString ? '?'.$queryString : '').$path;
|
||||
$queryString = $context->getQueryString();
|
||||
$path = $context->getPathInfo().($queryString ? '?'.$queryString : '').$path;
|
||||
} elseif ('?' === $path[0]) {
|
||||
$path = $this->requestContext->getPathInfo().$path;
|
||||
$path = $context->getPathInfo().$path;
|
||||
}
|
||||
|
||||
if ('/' !== $path[0]) {
|
||||
$path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path;
|
||||
$path = rtrim($context->getBaseUrl(), '/').'/'.$path;
|
||||
}
|
||||
|
||||
return $scheme.'://'.$host.$port.$path;
|
||||
|
||||
5
vendor/symfony/http-foundation/composer.json
vendored
5
vendor/symfony/http-foundation/composer.json
vendored
@@ -24,8 +24,11 @@
|
||||
"require-dev": {
|
||||
"predis/predis": "~1.0",
|
||||
"symfony/cache": "^4.4|^5.0|^6.0",
|
||||
"symfony/dependency-injection": "^5.4|^6.0",
|
||||
"symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4",
|
||||
"symfony/mime": "^4.4|^5.0|^6.0",
|
||||
"symfony/expression-language": "^4.4|^5.0|^6.0"
|
||||
"symfony/expression-language": "^4.4|^5.0|^6.0",
|
||||
"symfony/rate-limiter": "^5.2|^6.0"
|
||||
},
|
||||
"suggest" : {
|
||||
"symfony/mime": "To use the file extension guesser"
|
||||
|
||||
Reference in New Issue
Block a user