update patch 1

This commit is contained in:
fiqhpratama
2024-12-02 01:18:34 +07:00
parent 453d9bb470
commit 25026b0a85
3380 changed files with 103529 additions and 363623 deletions
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+3 -4
View File
@@ -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
+6 -3
View File
@@ -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;
+5 -6
View File
@@ -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
View File
@@ -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:')) {
@@ -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);
@@ -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__));
}
}
@@ -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
@@ -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;
@@ -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')) {
@@ -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));
}
}
@@ -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';
@@ -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));
}
}
@@ -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;
@@ -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;
@@ -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
@@ -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
@@ -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';
}
@@ -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);
}
/**
@@ -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);
}
/**
@@ -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
View File
@@ -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) {
+1
View File
@@ -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"
},