diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php
index 6462e2c15a7e..fe84ba5dad29 100644
--- a/src/Symfony/Component/Debug/ErrorHandler.php
+++ b/src/Symfony/Component/Debug/ErrorHandler.php
@@ -499,7 +499,7 @@ public function handleError($type, $message, $file, $line)
if ($this->isRecursive) {
$log = 0;
} else {
- if (!\defined('HHVM_VERSION')) {
+ if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404) && !\defined('HHVM_VERSION')) {
$currentErrorHandler = set_error_handler('var_dump');
restore_error_handler();
}
@@ -511,7 +511,7 @@ public function handleError($type, $message, $file, $line)
} finally {
$this->isRecursive = false;
- if (!\defined('HHVM_VERSION')) {
+ if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404) && !\defined('HHVM_VERSION')) {
set_error_handler($currentErrorHandler);
}
}
diff --git a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php
index b45a6d08c5b6..fcead4f84e01 100644
--- a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php
+++ b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php
@@ -329,8 +329,6 @@ public function testHandleDeprecation()
$handler = new ErrorHandler();
$handler->setDefaultLogger($logger);
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, []);
-
- restore_error_handler();
}
public function testHandleException()
diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php
index c98eea89e5c8..0c8edfcd9d3b 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php
@@ -519,7 +519,7 @@ public function handleError(int $type, string $message, string $file, int $line)
if ($this->isRecursive) {
$log = 0;
} else {
- if (!\defined('HHVM_VERSION')) {
+ if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404)) {
$currentErrorHandler = set_error_handler('var_dump');
restore_error_handler();
}
@@ -531,7 +531,7 @@ public function handleError(int $type, string $message, string $file, int $line)
} finally {
$this->isRecursive = false;
- if (!\defined('HHVM_VERSION')) {
+ if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404)) {
set_error_handler($currentErrorHandler);
}
}
diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php
index 70710302fd97..28b311549272 100644
--- a/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php
+++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php
@@ -363,8 +363,6 @@ public function testHandleDeprecation()
$handler = new ErrorHandler();
$handler->setDefaultLogger($logger);
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, []);
-
- restore_error_handler();
}
/**
@@ -618,6 +616,10 @@ public function errorHandlerWhenLoggingProvider(): iterable
public function testAssertQuietEval()
{
+ if ('-1' === ini_get('zend.assertions')) {
+ $this->markTestSkipped('zend.assertions is forcibly disabled');
+ }
+
$ini = [
ini_set('zend.assertions', 1),
ini_set('assert.active', 1),
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
index 325f61f11232..4d7eed8b0c43 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
@@ -117,11 +117,16 @@ public function reverseTransform($value)
// date-only patterns require parsing to be done in UTC, as midnight might not exist in the local timezone due
// to DST changes
$dateOnly = $this->isPatternDateOnly();
+ $dateFormatter = $this->getIntlDateFormatter($dateOnly);
- $timestamp = $this->getIntlDateFormatter($dateOnly)->parse($value);
+ try {
+ $timestamp = @$dateFormatter->parse($value);
+ } catch (\IntlException $e) {
+ throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
+ }
if (0 != intl_get_error_code()) {
- throw new TransformationFailedException(intl_get_error_message());
+ throw new TransformationFailedException(intl_get_error_message(), intl_get_error_code());
} elseif ($timestamp > 253402214400) {
// This timestamp represents UTC midnight of 9999-12-31 to prevent 5+ digit years
throw new TransformationFailedException('Years beyond 9999 are not supported.');
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
index 808571cbef41..c9821bfe7475 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
@@ -27,6 +27,12 @@ protected function setUp(): void
{
parent::setUp();
+ // Normalize intl. configuration settings.
+ if (\extension_loaded('intl')) {
+ $this->iniSet('intl.use_exceptions', 0);
+ $this->iniSet('intl.error_level', 0);
+ }
+
// Since we test against "de_AT", we need the full implementation
IntlTestHelper::requireFullIntl($this, '57.1');
@@ -322,4 +328,44 @@ public function testReverseTransformFiveDigitYearsWithTimestamp()
$transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, null, \IntlDateFormatter::GREGORIAN, 'yyyy-MM-dd HH:mm:ss');
$transformer->reverseTransform('20107-03-21 12:34:56');
}
+
+ public function testReverseTransformWrapsIntlErrorsWithErrorLevel()
+ {
+ if (!\extension_loaded('intl')) {
+ $this->markTestSkipped('intl extension is not loaded');
+ }
+
+ $this->iniSet('intl.error_level', E_WARNING);
+
+ $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
+ $transformer = new DateTimeToLocalizedStringTransformer();
+ $transformer->reverseTransform('12345');
+ }
+
+ public function testReverseTransformWrapsIntlErrorsWithExceptions()
+ {
+ if (!\extension_loaded('intl')) {
+ $this->markTestSkipped('intl extension is not loaded');
+ }
+
+ $this->iniSet('intl.use_exceptions', 1);
+
+ $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
+ $transformer = new DateTimeToLocalizedStringTransformer();
+ $transformer->reverseTransform('12345');
+ }
+
+ public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel()
+ {
+ if (!\extension_loaded('intl')) {
+ $this->markTestSkipped('intl extension is not loaded');
+ }
+
+ $this->iniSet('intl.use_exceptions', 1);
+ $this->iniSet('intl.error_level', E_WARNING);
+
+ $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
+ $transformer = new DateTimeToLocalizedStringTransformer();
+ $transformer->reverseTransform('12345');
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
index cdc66990488d..e71034abac98 100644
--- a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
+++ b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
@@ -252,10 +252,13 @@ public function getCookies($format = self::COOKIES_FLAT)
* @param string $domain
* @param bool $secure
* @param bool $httpOnly
+ * @param string $sameSite
*/
- public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true)
+ public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true/*, $sameSite = null*/)
{
- $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, null));
+ $sameSite = \func_num_args() > 5 ? func_get_arg(5) : null;
+
+ $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, $sameSite));
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
index 4d924412232c..18b3c36a6ae9 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
@@ -128,6 +128,14 @@ public function testClearCookieSecureNotHttpOnly()
$this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; secure', $bag);
}
+ public function testClearCookieSamesite()
+ {
+ $bag = new ResponseHeaderBag([]);
+
+ $bag->clearCookie('foo', '/', null, true, false, 'none');
+ $this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; secure; samesite=none', $bag);
+ }
+
public function testReplace()
{
$bag = new ResponseHeaderBag([]);
diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php
index aa9d50065f89..db4c2919dff5 100644
--- a/src/Symfony/Component/Process/Process.php
+++ b/src/Symfony/Component/Process/Process.php
@@ -336,7 +336,7 @@ public function start(callable $callback = null, array $env = [])
throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd));
}
- $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $options);
+ $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $options);
if (!\is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new process.');
diff --git a/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php b/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php
index a76bf6ef91eb..a151de825aa4 100644
--- a/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php
+++ b/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php
@@ -127,7 +127,7 @@ public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyIn
private function migrateSession(Request $request, TokenInterface $token, ?string $providerKey)
{
- if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession() || \in_array($providerKey, $this->statelessProviderKeys, true)) {
+ if (\in_array($providerKey, $this->statelessProviderKeys, true) || !$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
return;
}
diff --git a/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php b/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php
index 0256ec22ff16..5a6c3c26d089 100644
--- a/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php
+++ b/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php
@@ -153,6 +153,25 @@ public function testSessionStrategyIsNotCalledWhenStateless()
$handler->authenticateWithToken($this->token, $this->request, 'some_provider_key');
}
+ /**
+ * @requires function \Symfony\Component\HttpFoundation\Request::setSessionFactory
+ */
+ public function testSessionIsNotInstantiatedOnStatelessFirewall()
+ {
+ $sessionFactory = $this->getMockBuilder(\stdClass::class)
+ ->setMethods(['__invoke'])
+ ->getMock();
+
+ $sessionFactory->expects($this->never())
+ ->method('__invoke');
+
+ $this->request->setSessionFactory($sessionFactory);
+
+ $handler = new GuardAuthenticatorHandler($this->tokenStorage, $this->dispatcher, ['stateless_provider_key']);
+ $handler->setSessionAuthenticationStrategy($this->sessionStrategy);
+ $handler->authenticateWithToken($this->token, $this->request, 'stateless_provider_key');
+ }
+
protected function setUp(): void
{
$this->tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock();
diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php
index 6ae15ed9f306..41d61732ac92 100644
--- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php
+++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php
@@ -39,6 +39,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
protected $options = [
'secure' => false,
'httponly' => true,
+ 'samesite' => null,
];
private $providerKey;
private $secret;
@@ -276,7 +277,7 @@ protected function cancelCookie(Request $request)
$this->logger->debug('Clearing remember-me cookie.', ['name' => $this->options['name']]);
}
- $request->attributes->set(self::COOKIE_ATTR_NAME, new Cookie($this->options['name'], null, 1, $this->options['path'], $this->options['domain'], $this->options['secure'] ?? $request->isSecure(), $this->options['httponly'], false, $this->options['samesite'] ?? null));
+ $request->attributes->set(self::COOKIE_ATTR_NAME, new Cookie($this->options['name'], null, 1, $this->options['path'], $this->options['domain'], $this->options['secure'] ?? $request->isSecure(), $this->options['httponly'], false, $this->options['samesite']));
}
/**
diff --git a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
index 61b1257b4a46..167a09474135 100644
--- a/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
+++ b/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
@@ -86,7 +86,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request)
$this->options['secure'] ?? $request->isSecure(),
$this->options['httponly'],
false,
- $this->options['samesite'] ?? null
+ $this->options['samesite']
)
);
@@ -121,7 +121,7 @@ protected function onLoginSuccess(Request $request, Response $response, TokenInt
$this->options['secure'] ?? $request->isSecure(),
$this->options['httponly'],
false,
- $this->options['samesite'] ?? null
+ $this->options['samesite']
)
);
}
diff --git a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php
index 6db2a78330d7..8dfce95ae45b 100644
--- a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php
+++ b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php
@@ -83,7 +83,7 @@ protected function onLoginSuccess(Request $request, Response $response, TokenInt
$this->options['secure'] ?? $request->isSecure(),
$this->options['httponly'],
false,
- $this->options['samesite'] ?? null
+ $this->options['samesite']
)
);
}
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf
index 8f8d2d0a0fe9..674ccf5c30ea 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf
@@ -374,6 +374,14 @@
The number of elements in this collection should be a multiple of {{ compared_value }}.
+
+
+ This value should satisfy at least one of the following constraints:
+
+
+
+ Each element of this collection should satisfy its own set of constraints.
+