Skip to content

Commit

Permalink
Merge pull request #64 from laravel/fix/unsigned-serializable-closures
Browse files Browse the repository at this point in the history
[1.x] Fixes and tests unsigned closures
  • Loading branch information
taylorotwell authored Jan 30, 2023
2 parents 1d62a02 + 937e135 commit f23fe9d
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 18 deletions.
11 changes: 11 additions & 0 deletions src/SerializableClosure.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ public function getClosure()
return $this->serializable->getClosure();
}

/**
* Create 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.
*
Expand Down
5 changes: 3 additions & 2 deletions src/Serializers/Native.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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];

Expand Down
11 changes: 9 additions & 2 deletions tests/Datasets/Serializers.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
<?php

use Laravel\SerializableClosure\Serializers;
use Laravel\SerializableClosure\UnsignedSerializableClosure;

dataset('serializers', function () {
foreach ([Serializers\Native::class, Serializers\Signed::class] as $serializer) {
yield (new ReflectionClass($serializer))->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;
};
}
Expand Down
4 changes: 4 additions & 0 deletions tests/Pest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Laravel\SerializableClosure\SerializableClosure;
use Laravel\SerializableClosure\Serializers;
use Laravel\SerializableClosure\Support\ReflectionClosure;
use Laravel\SerializableClosure\UnsignedSerializableClosure;

/*
|--------------------------------------------------------------------------
Expand Down Expand Up @@ -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.');
}
Expand Down
8 changes: 7 additions & 1 deletion tests/Php73Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
66 changes: 53 additions & 13 deletions tests/SerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -204,7 +217,6 @@

test('closure nested', function () {
$o = function ($a) {

// this should never happen
if ($a === false) {
return false;
Expand Down Expand Up @@ -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');
Expand All @@ -349,16 +361,41 @@ 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(<<<OEF
O:55:"Laravel\SerializableClosure\UnsignedSerializableClosure":1:{s:12:"serializable";O:46:"Laravel\SerializableClosure\Serializers\Native":5:{s:3:"use";a:1:{s:1:"a";i:100;}s:8:"function";s:47:"function () use (\$a) {
return \$a;
}";s:5:"scope";s:22:"P\Tests\SerializerTest";s:4:"this";N;s:4:"self";
OEF
);
});

test('use objects with serializable closures properties', function () {
$a = new stdClass();

if ($this->serializer == Signed::class) {
SerializableClosure::setSecretKey('secret');
}

$a->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)();
Expand Down Expand Up @@ -459,8 +496,11 @@ public function aPublic()
class A2
{
private $phrase = 'Hello, World!';

private $closure1;

private $closure2;

private $closure3;

public function __construct()
Expand Down

0 comments on commit f23fe9d

Please sign in to comment.