diff --git a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php index 612350200e..c31dba8802 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ElasticsearchLogstashHandler.php @@ -129,6 +129,16 @@ class ElasticsearchLogstashHandler extends AbstractHandler $this->wait(false); } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->wait(true); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php index 7dbe15c6c9..a666dfc477 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php @@ -89,6 +89,12 @@ class AppKernel extends Kernel implements ExtensionInterface, ConfigurationInter public function __wakeup() { + foreach ($this as $k => $v) { + if (\is_object($v)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + } + $this->__construct($this->varDir, $this->testCase, $this->rootConfig, $this->environment, $this->debug); } diff --git a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php index 99413a6b62..baf95d524a 100644 --- a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php +++ b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php @@ -93,9 +93,20 @@ trait FilesystemCommonTrait set_error_handler(__CLASS__.'::throwError'); try { if (null === $this->tmp) { - $this->tmp = $this->directory.uniqid('', true); + $this->tmp = $this->directory.bin2hex(random_bytes(6)); } - file_put_contents($this->tmp, $data); + try { + $h = fopen($this->tmp, 'x'); + } catch (\ErrorException $e) { + if (false === strpos($e->getMessage(), 'File exists')) { + throw $e; + } + + $this->tmp = $this->directory.bin2hex(random_bytes(6)); + $h = fopen($this->tmp, 'x'); + } + fwrite($h, $data); + fclose($h); if (null !== $expiresAt) { touch($this->tmp, $expiresAt); diff --git a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php index 5a015cccaa..306fcd6130 100644 --- a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php +++ b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php @@ -227,6 +227,10 @@ class PrototypedArrayNode extends ArrayNode } elseif (isset($v[$this->keyAttribute])) { $k = $v[$this->keyAttribute]; + if (\is_float($k)) { + $k = var_export($k, true); + } + // remove the key attribute when required if ($this->removeKeyAttribute) { unset($v[$this->keyAttribute]); diff --git a/src/Symfony/Component/Config/Tests/Definition/NormalizationTest.php b/src/Symfony/Component/Config/Tests/Definition/NormalizationTest.php index cd32779373..c5fd94875b 100644 --- a/src/Symfony/Component/Config/Tests/Definition/NormalizationTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/NormalizationTest.php @@ -201,6 +201,32 @@ class NormalizationTest extends TestCase $this->assertNormalized($tree, $data, $data); } + public function testFloatLikeValueAsMapKeyAttribute() + { + $tree = (new TreeBuilder('root')) + ->getRootNode() + ->useAttributeAsKey('number') + ->arrayPrototype() + ->children() + ->scalarNode('foo')->end() + ->end() + ->end() + ->end() + ->buildTree() + ; + + $this->assertNormalized($tree, [ + [ + 'number' => 3.0, + 'foo' => 'bar', + ], + ], [ + '3.0' => [ + 'foo' => 'bar', + ], + ]); + } + public static function assertNormalized(NodeInterface $tree, $denormalized, $normalized) { self::assertSame($normalized, $tree->normalize($denormalized)); diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php index 85f0ac7347..d9e936fc49 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractConfigurator.php @@ -40,6 +40,16 @@ abstract class AbstractConfigurator throw new \BadMethodCallException(sprintf('Call to undefined method "%s::%s()".', static::class, $method)); } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + /** * Checks that a value is valid, optionally replacing Definition and Reference configurators by their configure value. * diff --git a/src/Symfony/Component/ErrorHandler/BufferingLogger.php b/src/Symfony/Component/ErrorHandler/BufferingLogger.php index 16e433dedf..72be64d127 100644 --- a/src/Symfony/Component/ErrorHandler/BufferingLogger.php +++ b/src/Symfony/Component/ErrorHandler/BufferingLogger.php @@ -35,6 +35,16 @@ class BufferingLogger extends AbstractLogger return $logs; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { foreach ($this->logs as [$level, $message, $context]) { diff --git a/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php b/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php index 323fdd2329..d1e03e8292 100644 --- a/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php +++ b/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php @@ -76,6 +76,16 @@ class OrderedHashMapIterator implements \Iterator $this->managedCursors[$this->cursorId] = &$this->cursor; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + /** * Removes the iterator's cursors from the managed cursors of the * corresponding {@link OrderedHashMap} instance. diff --git a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php index 7c36afa42a..25e0d1bf64 100644 --- a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php +++ b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php @@ -120,6 +120,16 @@ class ErrorChunk implements ChunkInterface return $this->didThrow; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { if (!$this->didThrow) { diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 014534bba9..f5fc0e70e6 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -367,6 +367,16 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, } } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->reset(); diff --git a/src/Symfony/Component/HttpClient/HttplugClient.php b/src/Symfony/Component/HttpClient/HttplugClient.php index 4f1e79143f..76c52fb169 100644 --- a/src/Symfony/Component/HttpClient/HttplugClient.php +++ b/src/Symfony/Component/HttpClient/HttplugClient.php @@ -218,6 +218,16 @@ final class HttplugClient implements HttplugInterface, HttpAsyncClient, RequestF throw new \LogicException(sprintf('You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".', __METHOD__)); } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->wait(); diff --git a/src/Symfony/Component/HttpClient/Response/AmpResponse.php b/src/Symfony/Component/HttpClient/Response/AmpResponse.php index b813ad774a..1c81d0b46e 100644 --- a/src/Symfony/Component/HttpClient/Response/AmpResponse.php +++ b/src/Symfony/Component/HttpClient/Response/AmpResponse.php @@ -142,6 +142,16 @@ final class AmpResponse implements ResponseInterface, StreamableInterface return null !== $type ? $this->info[$type] ?? null : $this->info; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { try { diff --git a/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php b/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php index 8ad619adce..69c0fa94e3 100644 --- a/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php @@ -127,6 +127,16 @@ trait CommonResponseTrait return $stream; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + /** * Closes the response and all its network handles. */ diff --git a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php index 7e58e06b30..d98b5c905a 100644 --- a/src/Symfony/Component/HttpClient/Response/TraceableResponse.php +++ b/src/Symfony/Component/HttpClient/Response/TraceableResponse.php @@ -44,6 +44,16 @@ class TraceableResponse implements ResponseInterface, StreamableInterface $this->event = $event; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { try { diff --git a/src/Symfony/Component/HttpClient/Tests/Retry/GenericRetryStrategyTest.php b/src/Symfony/Component/HttpClient/Tests/Retry/GenericRetryStrategyTest.php index e04cdb45b6..98b6578f0b 100644 --- a/src/Symfony/Component/HttpClient/Tests/Retry/GenericRetryStrategyTest.php +++ b/src/Symfony/Component/HttpClient/Tests/Retry/GenericRetryStrategyTest.php @@ -93,19 +93,16 @@ class GenericRetryStrategyTest extends TestCase public function testJitter() { $strategy = new GenericRetryStrategy([], 1000, 1, 0, 1); - $belowHalf = 0; - $aboveHalf = 0; - for ($i = 0; $i < 20; ++$i) { + $min = 2000; + $max = 0; + for ($i = 0; $i < 50; ++$i) { $delay = $strategy->getDelay($this->getContext(0, 'GET', 'http://example.com/', 200), null, null); - if ($delay < 500) { - ++$belowHalf; - } elseif ($delay > 1500) { - ++$aboveHalf; - } + $min = min($min, $delay); + $max = max($max, $delay); } - - $this->assertGreaterThanOrEqual(1, $belowHalf); - $this->assertGreaterThanOrEqual(1, $aboveHalf); + $this->assertGreaterThanOrEqual(1000, $max - $min); + $this->assertGreaterThanOrEqual(1000, $max); + $this->assertLessThanOrEqual(1000, $min); } private function getContext($retryCount, $method, $url, $statusCode): AsyncContext diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php index 19280a786a..0fb3291589 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php @@ -179,7 +179,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $fileLinkFormat = array_pop($this->data); $this->dataCount = \count($this->data); - self::__construct($this->stopwatch, $fileLinkFormat, $charset); + self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null); } public function getDumpsCount(): int diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c4fa66ee8d..2ee526394c 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -865,6 +865,10 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl public function __wakeup() { + if (\is_object($this->environment) || \is_object($this->debug)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + $this->__construct($this->environment, $this->debug); } } diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php index feaf22319f..83ac153667 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php @@ -35,6 +35,16 @@ class Connection extends AbstractConnection /** @var resource */ private $connection; + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->disconnect(); diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php index 6d97d7843c..7b1b8de7e1 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php @@ -38,6 +38,16 @@ class Query extends AbstractQuery parent::__construct($connection, $dn, $query, $options); } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $con = $this->connection->getResource(); diff --git a/src/Symfony/Component/Lock/Lock.php b/src/Symfony/Component/Lock/Lock.php index 69f1991120..c63e5224cb 100644 --- a/src/Symfony/Component/Lock/Lock.php +++ b/src/Symfony/Component/Lock/Lock.php @@ -49,6 +49,16 @@ final class Lock implements SharedLockInterface, LoggerAwareInterface $this->logger = new NullLogger(); } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + /** * Automatically releases the underlying lock when the object is destructed. */ diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesHttpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesHttpTransportTest.php index e1f28be824..cce8a4792c 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesHttpTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesHttpTransportTest.php @@ -63,6 +63,12 @@ class SesHttpTransportTest extends TestCase $this->assertStringContainsString('AWS3-HTTPS AWSAccessKeyId=ACCESS_KEY,Algorithm=HmacSHA256,Signature=', $options['headers'][0] ?? $options['request_headers'][0]); parse_str($options['body'], $body); + + $this->assertArrayHasKey('Destinations_member_1', $body); + $this->assertSame('saif.gmati@symfony.com', $body['Destinations_member_1']); + $this->assertArrayHasKey('Destinations_member_2', $body); + $this->assertSame('jeremy@derusse.com', $body['Destinations_member_2']); + $content = base64_decode($body['RawMessage_Data']); $this->assertStringContainsString('Hello!', $content); @@ -88,6 +94,7 @@ class SesHttpTransportTest extends TestCase $mail = new Email(); $mail->subject('Hello!') ->to(new Address('saif.gmati@symfony.com', 'Saif Eddin')) + ->bcc(new Address('jeremy@derusse.com', 'Jérémy Derussé')) ->from(new Address('fabpot@symfony.com', 'Fabien')) ->text('Hello There!'); diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php index 36fc5f8583..8e9e9de5f7 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php @@ -66,8 +66,14 @@ class SesHttpTransport extends AbstractHttpTransport ], ]; - if (($message->getOriginalMessage() instanceof Message) - && $configurationSetHeader = $message->getOriginalMessage()->getHeaders()->get('X-SES-CONFIGURATION-SET')) { + $index = 1; + foreach ($message->getEnvelope()->getRecipients() as $recipient) { + $request['body']['Destinations.member.'.$index++] = $recipient->getAddress(); + } + + if ($message->getOriginalMessage() instanceof Message + && $configurationSetHeader = $message->getOriginalMessage()->getHeaders()->get('X-SES-CONFIGURATION-SET') + ) { $request['body']['ConfigurationSetName'] = $configurationSetHeader->getBodyAsString(); } diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php index 9e5ead35a3..9456fd09bd 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -340,6 +340,16 @@ class SmtpTransport extends AbstractTransport $this->restartCounter = 0; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->stop(); diff --git a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/Connection.php index 7ccd5889e8..3e8112d405 100644 --- a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/Connection.php @@ -66,6 +66,16 @@ class Connection $this->queueUrl = $queueUrl; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->reset(); diff --git a/src/Symfony/Component/Mime/Part/DataPart.php b/src/Symfony/Component/Mime/Part/DataPart.php index 213f3c10c8..0da9230c29 100644 --- a/src/Symfony/Component/Mime/Part/DataPart.php +++ b/src/Symfony/Component/Mime/Part/DataPart.php @@ -155,7 +155,13 @@ class DataPart extends TextPart $r->setValue($this, $this->_headers); unset($this->_headers); + if (!\is_array($this->_parent)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + if (null !== $this->_parent[$name] && !\is_string($this->_parent[$name])) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } $r = new \ReflectionProperty(TextPart::class, $name); $r->setAccessible(true); $r->setValue($this, $this->_parent[$name]); diff --git a/src/Symfony/Component/Process/Pipes/UnixPipes.php b/src/Symfony/Component/Process/Pipes/UnixPipes.php index 70fdd29574..7cb5bab76e 100644 --- a/src/Symfony/Component/Process/Pipes/UnixPipes.php +++ b/src/Symfony/Component/Process/Pipes/UnixPipes.php @@ -35,6 +35,16 @@ class UnixPipes extends AbstractPipes parent::__construct($input); } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->close(); diff --git a/src/Symfony/Component/Process/Pipes/WindowsPipes.php b/src/Symfony/Component/Process/Pipes/WindowsPipes.php index b22171dd4a..b2c3f4f4f3 100644 --- a/src/Symfony/Component/Process/Pipes/WindowsPipes.php +++ b/src/Symfony/Component/Process/Pipes/WindowsPipes.php @@ -88,6 +88,16 @@ class WindowsPipes extends AbstractPipes parent::__construct($input); } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->close(); diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index f0c51e3d42..60022bfd27 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -195,6 +195,16 @@ class Process implements \IteratorAggregate return $process; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { if ($this->options['create_new_console'] ?? false) { diff --git a/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php b/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php index 227ab85037..ec61b82873 100644 --- a/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php +++ b/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php @@ -104,6 +104,10 @@ final class TokenBucket implements LimiterStateInterface */ public function __wakeup(): void { + if (!\is_string($this->stringRate)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + $this->rate = Rate::fromString($this->stringRate); unset($this->stringRate); } diff --git a/src/Symfony/Component/Routing/Loader/Configurator/CollectionConfigurator.php b/src/Symfony/Component/Routing/Loader/Configurator/CollectionConfigurator.php index 1d93ca5f6f..2bfbcad1c0 100644 --- a/src/Symfony/Component/Routing/Loader/Configurator/CollectionConfigurator.php +++ b/src/Symfony/Component/Routing/Loader/Configurator/CollectionConfigurator.php @@ -38,6 +38,16 @@ class CollectionConfigurator $this->parentPrefixes = $parentPrefixes; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { if (null === $this->prefixes) { diff --git a/src/Symfony/Component/Routing/Loader/Configurator/ImportConfigurator.php b/src/Symfony/Component/Routing/Loader/Configurator/ImportConfigurator.php index 1841253694..7642555f5e 100644 --- a/src/Symfony/Component/Routing/Loader/Configurator/ImportConfigurator.php +++ b/src/Symfony/Component/Routing/Loader/Configurator/ImportConfigurator.php @@ -30,6 +30,16 @@ class ImportConfigurator $this->route = $route; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->parent->addCollection($this->route); diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php index 09b218c029..0b48a5b245 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php @@ -185,18 +185,6 @@ class AuthenticatorManager implements AuthenticatorManagerInterface, UserAuthent if (null !== $this->logger) { $this->logger->info('Authenticator successful!', ['token' => $authenticatedToken, 'authenticator' => \get_class($authenticator)]); } - - // success! (sets the token on the token storage, etc) - $response = $this->handleAuthenticationSuccess($authenticatedToken, $passport, $request, $authenticator); - if ($response instanceof Response) { - return $response; - } - - if (null !== $this->logger) { - $this->logger->debug('Authenticator set no success response: request continues.', ['authenticator' => \get_class($authenticator)]); - } - - return null; } catch (AuthenticationException $e) { // oh no! Authentication failed! $response = $this->handleAuthenticationFailure($e, $request, $authenticator, $passport); @@ -206,6 +194,18 @@ class AuthenticatorManager implements AuthenticatorManagerInterface, UserAuthent return null; } + + // success! (sets the token on the token storage, etc) + $response = $this->handleAuthenticationSuccess($authenticatedToken, $passport, $request, $authenticator); + if ($response instanceof Response) { + return $response; + } + + if (null !== $this->logger) { + $this->logger->debug('Authenticator set no success response: request continues.', ['authenticator' => \get_class($authenticator)]); + } + + return null; } private function handleAuthenticationSuccess(TokenInterface $authenticatedToken, PassportInterface $passport, Request $request, AuthenticatorInterface $authenticator): ?Response diff --git a/src/Symfony/Component/Security/Http/EventListener/UserCheckerListener.php b/src/Symfony/Component/Security/Http/EventListener/UserCheckerListener.php index 829ac2ff7f..f53cdecaea 100644 --- a/src/Symfony/Component/Security/Http/EventListener/UserCheckerListener.php +++ b/src/Symfony/Component/Security/Http/EventListener/UserCheckerListener.php @@ -12,11 +12,12 @@ namespace Symfony\Component\Security\Http\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent; use Symfony\Component\Security\Core\User\UserCheckerInterface; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PreAuthenticatedUserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\UserPassportInterface; use Symfony\Component\Security\Http\Event\CheckPassportEvent; -use Symfony\Component\Security\Http\Event\LoginSuccessEvent; /** * @author Wouter de Jong @@ -43,21 +44,21 @@ class UserCheckerListener implements EventSubscriberInterface $this->userChecker->checkPreAuth($passport->getUser()); } - public function postCheckCredentials(LoginSuccessEvent $event): void + public function postCheckCredentials(AuthenticationSuccessEvent $event): void { - $passport = $event->getPassport(); - if (!$passport instanceof UserPassportInterface || null === $passport->getUser()) { + $user = $event->getAuthenticationToken()->getUser(); + if (!$user instanceof UserInterface) { return; } - $this->userChecker->checkPostAuth($passport->getUser()); + $this->userChecker->checkPostAuth($user); } public static function getSubscribedEvents(): array { return [ CheckPassportEvent::class => ['preCheckCredentials', 256], - LoginSuccessEvent::class => ['postCheckCredentials', 256], + AuthenticationSuccessEvent::class => ['postCheckCredentials', 256], ]; } } diff --git a/src/Symfony/Component/Security/Http/Tests/EventListener/UserCheckerListenerTest.php b/src/Symfony/Component/Security/Http/Tests/EventListener/UserCheckerListenerTest.php index 5422abfe5d..213cfbba68 100644 --- a/src/Symfony/Component/Security/Http/Tests/EventListener/UserCheckerListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/EventListener/UserCheckerListenerTest.php @@ -12,8 +12,8 @@ namespace Symfony\Component\Security\Http\Tests\EventListener; use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; +use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent; use Symfony\Component\Security\Core\User\User; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; @@ -21,8 +21,8 @@ use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PreAuthenticate use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; +use Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken; use Symfony\Component\Security\Http\Event\CheckPassportEvent; -use Symfony\Component\Security\Http\Event\LoginSuccessEvent; use Symfony\Component\Security\Http\EventListener\UserCheckerListener; class UserCheckerListenerTest extends TestCase @@ -63,14 +63,14 @@ class UserCheckerListenerTest extends TestCase { $this->userChecker->expects($this->once())->method('checkPostAuth')->with($this->user); - $this->listener->postCheckCredentials($this->createLoginSuccessEvent()); + $this->listener->postCheckCredentials(new AuthenticationSuccessEvent(new PostAuthenticationToken($this->user, 'main', []))); } public function testPostAuthNoUser() { $this->userChecker->expects($this->never())->method('checkPostAuth'); - $this->listener->postCheckCredentials($this->createLoginSuccessEvent($this->createMock(PassportInterface::class))); + $this->listener->postCheckCredentials(new AuthenticationSuccessEvent(new PreAuthenticatedToken('nobody', null, 'main'))); } private function createCheckPassportEvent($passport = null) @@ -82,12 +82,8 @@ class UserCheckerListenerTest extends TestCase return new CheckPassportEvent($this->createMock(AuthenticatorInterface::class), $passport); } - private function createLoginSuccessEvent($passport = null) + private function createAuthenticationSuccessEvent() { - if (null === $passport) { - $passport = new SelfValidatingPassport(new UserBadge('test', function () { return $this->user; })); - } - - return new LoginSuccessEvent($this->createMock(AuthenticatorInterface::class), $passport, $this->createMock(TokenInterface::class), new Request(), null, 'main'); + return new AuthenticationSuccessEvent(new PostAuthenticationToken($this->user, 'main', [])); } } diff --git a/src/Symfony/Component/String/UnicodeString.php b/src/Symfony/Component/String/UnicodeString.php index 2db507d7bb..9b906c6fc2 100644 --- a/src/Symfony/Component/String/UnicodeString.php +++ b/src/Symfony/Component/String/UnicodeString.php @@ -359,6 +359,10 @@ class UnicodeString extends AbstractUnicodeString public function __wakeup() { + if (!\is_string($this->string)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string); } diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 9898c177ac..8a76b4880b 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -203,7 +203,7 @@ class Parser array_pop($this->refsBeingParsed); } } elseif ( - self::preg_match('#^(?P(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(\s++(?P.+))?$#u', rtrim($this->currentLine), $values) + self::preg_match('#^(?P(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:( ++(?P.+))?$#u', rtrim($this->currentLine), $values) && (false === strpos($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"])) ) { if ($context && 'sequence' == $context) { diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index acbde08ae1..e680d9d166 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -915,4 +915,21 @@ class InlineTest extends TestCase [['!'], '! ["!"]'], ]; } + + /** + * @dataProvider ideographicSpaceProvider + */ + public function testParseIdeographicSpace(string $yaml, string $expected) + { + $this->assertSame($expected, Inline::parse($yaml)); + } + + public function ideographicSpaceProvider(): array + { + return [ + ["\u{3000}", ' '], + ["'\u{3000}'", ' '], + ["'a b'", 'a b'], + ]; + } } diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 963bbfabd6..3822ce7d0c 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -2732,6 +2732,22 @@ YAML; // (before, there was no \n after row2) $this->assertSame(['a' => ['b' => "row\nrow2\n"], 'c' => 'd'], $this->parser->parse($longDocument)); } + + public function testParseIdeographicSpaces() + { + $expected = <<assertSame([ + 'unquoted' => ' ', + 'quoted' => ' ', + 'within_string' => 'a b', + 'regular_space' => 'a b', + ], $this->parser->parse($expected)); + } } class B diff --git a/src/Symfony/Contracts/README.md b/src/Symfony/Contracts/README.md index 480c2a90e7..5beb497d7e 100644 --- a/src/Symfony/Contracts/README.md +++ b/src/Symfony/Contracts/README.md @@ -11,7 +11,7 @@ Design Principles * contracts are split by domain, each into their own sub-namespaces; * contracts are small and consistent sets of PHP interfaces, traits, normative - docblocks and reference test suites when applicable, ...; + docblocks and reference test suites when applicable; * all contracts must have a proven implementation to enter this repository; * they must be backward compatible with existing Symfony components.