update patch 1
This commit is contained in:
+4
-4
@@ -18,14 +18,14 @@ namespace Symfony\Component\HttpFoundation;
|
||||
*/
|
||||
class AcceptHeaderItem
|
||||
{
|
||||
private string $value;
|
||||
private float $quality = 1.0;
|
||||
private int $index = 0;
|
||||
private array $attributes = [];
|
||||
|
||||
public function __construct(string $value, array $attributes = [])
|
||||
{
|
||||
$this->value = $value;
|
||||
public function __construct(
|
||||
private string $value,
|
||||
array $attributes = [],
|
||||
) {
|
||||
foreach ($attributes as $name => $value) {
|
||||
$this->setAttribute($name, $value);
|
||||
}
|
||||
|
||||
+5
-5
@@ -70,7 +70,7 @@ class BinaryFileResponse extends Response
|
||||
if ($file instanceof \SplFileInfo) {
|
||||
$file = new File($file->getPathname(), !$isTemporaryFile);
|
||||
} else {
|
||||
$file = new File((string) $file);
|
||||
$file = new File($file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +110,8 @@ class BinaryFileResponse extends Response
|
||||
*/
|
||||
public function setChunkSize(int $chunkSize): static
|
||||
{
|
||||
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.');
|
||||
if ($chunkSize < 1) {
|
||||
throw new \InvalidArgumentException('The chunk size of a BinaryFileResponse cannot be less than 1.');
|
||||
}
|
||||
|
||||
$this->chunkSize = $chunkSize;
|
||||
@@ -262,13 +262,13 @@ class BinaryFileResponse extends Response
|
||||
$end = min($end, $fileSize - 1);
|
||||
if ($start < 0 || $start > $end) {
|
||||
$this->setStatusCode(416);
|
||||
$this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize));
|
||||
$this->headers->set('Content-Range', \sprintf('bytes */%s', $fileSize));
|
||||
} elseif ($end - $start < $fileSize - 1) {
|
||||
$this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
|
||||
$this->offset = $start;
|
||||
|
||||
$this->setStatusCode(206);
|
||||
$this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
|
||||
$this->headers->set('Content-Range', \sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
|
||||
$this->headers->set('Content-Length', $end - $start + 1);
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -1,6 +1,14 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
7.2
|
||||
---
|
||||
|
||||
* Add optional `$requests` parameter to `RequestStack::__construct()`
|
||||
* Add optional `$v4Bytes` and `$v6Bytes` parameters to `IpUtils::anonymize()`
|
||||
* Add `PRIVATE_SUBNETS` as a shortcut for private IP address ranges to `Request::setTrustedProxies()`
|
||||
* Deprecate passing `referer_check`, `use_only_cookies`, `use_trans_sid`, `trans_sid_hosts`, `trans_sid_tags`, `sid_bits_per_character` and `sid_length` options to `NativeSessionStorage`
|
||||
|
||||
7.1
|
||||
---
|
||||
|
||||
|
||||
+14
-18
@@ -22,17 +22,10 @@ class Cookie
|
||||
public const SAMESITE_LAX = 'lax';
|
||||
public const SAMESITE_STRICT = 'strict';
|
||||
|
||||
protected string $name;
|
||||
protected ?string $value;
|
||||
protected ?string $domain;
|
||||
protected int $expire;
|
||||
protected string $path;
|
||||
protected ?bool $secure;
|
||||
protected bool $httpOnly;
|
||||
|
||||
private bool $raw;
|
||||
private ?string $sameSite = null;
|
||||
private bool $partitioned = false;
|
||||
private bool $secureDefault = false;
|
||||
|
||||
private const RESERVED_CHARS_LIST = "=,; \t\r\n\v\f";
|
||||
@@ -94,27 +87,30 @@ class Cookie
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(string $name, ?string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', ?string $domain = null, ?bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX, bool $partitioned = false)
|
||||
{
|
||||
public function __construct(
|
||||
protected string $name,
|
||||
protected ?string $value = null,
|
||||
int|string|\DateTimeInterface $expire = 0,
|
||||
?string $path = '/',
|
||||
protected ?string $domain = null,
|
||||
protected ?bool $secure = null,
|
||||
protected bool $httpOnly = true,
|
||||
private bool $raw = false,
|
||||
?string $sameSite = self::SAMESITE_LAX,
|
||||
private bool $partitioned = false,
|
||||
) {
|
||||
// from PHP source code
|
||||
if ($raw && false !== strpbrk($name, self::RESERVED_CHARS_LIST)) {
|
||||
throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
|
||||
throw new \InvalidArgumentException(\sprintf('The cookie name "%s" contains invalid characters.', $name));
|
||||
}
|
||||
|
||||
if (!$name) {
|
||||
throw new \InvalidArgumentException('The cookie name cannot be empty.');
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
$this->domain = $domain;
|
||||
$this->expire = self::expiresTimestamp($expire);
|
||||
$this->path = $path ?: '/';
|
||||
$this->secure = $secure;
|
||||
$this->httpOnly = $httpOnly;
|
||||
$this->raw = $raw;
|
||||
$this->sameSite = $this->withSameSite($sameSite)->sameSite;
|
||||
$this->partitioned = $partitioned;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +204,7 @@ class Cookie
|
||||
public function withRaw(bool $raw = true): static
|
||||
{
|
||||
if ($raw && false !== strpbrk($this->name, self::RESERVED_CHARS_LIST)) {
|
||||
throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $this->name));
|
||||
throw new \InvalidArgumentException(\sprintf('The cookie name "%s" contains invalid characters.', $this->name));
|
||||
}
|
||||
|
||||
$cookie = clone $this;
|
||||
|
||||
@@ -20,6 +20,6 @@ class AccessDeniedException extends FileException
|
||||
{
|
||||
public function __construct(string $path)
|
||||
{
|
||||
parent::__construct(sprintf('The file %s could not be accessed', $path));
|
||||
parent::__construct(\sprintf('The file %s could not be accessed', $path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@ class FileNotFoundException extends FileException
|
||||
{
|
||||
public function __construct(string $path)
|
||||
{
|
||||
parent::__construct(sprintf('The file "%s" does not exist', $path));
|
||||
parent::__construct(\sprintf('The file "%s" does not exist', $path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@ class UnexpectedTypeException extends FileException
|
||||
{
|
||||
public function __construct(mixed $value, string $expectedType)
|
||||
{
|
||||
parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, get_debug_type($value)));
|
||||
parent::__construct(\sprintf('Expected argument of type %s, %s given', $expectedType, get_debug_type($value)));
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -93,7 +93,7 @@ class File extends \SplFileInfo
|
||||
restore_error_handler();
|
||||
}
|
||||
if (!$renamed) {
|
||||
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error)));
|
||||
throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error)));
|
||||
}
|
||||
|
||||
@chmod($target, 0666 & ~umask());
|
||||
@@ -106,7 +106,7 @@ class File extends \SplFileInfo
|
||||
$content = file_get_contents($this->getPathname());
|
||||
|
||||
if (false === $content) {
|
||||
throw new FileException(sprintf('Could not get the content of the file "%s".', $this->getPathname()));
|
||||
throw new FileException(\sprintf('Could not get the content of the file "%s".', $this->getPathname()));
|
||||
}
|
||||
|
||||
return $content;
|
||||
@@ -116,10 +116,10 @@ class File extends \SplFileInfo
|
||||
{
|
||||
if (!is_dir($directory)) {
|
||||
if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) {
|
||||
throw new FileException(sprintf('Unable to create the "%s" directory.', $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));
|
||||
throw new FileException(\sprintf('Unable to write in the "%s" directory.', $directory));
|
||||
}
|
||||
|
||||
$target = rtrim($directory, '/\\').\DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : $this->getName($name));
|
||||
@@ -134,8 +134,7 @@ class File extends \SplFileInfo
|
||||
{
|
||||
$originalName = str_replace('\\', '/', $name);
|
||||
$pos = strrpos($originalName, '/');
|
||||
$originalName = false === $pos ? $originalName : substr($originalName, $pos + 1);
|
||||
|
||||
return $originalName;
|
||||
return false === $pos ? $originalName : substr($originalName, $pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-6
@@ -31,7 +31,6 @@ use Symfony\Component\Mime\MimeTypes;
|
||||
*/
|
||||
class UploadedFile extends File
|
||||
{
|
||||
private bool $test;
|
||||
private string $originalName;
|
||||
private string $mimeType;
|
||||
private int $error;
|
||||
@@ -61,13 +60,17 @@ 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,
|
||||
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;
|
||||
$this->test = $test;
|
||||
|
||||
parent::__construct($path, \UPLOAD_ERR_OK === $this->error);
|
||||
}
|
||||
@@ -191,7 +194,7 @@ class UploadedFile extends File
|
||||
restore_error_handler();
|
||||
}
|
||||
if (!$moved) {
|
||||
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error)));
|
||||
throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error)));
|
||||
}
|
||||
|
||||
@chmod($target, 0666 & ~umask());
|
||||
@@ -281,6 +284,6 @@ class UploadedFile extends File
|
||||
$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);
|
||||
return \sprintf($message, $this->getClientOriginalName(), $maxFilesize);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -51,7 +51,7 @@ class HeaderBag implements \IteratorAggregate, \Countable, \Stringable
|
||||
foreach ($headers as $name => $values) {
|
||||
$name = ucwords($name, '-');
|
||||
foreach ($values as $value) {
|
||||
$content .= sprintf("%-{$max}s %s\r\n", $name.':', $value);
|
||||
$content .= \sprintf("%-{$max}s %s\r\n", $name.':', $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class HeaderBag implements \IteratorAggregate, \Countable, \Stringable
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $headers[0];
|
||||
return $headers[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +194,7 @@ class HeaderBag implements \IteratorAggregate, \Countable, \Stringable
|
||||
}
|
||||
|
||||
if (false === $date = \DateTimeImmutable::createFromFormat(\DATE_RFC2822, $value)) {
|
||||
throw new \RuntimeException(sprintf('The "%s" HTTP header is not parseable (%s).', $key, $value));
|
||||
throw new \RuntimeException(\sprintf('The "%s" HTTP header is not parseable (%s).', $key, $value));
|
||||
}
|
||||
|
||||
return $date;
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@ class HeaderUtils
|
||||
* Example:
|
||||
*
|
||||
* HeaderUtils::split('da, en-gb;q=0.8', ',;')
|
||||
* // => ['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 ',;='
|
||||
@@ -165,7 +165,7 @@ class HeaderUtils
|
||||
public static function makeDisposition(string $disposition, string $filename, string $filenameFallback = ''): string
|
||||
{
|
||||
if (!\in_array($disposition, [self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE])) {
|
||||
throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
|
||||
throw new \InvalidArgumentException(\sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
|
||||
}
|
||||
|
||||
if ('' === $filenameFallback) {
|
||||
|
||||
+6
-6
@@ -29,13 +29,13 @@ final class InputBag extends ParameterBag
|
||||
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)));
|
||||
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));
|
||||
throw new BadRequestException(\sprintf('Input value "%s" contains a non-scalar value.', $key));
|
||||
}
|
||||
|
||||
return $this === $value ? $default : $value;
|
||||
@@ -68,7 +68,7 @@ final class InputBag extends ParameterBag
|
||||
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)));
|
||||
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;
|
||||
@@ -114,11 +114,11 @@ final class InputBag extends ParameterBag
|
||||
}
|
||||
|
||||
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));
|
||||
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)));
|
||||
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;
|
||||
@@ -131,6 +131,6 @@ final class InputBag extends ParameterBag
|
||||
return $value;
|
||||
}
|
||||
|
||||
throw new BadRequestException(sprintf('Input value "%s" is invalid and flag "FILTER_NULL_ON_FAILURE" was not set.', $key));
|
||||
throw new BadRequestException(\sprintf('Input value "%s" is invalid and flag "FILTER_NULL_ON_FAILURE" was not set.', $key));
|
||||
}
|
||||
}
|
||||
|
||||
+29
-7
@@ -102,7 +102,7 @@ class IpUtils
|
||||
return self::setCacheResult($cacheKey, false);
|
||||
}
|
||||
|
||||
return self::setCacheResult($cacheKey, 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask));
|
||||
return self::setCacheResult($cacheKey, 0 === substr_compare(\sprintf('%032b', ip2long($requestIp)), \sprintf('%032b', ip2long($address)), 0, $netmask));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,25 +178,47 @@ class IpUtils
|
||||
/**
|
||||
* Anonymizes an IP/IPv6.
|
||||
*
|
||||
* Removes the last byte for v4 and the last 8 bytes for v6 IPs
|
||||
* 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): string
|
||||
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.');
|
||||
}
|
||||
|
||||
$wrappedIPv6 = false;
|
||||
if (str_starts_with($ip, '[') && str_ends_with($ip, ']')) {
|
||||
$wrappedIPv6 = true;
|
||||
$ip = substr($ip, 1, -1);
|
||||
}
|
||||
|
||||
$mappedIpV4MaskGenerator = function (string $mask, int $bytesToAnonymize) {
|
||||
$mask .= str_repeat('ff', 4 - $bytesToAnonymize);
|
||||
$mask .= str_repeat('00', $bytesToAnonymize);
|
||||
|
||||
return '::'.implode(':', str_split($mask, 4));
|
||||
};
|
||||
|
||||
$packedAddress = inet_pton($ip);
|
||||
if (4 === \strlen($packedAddress)) {
|
||||
$mask = '255.255.255.0';
|
||||
$mask = rtrim(str_repeat('255.', 4 - $v4Bytes).str_repeat('0.', $v4Bytes), '.');
|
||||
} elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff:ffff'))) {
|
||||
$mask = '::ffff:ffff:ff00';
|
||||
$mask = $mappedIpV4MaskGenerator('ffff', $v4Bytes);
|
||||
} elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff'))) {
|
||||
$mask = '::ffff:ff00';
|
||||
$mask = $mappedIpV4MaskGenerator('', $v4Bytes);
|
||||
} else {
|
||||
$mask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000';
|
||||
$mask = str_repeat('ff', 16 - $v6Bytes).str_repeat('00', $v6Bytes);
|
||||
$mask = implode(':', str_split($mask, 4));
|
||||
}
|
||||
$ip = inet_ntop($packedAddress & inet_pton($mask));
|
||||
|
||||
|
||||
+3
-3
@@ -40,8 +40,8 @@ class JsonResponse extends Response
|
||||
{
|
||||
parent::__construct('', $status, $headers);
|
||||
|
||||
if ($json && !\is_string($data) && !is_numeric($data) && !\is_callable([$data, '__toString'])) {
|
||||
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)));
|
||||
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();
|
||||
@@ -173,7 +173,7 @@ class JsonResponse extends Response
|
||||
// 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));
|
||||
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)
|
||||
|
||||
+9
-11
@@ -23,11 +23,9 @@ use Symfony\Component\HttpFoundation\Exception\UnexpectedValueException;
|
||||
*/
|
||||
class ParameterBag implements \IteratorAggregate, \Countable
|
||||
{
|
||||
protected array $parameters;
|
||||
|
||||
public function __construct(array $parameters = [])
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
public function __construct(
|
||||
protected array $parameters = [],
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,7 +40,7 @@ class ParameterBag implements \IteratorAggregate, \Countable
|
||||
}
|
||||
|
||||
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)));
|
||||
throw new BadRequestException(\sprintf('Unexpected value for parameter "%s": expecting "array", got "%s".', $key, get_debug_type($value)));
|
||||
}
|
||||
|
||||
return $value;
|
||||
@@ -129,7 +127,7 @@ class ParameterBag implements \IteratorAggregate, \Countable
|
||||
{
|
||||
$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));
|
||||
throw new UnexpectedValueException(\sprintf('Parameter value "%s" cannot be converted to "string".', $key));
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
@@ -174,7 +172,7 @@ class ParameterBag implements \IteratorAggregate, \Countable
|
||||
try {
|
||||
return $class::from($value);
|
||||
} catch (\ValueError|\TypeError $e) {
|
||||
throw new UnexpectedValueException(sprintf('Parameter "%s" cannot be converted to enum: %s.', $key, $e->getMessage()), $e->getCode(), $e);
|
||||
throw new UnexpectedValueException(\sprintf('Parameter "%s" cannot be converted to enum: %s.', $key, $e->getMessage()), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,11 +199,11 @@ class ParameterBag implements \IteratorAggregate, \Countable
|
||||
}
|
||||
|
||||
if (\is_object($value) && !$value instanceof \Stringable) {
|
||||
throw new UnexpectedValueException(sprintf('Parameter value "%s" cannot be filtered.', $key));
|
||||
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)));
|
||||
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;
|
||||
@@ -218,7 +216,7 @@ class ParameterBag implements \IteratorAggregate, \Countable
|
||||
return $value;
|
||||
}
|
||||
|
||||
throw new \UnexpectedValueException(sprintf('Parameter value "%s" is invalid and flag "FILTER_NULL_ON_FAILURE" was not set.', $key));
|
||||
throw new \UnexpectedValueException(\sprintf('Parameter value "%s" is invalid and flag "FILTER_NULL_ON_FAILURE" was not set.', $key));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@ class RedirectResponse extends Response
|
||||
$this->setTargetUrl($url);
|
||||
|
||||
if (!$this->isRedirect()) {
|
||||
throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $status));
|
||||
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))) {
|
||||
@@ -71,7 +71,7 @@ class RedirectResponse extends Response
|
||||
$this->targetUrl = $url;
|
||||
|
||||
$this->setContent(
|
||||
sprintf('<!DOCTYPE html>
|
||||
\sprintf('<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
+29
-27
@@ -194,8 +194,7 @@ class Request
|
||||
self::HEADER_X_FORWARDED_PREFIX => 'X_FORWARDED_PREFIX',
|
||||
];
|
||||
|
||||
/** @var bool */
|
||||
private $isIisRewrite = false;
|
||||
private bool $isIisRewrite = false;
|
||||
|
||||
/**
|
||||
* @param array $query The GET parameters
|
||||
@@ -301,8 +300,7 @@ class Request
|
||||
$server['PATH_INFO'] = '';
|
||||
$server['REQUEST_METHOD'] = strtoupper($method);
|
||||
|
||||
$components = parse_url($uri);
|
||||
if (false === $components) {
|
||||
if (false === $components = parse_url(\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#')) {
|
||||
throw new BadRequestException('Invalid URI.');
|
||||
}
|
||||
|
||||
@@ -486,7 +484,7 @@ class Request
|
||||
}
|
||||
|
||||
return
|
||||
sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n".
|
||||
\sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n".
|
||||
$this->headers.
|
||||
$cookieHeader."\r\n".
|
||||
$content;
|
||||
@@ -535,20 +533,26 @@ class Request
|
||||
*
|
||||
* 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']
|
||||
* @param int $trustedHeaderSet A bit field of Request::HEADER_*, to set which headers to trust from your proxies
|
||||
* @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<Request::HEADER_*> $trustedHeaderSet A bit field to set which headers to trust from your proxies
|
||||
*/
|
||||
public static function setTrustedProxies(array $proxies, int $trustedHeaderSet): void
|
||||
{
|
||||
self::$trustedProxies = array_reduce($proxies, function ($proxies, $proxy) {
|
||||
if ('REMOTE_ADDR' !== $proxy) {
|
||||
$proxies[] = $proxy;
|
||||
} elseif (isset($_SERVER['REMOTE_ADDR'])) {
|
||||
$proxies[] = $_SERVER['REMOTE_ADDR'];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return $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;
|
||||
}
|
||||
|
||||
@@ -581,7 +585,7 @@ class Request
|
||||
*/
|
||||
public static function setTrustedHosts(array $hostPatterns): void
|
||||
{
|
||||
self::$trustedHostPatterns = array_map(fn ($hostPattern) => sprintf('{%s}i', $hostPattern), $hostPatterns);
|
||||
self::$trustedHostPatterns = array_map(fn ($hostPattern) => \sprintf('{%s}i', $hostPattern), $hostPatterns);
|
||||
// we need to reset trusted hosts on trusted host patterns change
|
||||
self::$trustedHosts = [];
|
||||
}
|
||||
@@ -764,9 +768,7 @@ class Request
|
||||
*/
|
||||
public function getClientIp(): ?string
|
||||
{
|
||||
$ipAddresses = $this->getClientIps();
|
||||
|
||||
return $ipAddresses[0];
|
||||
return $this->getClientIps()[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1098,7 +1100,7 @@ class Request
|
||||
}
|
||||
$this->isHostValid = false;
|
||||
|
||||
throw new SuspiciousOperationException(sprintf('Invalid Host "%s".', $host));
|
||||
throw new SuspiciousOperationException(\sprintf('Invalid Host "%s".', $host));
|
||||
}
|
||||
|
||||
if (\count(self::$trustedHostPatterns) > 0) {
|
||||
@@ -1121,7 +1123,7 @@ class Request
|
||||
}
|
||||
$this->isHostValid = false;
|
||||
|
||||
throw new SuspiciousOperationException(sprintf('Untrusted Host "%s".', $host));
|
||||
throw new SuspiciousOperationException(\sprintf('Untrusted Host "%s".', $host));
|
||||
}
|
||||
|
||||
return $host;
|
||||
@@ -1461,7 +1463,7 @@ class Request
|
||||
}
|
||||
|
||||
if (!\is_array($content)) {
|
||||
throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content)));
|
||||
throw new JsonException(\sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content)));
|
||||
}
|
||||
|
||||
return new InputBag($content);
|
||||
@@ -1487,7 +1489,7 @@ class Request
|
||||
}
|
||||
|
||||
if (!\is_array($content)) {
|
||||
throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content)));
|
||||
throw new JsonException(\sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content)));
|
||||
}
|
||||
|
||||
return $content;
|
||||
@@ -1546,7 +1548,7 @@ class Request
|
||||
return $preferredLanguages[0] ?? null;
|
||||
}
|
||||
|
||||
$locales = array_map($this->formatLocale(...), $locales ?? []);
|
||||
$locales = array_map($this->formatLocale(...), $locales);
|
||||
if (!$preferredLanguages) {
|
||||
return $locales[0];
|
||||
}
|
||||
@@ -1582,7 +1584,7 @@ class Request
|
||||
$this->languages = [];
|
||||
foreach ($languages as $acceptHeaderItem) {
|
||||
$lang = $acceptHeaderItem->getValue();
|
||||
$this->languages[] = $this->formatLocale($lang);
|
||||
$this->languages[] = self::formatLocale($lang);
|
||||
}
|
||||
$this->languages = array_unique($this->languages);
|
||||
|
||||
@@ -1894,7 +1896,7 @@ class Request
|
||||
}
|
||||
|
||||
$pathInfo = substr($requestUri, \strlen($baseUrl));
|
||||
if (false === $pathInfo || '' === $pathInfo) {
|
||||
if ('' === $pathInfo) {
|
||||
// If substr() returns false then PATH_INFO is set to an empty string
|
||||
return '/';
|
||||
}
|
||||
@@ -1953,7 +1955,7 @@ class Request
|
||||
|
||||
$len = \strlen($prefix);
|
||||
|
||||
if (preg_match(sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) {
|
||||
if (preg_match(\sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) {
|
||||
return $match[0];
|
||||
}
|
||||
|
||||
@@ -2045,7 +2047,7 @@ class Request
|
||||
}
|
||||
$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]));
|
||||
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
|
||||
|
||||
+10
@@ -26,6 +26,16 @@ class RequestStack
|
||||
*/
|
||||
private array $requests = [];
|
||||
|
||||
/**
|
||||
* @param Request[] $requests
|
||||
*/
|
||||
public function __construct(array $requests = [])
|
||||
{
|
||||
foreach ($requests as $request) {
|
||||
$this->push($request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a Request on the stack.
|
||||
*
|
||||
|
||||
+4
-4
@@ -217,7 +217,7 @@ class Response
|
||||
public function __toString(): string
|
||||
{
|
||||
return
|
||||
sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
|
||||
\sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
|
||||
$this->headers."\r\n".
|
||||
$this->getContent();
|
||||
}
|
||||
@@ -365,7 +365,7 @@ class Response
|
||||
$statusCode ??= $this->statusCode;
|
||||
|
||||
// status
|
||||
header(sprintf('HTTP/%s %s %s', $this->version, $statusCode, $this->statusText), true, $statusCode);
|
||||
header(\sprintf('HTTP/%s %s %s', $this->version, $statusCode, $this->statusText), true, $statusCode);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -470,7 +470,7 @@ class Response
|
||||
{
|
||||
$this->statusCode = $code;
|
||||
if ($this->isInvalid()) {
|
||||
throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code));
|
||||
throw new \InvalidArgumentException(\sprintf('The HTTP status code "%s" is not valid.', $code));
|
||||
}
|
||||
|
||||
if (null === $text) {
|
||||
@@ -973,7 +973,7 @@ class Response
|
||||
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)));
|
||||
throw new \InvalidArgumentException(\sprintf('Response does not support the following options: "%s".', implode('", "', $diff)));
|
||||
}
|
||||
|
||||
if (isset($options['etag'])) {
|
||||
|
||||
+1
-1
@@ -195,7 +195,7 @@ class ResponseHeaderBag extends HeaderBag
|
||||
public function getCookies(string $format = self::COOKIES_FLAT): array
|
||||
{
|
||||
if (!\in_array($format, [self::COOKIES_FLAT, self::COOKIES_ARRAY])) {
|
||||
throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', [self::COOKIES_FLAT, self::COOKIES_ARRAY])));
|
||||
throw new \InvalidArgumentException(\sprintf('Format "%s" invalid (%s).', $format, implode(', ', [self::COOKIES_FLAT, self::COOKIES_ARRAY])));
|
||||
}
|
||||
|
||||
if (self::COOKIES_ARRAY === $format) {
|
||||
|
||||
@@ -21,14 +21,13 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta
|
||||
protected array $attributes = [];
|
||||
|
||||
private string $name = 'attributes';
|
||||
private string $storageKey;
|
||||
|
||||
/**
|
||||
* @param string $storageKey The key used to store attributes in the session
|
||||
*/
|
||||
public function __construct(string $storageKey = '_sf2_attributes')
|
||||
{
|
||||
$this->storageKey = $storageKey;
|
||||
public function __construct(
|
||||
private string $storageKey = '_sf2_attributes',
|
||||
) {
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
|
||||
@@ -20,14 +20,13 @@ class AutoExpireFlashBag implements FlashBagInterface
|
||||
{
|
||||
private string $name = 'flashes';
|
||||
private array $flashes = ['display' => [], 'new' => []];
|
||||
private string $storageKey;
|
||||
|
||||
/**
|
||||
* @param string $storageKey The key used to store flashes in the session
|
||||
*/
|
||||
public function __construct(string $storageKey = '_symfony_flashes')
|
||||
{
|
||||
$this->storageKey = $storageKey;
|
||||
public function __construct(
|
||||
private string $storageKey = '_symfony_flashes',
|
||||
) {
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
|
||||
@@ -20,14 +20,13 @@ class FlashBag implements FlashBagInterface
|
||||
{
|
||||
private string $name = 'flashes';
|
||||
private array $flashes = [];
|
||||
private string $storageKey;
|
||||
|
||||
/**
|
||||
* @param string $storageKey The key used to store flashes in the session
|
||||
*/
|
||||
public function __construct(string $storageKey = '_symfony_flashes')
|
||||
{
|
||||
$this->storageKey = $storageKey;
|
||||
public function __construct(
|
||||
private string $storageKey = '_symfony_flashes',
|
||||
) {
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
|
||||
@@ -18,13 +18,16 @@ namespace Symfony\Component\HttpFoundation\Session;
|
||||
*/
|
||||
final class SessionBagProxy implements SessionBagInterface
|
||||
{
|
||||
private SessionBagInterface $bag;
|
||||
private array $data;
|
||||
private ?int $usageIndex;
|
||||
private ?\Closure $usageReporter;
|
||||
|
||||
public function __construct(SessionBagInterface $bag, array &$data, ?int &$usageIndex, ?callable $usageReporter)
|
||||
{
|
||||
public function __construct(
|
||||
private SessionBagInterface $bag,
|
||||
array &$data,
|
||||
?int &$usageIndex,
|
||||
?callable $usageReporter,
|
||||
) {
|
||||
$this->bag = $bag;
|
||||
$this->data = &$data;
|
||||
$this->usageIndex = &$usageIndex;
|
||||
|
||||
@@ -22,14 +22,13 @@ class_exists(Session::class);
|
||||
*/
|
||||
class SessionFactory implements SessionFactoryInterface
|
||||
{
|
||||
private RequestStack $requestStack;
|
||||
private SessionStorageFactoryInterface $storageFactory;
|
||||
private ?\Closure $usageReporter;
|
||||
|
||||
public function __construct(RequestStack $requestStack, SessionStorageFactoryInterface $storageFactory, ?callable $usageReporter = null)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
$this->storageFactory = $storageFactory;
|
||||
public function __construct(
|
||||
private RequestStack $requestStack,
|
||||
private SessionStorageFactoryInterface $storageFactory,
|
||||
?callable $usageReporter = null,
|
||||
) {
|
||||
$this->usageReporter = null === $usageReporter ? null : $usageReporter(...);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ final class SessionUtils
|
||||
public static function popSessionCookie(string $sessionName, #[\SensitiveParameter] string $sessionId): ?string
|
||||
{
|
||||
$sessionCookie = null;
|
||||
$sessionCookiePrefix = sprintf(' %s=', urlencode($sessionName));
|
||||
$sessionCookieWithId = sprintf('%s%s;', $sessionCookiePrefix, urlencode($sessionId));
|
||||
$sessionCookiePrefix = \sprintf(' %s=', urlencode($sessionName));
|
||||
$sessionCookieWithId = \sprintf('%s%s;', $sessionCookiePrefix, urlencode($sessionId));
|
||||
$otherCookies = [];
|
||||
foreach (headers_list() as $h) {
|
||||
if (0 !== stripos($h, 'Set-Cookie:')) {
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
|
||||
{
|
||||
$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')));
|
||||
header(\sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire')));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -88,7 +88,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
|
||||
{
|
||||
if (!headers_sent() && filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOL)) {
|
||||
if (!isset($this->sessionName)) {
|
||||
throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class));
|
||||
throw new \LogicException(\sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class));
|
||||
}
|
||||
$cookie = SessionUtils::popSessionCookie($this->sessionName, $sessionId);
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ class IdentityMarshaller implements MarshallerInterface
|
||||
{
|
||||
foreach ($values as $key => $value) {
|
||||
if (!\is_string($value)) {
|
||||
throw new \LogicException(sprintf('%s accepts only string as data.', __METHOD__));
|
||||
throw new \LogicException(\sprintf('%s accepts only string as data.', __METHOD__));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -18,13 +18,10 @@ use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||
*/
|
||||
class MarshallingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
|
||||
{
|
||||
private AbstractSessionHandler $handler;
|
||||
private MarshallerInterface $marshaller;
|
||||
|
||||
public function __construct(AbstractSessionHandler $handler, MarshallerInterface $marshaller)
|
||||
{
|
||||
$this->handler = $handler;
|
||||
$this->marshaller = $marshaller;
|
||||
public function __construct(
|
||||
private AbstractSessionHandler $handler,
|
||||
private MarshallerInterface $marshaller,
|
||||
) {
|
||||
}
|
||||
|
||||
public function open(string $savePath, string $name): bool
|
||||
|
||||
+5
-7
@@ -21,8 +21,6 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
||||
*/
|
||||
class MemcachedSessionHandler extends AbstractSessionHandler
|
||||
{
|
||||
private \Memcached $memcached;
|
||||
|
||||
/**
|
||||
* Time to live in seconds.
|
||||
*/
|
||||
@@ -42,12 +40,12 @@ class MemcachedSessionHandler extends AbstractSessionHandler
|
||||
*
|
||||
* @throws \InvalidArgumentException When unsupported options are passed
|
||||
*/
|
||||
public function __construct(\Memcached $memcached, array $options = [])
|
||||
{
|
||||
$this->memcached = $memcached;
|
||||
|
||||
public function __construct(
|
||||
private \Memcached $memcached,
|
||||
array $options = [],
|
||||
) {
|
||||
if ($diff = array_diff(array_keys($options), ['prefix', 'expiretime', 'ttl'])) {
|
||||
throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff)));
|
||||
throw new \InvalidArgumentException(\sprintf('The following options are not supported "%s".', implode(', ', $diff)));
|
||||
}
|
||||
|
||||
$this->ttl = $options['expiretime'] ?? $options['ttl'] ?? null;
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@ class NativeFileSessionHandler extends \SessionHandler
|
||||
|
||||
if ($count = substr_count($savePath, ';')) {
|
||||
if ($count > 2) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid argument $savePath \'%s\'.', $savePath));
|
||||
throw new \InvalidArgumentException(\sprintf('Invalid argument $savePath \'%s\'.', $savePath));
|
||||
}
|
||||
|
||||
// characters after last ';' are the path
|
||||
@@ -42,7 +42,7 @@ class NativeFileSessionHandler extends \SessionHandler
|
||||
}
|
||||
|
||||
if ($baseDir && !is_dir($baseDir) && !@mkdir($baseDir, 0777, true) && !is_dir($baseDir)) {
|
||||
throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $baseDir));
|
||||
throw new \RuntimeException(\sprintf('Session Storage was not able to create directory "%s".', $baseDir));
|
||||
}
|
||||
|
||||
if ($savePath !== \ini_get('session.save_path')) {
|
||||
|
||||
+6
-6
@@ -155,7 +155,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
{
|
||||
if ($pdoOrDsn instanceof \PDO) {
|
||||
if (\PDO::ERRMODE_EXCEPTION !== $pdoOrDsn->getAttribute(\PDO::ATTR_ERRMODE)) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__));
|
||||
throw new \InvalidArgumentException(\sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__));
|
||||
}
|
||||
|
||||
$this->pdo = $pdoOrDsn;
|
||||
@@ -222,7 +222,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
$table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
|
||||
break;
|
||||
default:
|
||||
throw new \DomainException(sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver));
|
||||
throw new \DomainException(\sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver));
|
||||
}
|
||||
$table->setPrimaryKey([$this->idCol]);
|
||||
$table->addIndex([$this->lifetimeCol], $this->lifetimeCol.'_idx');
|
||||
@@ -255,7 +255,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
'pgsql' => "CREATE TABLE $this->table ($this->idCol VARCHAR(128) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)",
|
||||
'oci' => "CREATE TABLE $this->table ($this->idCol VARCHAR2(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)",
|
||||
'sqlsrv' => "CREATE TABLE $this->table ($this->idCol VARCHAR(128) NOT NULL PRIMARY KEY, $this->dataCol VARBINARY(MAX) NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)",
|
||||
default => throw new \DomainException(sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver)),
|
||||
default => throw new \DomainException(\sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver)),
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -536,7 +536,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
return $dsn;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('The scheme "%s" is not supported by the PdoSessionHandler URL configuration. Pass a PDO DSN directly.', $params['scheme']));
|
||||
throw new \InvalidArgumentException(\sprintf('The scheme "%s" is not supported by the PdoSessionHandler URL configuration. Pass a PDO DSN directly.', $params['scheme']));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,7 +732,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
case 'sqlite':
|
||||
throw new \DomainException('SQLite does not support advisory locks.');
|
||||
default:
|
||||
throw new \DomainException(sprintf('Advisory locks are currently not implemented for PDO driver "%s".', $this->driver));
|
||||
throw new \DomainException(\sprintf('Advisory locks are currently not implemented for PDO driver "%s".', $this->driver));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,7 +774,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
// we already locked when starting transaction
|
||||
break;
|
||||
default:
|
||||
throw new \DomainException(sprintf('Transactional locks are currently not implemented for PDO driver "%s".', $this->driver));
|
||||
throw new \DomainException(\sprintf('Transactional locks are currently not implemented for PDO driver "%s".', $this->driver));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ class RedisSessionHandler extends AbstractSessionHandler
|
||||
array $options = [],
|
||||
) {
|
||||
if ($diff = array_diff(array_keys($options), ['prefix', 'ttl'])) {
|
||||
throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff)));
|
||||
throw new \InvalidArgumentException(\sprintf('The following options are not supported "%s".', implode(', ', $diff)));
|
||||
}
|
||||
|
||||
$this->prefix = $options['prefix'] ?? 'sf_s';
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ class SessionHandlerFactory
|
||||
return new PdoSessionHandler($connection);
|
||||
|
||||
case !\is_string($connection):
|
||||
throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', get_debug_type($connection)));
|
||||
throw new \InvalidArgumentException(\sprintf('Unsupported Connection: "%s".', get_debug_type($connection)));
|
||||
case str_starts_with($connection, 'file://'):
|
||||
$savePath = substr($connection, 7);
|
||||
|
||||
@@ -90,6 +90,6 @@ class SessionHandlerFactory
|
||||
return new PdoSessionHandler($connection, $options);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', $connection));
|
||||
throw new \InvalidArgumentException(\sprintf('Unsupported Connection: "%s".', $connection));
|
||||
}
|
||||
}
|
||||
|
||||
+4
-6
@@ -18,16 +18,14 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
||||
*/
|
||||
class StrictSessionHandler extends AbstractSessionHandler
|
||||
{
|
||||
private \SessionHandlerInterface $handler;
|
||||
private bool $doDestroy;
|
||||
|
||||
public function __construct(\SessionHandlerInterface $handler)
|
||||
{
|
||||
public function __construct(
|
||||
private \SessionHandlerInterface $handler,
|
||||
) {
|
||||
if ($handler instanceof \SessionUpdateTimestampHandlerInterface) {
|
||||
throw new \LogicException(sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', get_debug_type($handler), self::class));
|
||||
throw new \LogicException(\sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', get_debug_type($handler), self::class));
|
||||
}
|
||||
|
||||
$this->handler = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,18 +29,16 @@ class MetadataBag implements SessionBagInterface
|
||||
protected array $meta = [self::CREATED => 0, self::UPDATED => 0, self::LIFETIME => 0];
|
||||
|
||||
private string $name = '__metadata';
|
||||
private string $storageKey;
|
||||
private int $lastUsed;
|
||||
private int $updateThreshold;
|
||||
|
||||
/**
|
||||
* @param string $storageKey The key used to store bag in the session
|
||||
* @param int $updateThreshold The time to wait between two UPDATED updates
|
||||
*/
|
||||
public function __construct(string $storageKey = '_sf2_meta', int $updateThreshold = 0)
|
||||
{
|
||||
$this->storageKey = $storageKey;
|
||||
$this->updateThreshold = $updateThreshold;
|
||||
public function __construct(
|
||||
private string $storageKey = '_sf2_meta',
|
||||
private int $updateThreshold = 0,
|
||||
) {
|
||||
}
|
||||
|
||||
public function initialize(array &$array): void
|
||||
|
||||
@@ -28,7 +28,6 @@ use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
|
||||
class MockArraySessionStorage implements SessionStorageInterface
|
||||
{
|
||||
protected string $id = '';
|
||||
protected string $name;
|
||||
protected bool $started = false;
|
||||
protected bool $closed = false;
|
||||
protected array $data = [];
|
||||
@@ -39,9 +38,10 @@ class MockArraySessionStorage implements SessionStorageInterface
|
||||
*/
|
||||
protected array $bags = [];
|
||||
|
||||
public function __construct(string $name = 'MOCKSESSID', ?MetadataBag $metaBag = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
public function __construct(
|
||||
protected string $name = 'MOCKSESSID',
|
||||
?MetadataBag $metaBag = null,
|
||||
) {
|
||||
$this->setMetadataBag($metaBag);
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ class MockArraySessionStorage implements SessionStorageInterface
|
||||
public function getBag(string $name): SessionBagInterface
|
||||
{
|
||||
if (!isset($this->bags[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name));
|
||||
throw new \InvalidArgumentException(\sprintf('The SessionBagInterface "%s" is not registered.', $name));
|
||||
}
|
||||
|
||||
if (!$this->started) {
|
||||
|
||||
@@ -35,7 +35,7 @@ class MockFileSessionStorage extends MockArraySessionStorage
|
||||
$savePath ??= sys_get_temp_dir();
|
||||
|
||||
if (!is_dir($savePath) && !@mkdir($savePath, 0777, true) && !is_dir($savePath)) {
|
||||
throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $savePath));
|
||||
throw new \RuntimeException(\sprintf('Session Storage was not able to create directory "%s".', $savePath));
|
||||
}
|
||||
|
||||
$this->savePath = $savePath;
|
||||
|
||||
+5
-9
@@ -21,18 +21,14 @@ class_exists(MockFileSessionStorage::class);
|
||||
*/
|
||||
class MockFileSessionStorageFactory implements SessionStorageFactoryInterface
|
||||
{
|
||||
private ?string $savePath;
|
||||
private string $name;
|
||||
private ?MetadataBag $metaBag;
|
||||
|
||||
/**
|
||||
* @see MockFileSessionStorage constructor.
|
||||
*/
|
||||
public function __construct(?string $savePath = null, string $name = 'MOCKSESSID', ?MetadataBag $metaBag = null)
|
||||
{
|
||||
$this->savePath = $savePath;
|
||||
$this->name = $name;
|
||||
$this->metaBag = $metaBag;
|
||||
public function __construct(
|
||||
private ?string $savePath = null,
|
||||
private string $name = 'MOCKSESSID',
|
||||
private ?MetadataBag $metaBag = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function createStorage(?Request $request): SessionStorageInterface
|
||||
|
||||
@@ -62,16 +62,16 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
* gc_probability, "1"
|
||||
* lazy_write, "1"
|
||||
* name, "PHPSESSID"
|
||||
* referer_check, ""
|
||||
* referer_check, "" (deprecated since Symfony 7.2, to be removed in Symfony 8.0)
|
||||
* serialize_handler, "php"
|
||||
* use_strict_mode, "1"
|
||||
* use_cookies, "1"
|
||||
* use_only_cookies, "1"
|
||||
* use_trans_sid, "0"
|
||||
* sid_length, "32"
|
||||
* sid_bits_per_character, "5"
|
||||
* trans_sid_hosts, $_SERVER['HTTP_HOST']
|
||||
* trans_sid_tags, "a=href,area=href,frame=src,form="
|
||||
* use_only_cookies, "1" (deprecated since Symfony 7.2, to be removed in Symfony 8.0)
|
||||
* use_trans_sid, "0" (deprecated since Symfony 7.2, to be removed in Symfony 8.0)
|
||||
* sid_length, "32" (@deprecated since Symfony 7.2, to be removed in 8.0)
|
||||
* sid_bits_per_character, "5" (@deprecated since Symfony 7.2, to be removed in 8.0)
|
||||
* trans_sid_hosts, $_SERVER['HTTP_HOST'] (deprecated since Symfony 7.2, to be removed in Symfony 8.0)
|
||||
* trans_sid_tags, "a=href,area=href,frame=src,form=" (deprecated since Symfony 7.2, to be removed in Symfony 8.0)
|
||||
*/
|
||||
public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface|null $handler = null, ?MetadataBag $metaBag = null)
|
||||
{
|
||||
@@ -113,7 +113,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
}
|
||||
|
||||
if (filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOL) && 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));
|
||||
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;
|
||||
@@ -126,8 +126,8 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
* 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,-`
|
||||
* - 5 for range `a-v0-9` (@deprecated since Symfony 7.2, it will default to 4 and the option will be ignored in Symfony 8.0)
|
||||
* - 6 for range `a-zA-Z0-9,-` (@deprecated since Symfony 7.2, it will default to 4 and the option will be ignored in Symfony 8.0)
|
||||
*
|
||||
* ---------- Part 2
|
||||
*
|
||||
@@ -139,6 +139,8 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
* - 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.
|
||||
*
|
||||
* This is @deprecated since Symfony 7.2, the sid length will default to 32 and the option will be ignored in Symfony 8.0.
|
||||
*
|
||||
* ---------- Conclusion
|
||||
*
|
||||
* The parts 1 and 2 prevent the warning below:
|
||||
@@ -224,7 +226,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
$previousHandler = set_error_handler(function ($type, $msg, $file, $line) use (&$previousHandler) {
|
||||
if (\E_WARNING === $type && str_starts_with($msg, 'session_write_close():')) {
|
||||
$handler = $this->saveHandler instanceof SessionHandlerProxy ? $this->saveHandler->getHandler() : $this->saveHandler;
|
||||
$msg = sprintf('session_write_close(): Failed to write session data with "%s" handler', $handler::class);
|
||||
$msg = \sprintf('session_write_close(): Failed to write session data with "%s" handler', $handler::class);
|
||||
}
|
||||
|
||||
return $previousHandler ? $previousHandler($type, $msg, $file, $line) : false;
|
||||
@@ -271,7 +273,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
public function getBag(string $name): SessionBagInterface
|
||||
{
|
||||
if (!isset($this->bags[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name));
|
||||
throw new \InvalidArgumentException(\sprintf('The SessionBagInterface "%s" is not registered.', $name));
|
||||
}
|
||||
|
||||
if (!$this->started && $this->saveHandler->isActive()) {
|
||||
@@ -328,6 +330,10 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||
]);
|
||||
|
||||
foreach ($options as $key => $value) {
|
||||
if (\in_array($key, ['referer_check', 'use_only_cookies', 'use_trans_sid', 'trans_sid_hosts', 'trans_sid_tags', 'sid_length', 'sid_bits_per_character'], true)) {
|
||||
trigger_deprecation('symfony/http-foundation', '7.2', 'NativeSessionStorage\'s "%s" option is deprecated and will be ignored in Symfony 8.0.', $key);
|
||||
}
|
||||
|
||||
if (isset($validOptions[$key])) {
|
||||
if ('cookie_secure' === $key && 'auto' === $value) {
|
||||
continue;
|
||||
|
||||
+6
-11
@@ -22,20 +22,15 @@ class_exists(NativeSessionStorage::class);
|
||||
*/
|
||||
class NativeSessionStorageFactory implements SessionStorageFactoryInterface
|
||||
{
|
||||
private array $options;
|
||||
private AbstractProxy|\SessionHandlerInterface|null $handler;
|
||||
private ?MetadataBag $metaBag;
|
||||
private bool $secure;
|
||||
|
||||
/**
|
||||
* @see NativeSessionStorage constructor.
|
||||
*/
|
||||
public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface|null $handler = null, ?MetadataBag $metaBag = null, bool $secure = false)
|
||||
{
|
||||
$this->options = $options;
|
||||
$this->handler = $handler;
|
||||
$this->metaBag = $metaBag;
|
||||
$this->secure = $secure;
|
||||
public function __construct(
|
||||
private array $options = [],
|
||||
private AbstractProxy|\SessionHandlerInterface|null $handler = null,
|
||||
private ?MetadataBag $metaBag = null,
|
||||
private bool $secure = false,
|
||||
) {
|
||||
}
|
||||
|
||||
public function createStorage(?Request $request): SessionStorageInterface
|
||||
|
||||
+5
-9
@@ -22,15 +22,11 @@ class_exists(PhpBridgeSessionStorage::class);
|
||||
*/
|
||||
class PhpBridgeSessionStorageFactory implements SessionStorageFactoryInterface
|
||||
{
|
||||
private AbstractProxy|\SessionHandlerInterface|null $handler;
|
||||
private ?MetadataBag $metaBag;
|
||||
private bool $secure;
|
||||
|
||||
public function __construct(AbstractProxy|\SessionHandlerInterface|null $handler = null, ?MetadataBag $metaBag = null, bool $secure = false)
|
||||
{
|
||||
$this->handler = $handler;
|
||||
$this->metaBag = $metaBag;
|
||||
$this->secure = $secure;
|
||||
public function __construct(
|
||||
private AbstractProxy|\SessionHandlerInterface|null $handler = null,
|
||||
private ?MetadataBag $metaBag = null,
|
||||
private bool $secure = false,
|
||||
) {
|
||||
}
|
||||
|
||||
public function createStorage(?Request $request): SessionStorageInterface
|
||||
|
||||
+3
-5
@@ -18,11 +18,9 @@ use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandle
|
||||
*/
|
||||
class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
|
||||
{
|
||||
protected \SessionHandlerInterface $handler;
|
||||
|
||||
public function __construct(\SessionHandlerInterface $handler)
|
||||
{
|
||||
$this->handler = $handler;
|
||||
public function __construct(
|
||||
protected \SessionHandlerInterface $handler,
|
||||
) {
|
||||
$this->wrapper = $handler instanceof \SessionHandler;
|
||||
$this->saveHandlerName = $this->wrapper || ($handler instanceof StrictSessionHandler && $handler->isWrapper()) ? \ini_get('session.save_handler') : 'user';
|
||||
}
|
||||
|
||||
+5
-8
@@ -16,18 +16,15 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
final class RequestAttributeValueSame extends Constraint
|
||||
{
|
||||
private string $name;
|
||||
private string $value;
|
||||
|
||||
public function __construct(string $name, string $value)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
public function __construct(
|
||||
private string $name,
|
||||
private string $value,
|
||||
) {
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return sprintf('has attribute "%s" with value "%s"', $this->name, $this->value);
|
||||
return \sprintf('has attribute "%s" with value "%s"', $this->name, $this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-16
@@ -17,31 +17,25 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class ResponseCookieValueSame extends Constraint
|
||||
{
|
||||
private string $name;
|
||||
private string $value;
|
||||
private string $path;
|
||||
private ?string $domain;
|
||||
|
||||
public function __construct(string $name, string $value, string $path = '/', ?string $domain = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
$this->path = $path;
|
||||
$this->domain = $domain;
|
||||
public function __construct(
|
||||
private string $name,
|
||||
private string $value,
|
||||
private string $path = '/',
|
||||
private ?string $domain = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
$str = sprintf('has cookie "%s"', $this->name);
|
||||
$str = \sprintf('has cookie "%s"', $this->name);
|
||||
if ('/' !== $this->path) {
|
||||
$str .= sprintf(' with path "%s"', $this->path);
|
||||
$str .= \sprintf(' with path "%s"', $this->path);
|
||||
}
|
||||
if ($this->domain) {
|
||||
$str .= sprintf(' for domain "%s"', $this->domain);
|
||||
$str .= \sprintf(' for domain "%s"', $this->domain);
|
||||
}
|
||||
$str .= sprintf(' with value "%s"', $this->value);
|
||||
|
||||
return $str;
|
||||
return $str.\sprintf(' with value "%s"', $this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,16 +22,11 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
*/
|
||||
final class ResponseFormatSame extends Constraint
|
||||
{
|
||||
private Request $request;
|
||||
private ?string $format;
|
||||
|
||||
public function __construct(
|
||||
Request $request,
|
||||
?string $format,
|
||||
private Request $request,
|
||||
private ?string $format,
|
||||
private readonly bool $verbose = true,
|
||||
) {
|
||||
$this->request = $request;
|
||||
$this->format = $format;
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
|
||||
@@ -17,25 +17,21 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class ResponseHasCookie extends Constraint
|
||||
{
|
||||
private string $name;
|
||||
private string $path;
|
||||
private ?string $domain;
|
||||
|
||||
public function __construct(string $name, string $path = '/', ?string $domain = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->path = $path;
|
||||
$this->domain = $domain;
|
||||
public function __construct(
|
||||
private string $name,
|
||||
private string $path = '/',
|
||||
private ?string $domain = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
$str = sprintf('has cookie "%s"', $this->name);
|
||||
$str = \sprintf('has cookie "%s"', $this->name);
|
||||
if ('/' !== $this->path) {
|
||||
$str .= sprintf(' with path "%s"', $this->path);
|
||||
$str .= \sprintf(' with path "%s"', $this->path);
|
||||
}
|
||||
if ($this->domain) {
|
||||
$str .= sprintf(' for domain "%s"', $this->domain);
|
||||
$str .= \sprintf(' for domain "%s"', $this->domain);
|
||||
}
|
||||
|
||||
return $str;
|
||||
|
||||
@@ -16,16 +16,14 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class ResponseHasHeader extends Constraint
|
||||
{
|
||||
private string $headerName;
|
||||
|
||||
public function __construct(string $headerName)
|
||||
{
|
||||
$this->headerName = $headerName;
|
||||
public function __construct(
|
||||
private string $headerName,
|
||||
) {
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return sprintf('has header "%s"', $this->headerName);
|
||||
return \sprintf('has header "%s"', $this->headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ final class ResponseHeaderLocationSame extends Constraint
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return sprintf('has header "Location" matching "%s"', $this->expectedValue);
|
||||
return \sprintf('has header "Location" matching "%s"', $this->expectedValue);
|
||||
}
|
||||
|
||||
protected function matches($other): bool
|
||||
@@ -53,7 +53,7 @@ final class ResponseHeaderLocationSame extends Constraint
|
||||
}
|
||||
|
||||
if (str_starts_with($url, '//')) {
|
||||
return sprintf('%s:%s', $this->request->getScheme(), $url);
|
||||
return \sprintf('%s:%s', $this->request->getScheme(), $url);
|
||||
}
|
||||
|
||||
if (str_starts_with($url, '/')) {
|
||||
|
||||
@@ -16,18 +16,15 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class ResponseHeaderSame extends Constraint
|
||||
{
|
||||
private string $headerName;
|
||||
private string $expectedValue;
|
||||
|
||||
public function __construct(string $headerName, string $expectedValue)
|
||||
{
|
||||
$this->headerName = $headerName;
|
||||
$this->expectedValue = $expectedValue;
|
||||
public function __construct(
|
||||
private string $headerName,
|
||||
private string $expectedValue,
|
||||
) {
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue);
|
||||
return \sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,11 +16,10 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class ResponseStatusCodeSame extends Constraint
|
||||
{
|
||||
private int $statusCode;
|
||||
|
||||
public function __construct(int $statusCode, private readonly bool $verbose = true)
|
||||
{
|
||||
$this->statusCode = $statusCode;
|
||||
public function __construct(
|
||||
private int $statusCode,
|
||||
private readonly bool $verbose = true,
|
||||
) {
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
|
||||
+8
-13
@@ -18,23 +18,18 @@ use Symfony\Component\HttpFoundation\Exception\LogicException;
|
||||
*/
|
||||
class UriSigner
|
||||
{
|
||||
private string $secret;
|
||||
private string $hashParameter;
|
||||
private string $expirationParameter;
|
||||
|
||||
/**
|
||||
* @param string $hashParameter Query string parameter to use
|
||||
* @param string $expirationParameter Query string parameter to use for expiration
|
||||
*/
|
||||
public function __construct(#[\SensitiveParameter] string $secret, string $hashParameter = '_hash', string $expirationParameter = '_expiration')
|
||||
{
|
||||
public function __construct(
|
||||
#[\SensitiveParameter] private string $secret,
|
||||
private string $hashParameter = '_hash',
|
||||
private string $expirationParameter = '_expiration',
|
||||
) {
|
||||
if (!$secret) {
|
||||
throw new \InvalidArgumentException('A non-empty secret is required.');
|
||||
}
|
||||
|
||||
$this->secret = $secret;
|
||||
$this->hashParameter = $hashParameter;
|
||||
$this->expirationParameter = $expirationParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +55,7 @@ class UriSigner
|
||||
}
|
||||
|
||||
if (null !== $expiration && !$expiration instanceof \DateTimeInterface && !$expiration instanceof \DateInterval && !\is_int($expiration)) {
|
||||
throw new \TypeError(sprintf('The second argument of %s() must be an instance of %s or %s, an integer or null (%s given).', __METHOD__, \DateTimeInterface::class, \DateInterval::class, get_debug_type($expiration)));
|
||||
throw new \TypeError(\sprintf('The second argument of %s() must be an instance of %s or %s, an integer or null (%s given).', __METHOD__, \DateTimeInterface::class, \DateInterval::class, get_debug_type($expiration)));
|
||||
}
|
||||
|
||||
$url = parse_url($uri);
|
||||
@@ -71,11 +66,11 @@ class UriSigner
|
||||
}
|
||||
|
||||
if (isset($params[$this->hashParameter])) {
|
||||
throw new LogicException(sprintf('URI query parameter conflict: parameter name "%s" is reserved.', $this->hashParameter));
|
||||
throw new LogicException(\sprintf('URI query parameter conflict: parameter name "%s" is reserved.', $this->hashParameter));
|
||||
}
|
||||
|
||||
if (isset($params[$this->expirationParameter])) {
|
||||
throw new LogicException(sprintf('URI query parameter conflict: parameter name "%s" is reserved.', $this->expirationParameter));
|
||||
throw new LogicException(\sprintf('URI query parameter conflict: parameter name "%s" is reserved.', $this->expirationParameter));
|
||||
}
|
||||
|
||||
if (null !== $expiration) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/deprecation-contracts": "^2.5|^3.0",
|
||||
"symfony/polyfill-mbstring": "~1.1",
|
||||
"symfony/polyfill-php83": "^1.27"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user