Fix collection deserialization errors

This commit is contained in:
Ben Ramsey
2020-03-29 15:08:55 -05:00
parent 15f777bb36
commit ba8fff1d3a
6 changed files with 257 additions and 1 deletions
+11 -1
View File
@@ -21,6 +21,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Security
## [4.0.1] - 2020-03-29
### Fixed
* Fix collection deserialization errors due to upstream `allowed_classes` being
set to `false`. For details, see [ramsey/uuid#303](https://github.com/ramsey/uuid/issues/303)
and [ramsey/collection#47](https://github.com/ramsey/collection/issues/47).
## [4.0.0] - 2020-03-22
### Added
@@ -1173,7 +1182,8 @@ versions leading up to this release.*
[ramsey/uuid-doctrine]: https://github.com/ramsey/uuid-doctrine
[ramsey/uuid-console]: https://github.com/ramsey/uuid-console
[unreleased]: https://github.com/ramsey/uuid/compare/4.0.0...HEAD
[unreleased]: https://github.com/ramsey/uuid/compare/4.0.1...HEAD
[4.0.1]: https://github.com/ramsey/uuid/compare/4.0.0...4.0.1
[4.0.0]: https://github.com/ramsey/uuid/compare/4.0.0-beta2...4.0.0
[4.0.0-beta2]: https://github.com/ramsey/uuid/compare/4.0.0-beta1...4.0.0-beta2
[4.0.0-beta1]: https://github.com/ramsey/uuid/compare/4.0.0-alpha5...4.0.0-beta1
+33
View File
@@ -16,6 +16,13 @@ namespace Ramsey\Uuid\Builder;
use Ramsey\Collection\AbstractCollection;
use Ramsey\Collection\CollectionInterface;
use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
use Traversable;
/**
@@ -37,4 +44,30 @@ class BuilderCollection extends AbstractCollection implements CollectionInterfac
{
return parent::getIterator();
}
/**
* Re-constructs the object from its serialized form
*
* @param string $serialized The serialized PHP string to unserialize into
* a UuidInterface instance
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
*/
public function unserialize($serialized): void
{
/** @var mixed[] $data */
$data = unserialize($serialized, [
'allowed_classes' => [
BrickMathCalculator::class,
GenericNumberConverter::class,
GenericTimeConverter::class,
GuidBuilder::class,
NonstandardUuidBuilder::class,
PhpTimeConverter::class,
Rfc4122UuidBuilder::class,
],
]);
$this->data = $data;
}
}
@@ -17,6 +17,7 @@ namespace Ramsey\Uuid\Provider\Node;
use Ramsey\Collection\AbstractCollection;
use Ramsey\Collection\CollectionInterface;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
/**
* A collection of NodeProviderInterface objects
@@ -27,4 +28,27 @@ class NodeProviderCollection extends AbstractCollection implements CollectionInt
{
return NodeProviderInterface::class;
}
/**
* Re-constructs the object from its serialized form
*
* @param string $serialized The serialized PHP string to unserialize into
* a UuidInterface instance
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
*/
public function unserialize($serialized): void
{
/** @var mixed[] $data */
$data = unserialize($serialized, [
'allowed_classes' => [
Hexadecimal::class,
RandomNodeProvider::class,
StaticNodeProvider::class,
SystemNodeProvider::class,
],
]);
$this->data = $data;
}
}
+1
View File
@@ -291,6 +291,7 @@ class Uuid implements UuidInterface
$this->codec = $uuid->codec;
$this->numberConverter = $uuid->numberConverter;
$this->fields = $uuid->fields;
$this->timeConverter = $uuid->timeConverter;
}
public function compareTo(UuidInterface $other): int
+158
View File
@@ -4,14 +4,28 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Test\Builder;
use DateTimeInterface;
use Mockery;
use Ramsey\Uuid\Builder\BuilderCollection;
use Ramsey\Uuid\Builder\FallbackBuilder;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Codec\StringCodec;
use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
use Ramsey\Uuid\Exception\BuilderNotFoundException;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
use Ramsey\Uuid\Nonstandard\UuidV6;
use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
use Ramsey\Uuid\Rfc4122\UuidV1;
use Ramsey\Uuid\Rfc4122\UuidV2;
use Ramsey\Uuid\Test\TestCase;
use Ramsey\Uuid\UuidInterface;
use Ramsey\Uuid\Validator\GenericValidator;
class FallbackBuilderTest extends TestCase
{
@@ -50,4 +64,148 @@ class FallbackBuilderTest extends TestCase
$fallbackBuilder->build($codec, $bytes);
}
/**
* @dataProvider provideBytes
*/
public function testSerializationOfBuilderCollection(string $bytes): void
{
$validator = new GenericValidator();
$calculator = new BrickMathCalculator();
$genericNumberConverter = new GenericNumberConverter($calculator);
$genericTimeConverter = new GenericTimeConverter($calculator);
$phpTimeConverter = new PhpTimeConverter($calculator, $genericTimeConverter);
// Use the GenericTimeConverter.
$guidBuilder = new GuidBuilder($genericNumberConverter, $genericTimeConverter);
$rfc4122Builder = new Rfc4122UuidBuilder($genericNumberConverter, $genericTimeConverter);
$nonstandardBuilder = new NonstandardUuidBuilder($genericNumberConverter, $genericTimeConverter);
// Use the PhpTimeConverter.
$guidBuilder2 = new GuidBuilder($genericNumberConverter, $phpTimeConverter);
$rfc4122Builder2 = new Rfc4122UuidBuilder($genericNumberConverter, $phpTimeConverter);
$nonstandardBuilder2 = new NonstandardUuidBuilder($genericNumberConverter, $phpTimeConverter);
$builderCollection = new BuilderCollection(
[
$guidBuilder,
$guidBuilder2,
$rfc4122Builder,
$rfc4122Builder2,
$nonstandardBuilder,
$nonstandardBuilder2,
]
);
$serializedBuilderCollection = serialize($builderCollection);
/** @var BuilderCollection $unserializedBuilderCollection */
$unserializedBuilderCollection = unserialize($serializedBuilderCollection);
$this->assertInstanceOf(BuilderCollection::class, $unserializedBuilderCollection);
/** @var UuidBuilderInterface $builder */
foreach ($unserializedBuilderCollection as $builder) {
$codec = new StringCodec($builder);
$this->assertInstanceOf(UuidBuilderInterface::class, $builder);
try {
$uuid = $builder->build($codec, $bytes);
$this->assertInstanceOf(UuidInterface::class, $uuid);
if (($uuid instanceof UuidV1) || ($uuid instanceof UuidV2) || ($uuid instanceof UuidV6)) {
$this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime());
}
} catch (UnableToBuildUuidException $exception) {
switch ($exception->getMessage()) {
case 'The byte string received does not contain a valid version':
case 'The byte string received does not conform to the RFC 4122 variant':
case 'The byte string received does not conform to the RFC 4122 or Microsoft Corporation variants':
// This is expected; ignoring.
break;
default:
throw $exception;
}
}
}
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification
*/
public function provideBytes(): array
{
return [
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1110b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1111b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1112b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1113b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1114b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1115b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1116b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1117b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e111eb210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e111fb210800200c9a66'),
],
[
// Version 1 bytes
'bytes' => hex2bin('ff6f8cb0c57d11e19b210800200c9a66'),
],
[
// Version 2 bytes
'bytes' => hex2bin('000001f55cde21ea84000242ac130003'),
],
[
// Version 3 bytes
'bytes' => hex2bin('ff6f8cb0c57d31e1bb210800200c9a66'),
],
[
// Version 4 bytes
'bytes' => hex2bin('ff6f8cb0c57d41e1ab210800200c9a66'),
],
[
// Version 5 bytes
'bytes' => hex2bin('ff6f8cb0c57d51e18b210800200c9a66'),
],
[
// Version 6 bytes
'bytes' => hex2bin('ff6f8cb0c57d61e18b210800200c9a66'),
],
[
// NIL bytes
'bytes' => hex2bin('00000000000000000000000000000000'),
],
];
}
}
@@ -7,6 +7,9 @@ namespace Ramsey\Uuid\Test\Provider\Node;
use Ramsey\Uuid\Exception\NodeException;
use Ramsey\Uuid\Provider\Node\FallbackNodeProvider;
use Ramsey\Uuid\Provider\Node\NodeProviderCollection;
use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
use Ramsey\Uuid\Provider\Node\StaticNodeProvider;
use Ramsey\Uuid\Provider\Node\SystemNodeProvider;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Test\TestCase;
use Ramsey\Uuid\Type\Hexadecimal;
@@ -65,4 +68,31 @@ class FallbackNodeProviderTest extends TestCase
$provider->getNode();
}
public function testSerializationOfNodeProviderCollection(): void
{
$staticNodeProvider = new StaticNodeProvider(new Hexadecimal('aabbccddeeff'));
$randomNodeProvider = new RandomNodeProvider();
$systemNodeProvider = new SystemNodeProvider();
$nodeProviderCollection = new NodeProviderCollection(
[
$staticNodeProvider,
$randomNodeProvider,
$systemNodeProvider,
]
);
$serializedNodeProviderCollection = serialize($nodeProviderCollection);
/** @var NodeProviderCollection $unserializedNodeProviderCollection */
$unserializedNodeProviderCollection = unserialize($serializedNodeProviderCollection);
$this->assertInstanceOf(NodeProviderCollection::class, $unserializedNodeProviderCollection);
foreach ($unserializedNodeProviderCollection as $nodeProvider) {
$this->assertInstanceOf(NodeProviderInterface::class, $nodeProvider);
$this->assertInstanceOf(Hexadecimal::class, $nodeProvider->getNode());
}
}
}