From 636c755523e214ea043dcc2bc76310467a96ff99 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Mon, 30 Jan 2023 16:43:40 +0000 Subject: [PATCH 1/2] Fixes and tests unsigned closures --- src/SerializableClosure.php | 11 ++++++ src/Serializers/Native.php | 5 +-- tests/Datasets/Serializers.php | 11 ++++-- tests/Pest.php | 4 +++ tests/Php73Test.php | 8 ++++- tests/SerializerTest.php | 66 +++++++++++++++++++++++++++------- 6 files changed, 87 insertions(+), 18 deletions(-) diff --git a/src/SerializableClosure.php b/src/SerializableClosure.php index e7f9f0cf..51b7a8c7 100644 --- a/src/SerializableClosure.php +++ b/src/SerializableClosure.php @@ -62,6 +62,17 @@ public function getClosure() return $this->serializable->getClosure(); } + /** + * Creates a new unsigned serializable closure instance. + * + * @param Closure $closure + * @return \Laravel\SerializableClosure\UnsignedSerializableClosure + */ + public static function unsigned(Closure $closure) + { + return new UnsignedSerializableClosure($closure); + } + /** * Sets the serializable closure secret key. * diff --git a/src/Serializers/Native.php b/src/Serializers/Native.php index 0ff8410c..4a04b981 100644 --- a/src/Serializers/Native.php +++ b/src/Serializers/Native.php @@ -10,6 +10,7 @@ use Laravel\SerializableClosure\Support\ClosureStream; use Laravel\SerializableClosure\Support\ReflectionClosure; use Laravel\SerializableClosure\Support\SelfReference; +use Laravel\SerializableClosure\UnsignedSerializableClosure; use ReflectionObject; use UnitEnum; @@ -379,7 +380,7 @@ protected function mapPointers(&$data) $item = $property->getValue($data); - if ($item instanceof SerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) { + if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) { $this->code['objects'][] = [ 'instance' => $data, 'property' => $property, @@ -452,7 +453,7 @@ protected function mapByReference(&$data) } unset($value); - } elseif (is_object($data) && ! $data instanceof SerializableClosure) { + } elseif (is_object($data) && ! $data instanceof SerializableClosure && ! $data instanceof UnsignedSerializableClosure) { if (isset($this->scope[$data])) { $data = $this->scope[$data]; diff --git a/tests/Datasets/Serializers.php b/tests/Datasets/Serializers.php index ba581365..9f52da5b 100644 --- a/tests/Datasets/Serializers.php +++ b/tests/Datasets/Serializers.php @@ -1,10 +1,17 @@ getShortName() => function () use ($serializer) { + foreach ([Serializers\Native::class, Serializers\Signed::class, UnsignedSerializableClosure::class] as $serializer) { + $serializerShortName = (new ReflectionClass($serializer))->getShortName(); + + if ($serializer != UnsignedSerializableClosure::class) { + $serializerShortName = 'SerializableClosure > '.$serializerShortName; + } + + yield $serializerShortName => function () use ($serializer) { $this->serializer = $serializer; }; } diff --git a/tests/Pest.php b/tests/Pest.php index 5e98cacf..d83884b8 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -3,6 +3,7 @@ use Laravel\SerializableClosure\SerializableClosure; use Laravel\SerializableClosure\Serializers; use Laravel\SerializableClosure\Support\ReflectionClosure; +use Laravel\SerializableClosure\UnsignedSerializableClosure; /* |-------------------------------------------------------------------------- @@ -69,6 +70,9 @@ function s($closure) SerializableClosure::setSecretKey('secret'); $closure = new SerializableClosure($closure); break; + case UnsignedSerializableClosure::class: + $closure = SerializableClosure::unsigned($closure); + break; default: throw new Exception('Please use the [serializers] dataset.'); } diff --git a/tests/Php73Test.php b/tests/Php73Test.php index cf246aab..19ef09f8 100644 --- a/tests/Php73Test.php +++ b/tests/Php73Test.php @@ -3,8 +3,14 @@ use Laravel\SerializableClosure\Exceptions\PhpVersionNotSupportedException; use Laravel\SerializableClosure\SerializableClosure; -it('does not support PHP 7.3', function () { +test('serializable closure does not support PHP 7.3', function () { new SerializableClosure(function () { return 'foo'; }); })->throws(PhpVersionNotSupportedException::class); + +test('unsigned serializable closure does not support PHP 7.3', function () { + SerializableClosure::unsigned(function () { + return 'foo'; + }); +})->throws(PhpVersionNotSupportedException::class); diff --git a/tests/SerializerTest.php b/tests/SerializerTest.php index 75287396..56ec800a 100644 --- a/tests/SerializerTest.php +++ b/tests/SerializerTest.php @@ -5,6 +5,7 @@ use Laravel\SerializableClosure\SerializableClosure; use Laravel\SerializableClosure\Serializers\Signed; use Laravel\SerializableClosure\Support\ReflectionClosure; +use Laravel\SerializableClosure\UnsignedSerializableClosure; use Tests\Fixtures\Model; test('closure use return value', function () { @@ -37,12 +38,18 @@ return $data; }); - $c = unserialize(serialize(new SerializableClosure(function () use ($a) { - return $a; - }))); + if ($this->serializer == UnsignedSerializableClosure::class) { + $c = unserialize(serialize(SerializableClosure::unsigned(function () use ($a) { + return $a; + }))); + } else { + $c = unserialize(serialize(new SerializableClosure(function () use ($a) { + return $a; + }))); + } expect($c())->toEqual(50); -})->skip((float) phpversion() < '7.4'); +})->with('serializers')->skip((float) phpversion() < '7.4'); test('closure use transformation with Signed', function () { $a = 100; @@ -64,12 +71,18 @@ return $data; }); - $c = unserialize(serialize(new SerializableClosure(function () use ($a) { - return $a; - }))); + if ($this->serializer == UnsignedSerializableClosure::class) { + $c = unserialize(serialize(SerializableClosure::unsigned(function () use ($a) { + return $a; + }))); + } else { + $c = unserialize(serialize(new SerializableClosure(function () use ($a) { + return $a; + }))); + } expect($c())->toEqual(50); -})->skip((float) phpversion() < '7.4'); +})->with('serializers')->skip((float) phpversion() < '7.4'); test('closure use return closure', function () { $a = function ($p) { @@ -204,7 +217,6 @@ test('closure nested', function () { $o = function ($a) { - // this should never happen if ($a === false) { return false; @@ -330,7 +342,7 @@ function () { expect($r[1])->toEqual($b); })->with('serializers'); -test('serialization string content dont change', function () { +test('serializable closure serialization string content dont change', function () { $a = 100; SerializableClosure::setSecretKey('foo'); @@ -349,6 +361,25 @@ function () { ); }); +test('unsigned serializable closure serialization string content dont change', function () { + $a = 100; + + SerializableClosure::setSecretKey('foo'); + + $c = SerializableClosure::unsigned(function () use ($a) { + return $a; + }); + + $actual = explode('s:32:', serialize($c))[0]; + + expect($actual)->toBe(<<b = new SerializableClosure(function () { - return 'Hi'; - }); + if ($this->serializer == UnsignedSerializableClosure::class) { + $a->b = SerializableClosure::unsigned(function () { + return 'Hi'; + }); + } else { + $a->b = new SerializableClosure(function () { + return 'Hi'; + }); + } $closure = function () use ($a) { return ($a->b)(); @@ -459,8 +496,11 @@ public function aPublic() class A2 { private $phrase = 'Hello, World!'; + private $closure1; + private $closure2; + private $closure3; public function __construct() From 937e1351a2269f9a9dd5bc79a10375388dd9004e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 30 Jan 2023 12:31:08 -0600 Subject: [PATCH 2/2] Update SerializableClosure.php --- src/SerializableClosure.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializableClosure.php b/src/SerializableClosure.php index 51b7a8c7..86422f93 100644 --- a/src/SerializableClosure.php +++ b/src/SerializableClosure.php @@ -63,7 +63,7 @@ public function getClosure() } /** - * Creates a new unsigned serializable closure instance. + * Create a new unsigned serializable closure instance. * * @param Closure $closure * @return \Laravel\SerializableClosure\UnsignedSerializableClosure