Skip to content

Support PHP 8.1 #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

strategy:
matrix:
php: ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0']
php: ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1']

steps:
- name: Checkout Code
Expand All @@ -35,18 +35,18 @@ jobs:
timeout_minutes: 5
max_attempts: 5
command: composer update --no-interaction --no-progress
if: "matrix.php != '8.0'"
if: "matrix.php < 8"

- name: Install PHP 8 Dependencies
uses: nick-invision/retry@v1
with:
timeout_minutes: 5
max_attempts: 5
command: |
composer require "phpunit/phpunit:^9.3" --no-update
composer update --no-interaction --no-progress --ignore-platform-req=php
php -v
if: "matrix.php == '8.0'"
composer config platform.php 7.4.999
composer require "phpunit/phpunit:^9.5.9" --no-update
composer update --no-interaction --no-progress
if: "matrix.php >= 8"

- name: Execute PHPUnit
run: vendor/bin/phpunit
136 changes: 79 additions & 57 deletions src/SerializableClosure.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,10 @@ public function __invoke()
}

/**
* Implementation of Serializable::serialize()
*
* @return string The serialized closure
* @return array
*/
public function serialize()
#[\ReturnTypeWillChange]
public function __serialize()
{
if ($this->scope === null) {
$this->scope = new ClosureScope();
Expand Down Expand Up @@ -147,7 +146,7 @@ public function serialize()

$this->mapByReference($use);

$ret = \serialize(array(
$closure = \serialize(array(
'use' => $use,
'function' => $code,
'scope' => $scope,
Expand All @@ -156,15 +155,32 @@ public function serialize()
));

if (static::$securityProvider !== null) {
$data = static::$securityProvider->sign($ret);
$ret = '@' . $data['hash'] . '.' . $data['closure'];
$data = static::$securityProvider->sign($closure);
} else {
$data = array('closure' => $closure);
}

if (!--$this->scope->serializations && !--$this->scope->toserialize) {
$this->scope = null;
}

return $ret;
return $data;
}

/**
* Implementation of Serializable::serialize()
*
* @return string The serialized closure
*/
public function serialize()
{
$data = $this->__serialize();

if (isset($data['hash'])) {
return sprintf('@%s.%s', $data['hash'], $data['closure']);
}

return $data['closure'];
}

/**
Expand All @@ -179,66 +195,24 @@ protected function transformUseVariables($data)
}

/**
* Implementation of Serializable::unserialize()
*
* @param string $data Serialized data
* @throws SecurityException
* @return void
*/
public function unserialize($data)
#[\ReturnTypeWillChange]
public function __unserialize(array $data)
{
ClosureStream::register();

if (static::$securityProvider !== null) {
if ($data[0] !== '@') {
throw new SecurityException("The serialized closure is not signed. ".
"Make sure you use a security provider for both serialization and unserialization.");
}

if ($data[1] !== '{') {
$separator = strpos($data, '.');
if ($separator === false) {
throw new SecurityException('Invalid signed closure');
}
$hash = substr($data, 1, $separator - 1);
$closure = substr($data, $separator + 1);

$data = ['hash' => $hash, 'closure' => $closure];

unset($hash, $closure);
} else {
$data = json_decode(substr($data, 1), true);
}

if (!is_array($data) || !static::$securityProvider->verify($data)) {
throw new SecurityException("Your serialized closure might have been modified and it's unsafe to be unserialized. " .
"Make sure you use the same security provider, with the same settings, " .
"both for serialization and unserialization.");
}

$data = $data['closure'];
} elseif ($data[0] === '@') {
if ($data[1] !== '{') {
$separator = strpos($data, '.');
if ($separator === false) {
throw new SecurityException('Invalid signed closure');
}
$hash = substr($data, 1, $separator - 1);
$closure = substr($data, $separator + 1);

$data = ['hash' => $hash, 'closure' => $closure];

unset($hash, $closure);
} else {
$data = json_decode(substr($data, 1), true);
}

if (!is_array($data) || !isset($data['closure']) || !isset($data['hash'])) {
throw new SecurityException('Invalid signed closure');
}

$data = $data['closure'];
}

$data = $data['closure'];

$this->code = \unserialize($data);

// unset data
Expand All @@ -256,13 +230,13 @@ public function unserialize($data)

$this->closure = include(ClosureStream::STREAM_PROTO . '://' . $this->code['function']);

if($this->code['this'] === $this){
if ($this->code['this'] === $this) {
$this->code['this'] = null;
}

$this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']);

if(!empty($this->code['objects'])){
if (!empty($this->code['objects'])) {
foreach ($this->code['objects'] as $item){
$item['property']->setValue($item['instance'], $item['object']->getClosure());
}
Expand All @@ -271,6 +245,54 @@ public function unserialize($data)
$this->code = $this->code['function'];
}

/**
* Implementation of Serializable::unserialize()
*
* @param string $data Serialized data
* @throws SecurityException
*/
public function unserialize($data)
{
if (static::$securityProvider !== null) {
if ($data[0] !== '@') {
throw new SecurityException("The serialized closure is not signed. ".
"Make sure you use a security provider for both serialization and unserialization.");
}

if ($data[1] !== '{') {
$separator = strpos($data, '.');
if ($separator === false) {
throw new SecurityException('Invalid signed closure');
}
$hash = substr($data, 1, $separator - 1);
$closure = substr($data, $separator + 1);

$this->__unserialize(['hash' => $hash, 'closure' => $closure]);
} else {
$this->__unserialize(json_decode(substr($data, 1), true));
}
} elseif ($data[0] === '@') {
if ($data[1] !== '{') {
$separator = strpos($data, '.');
if ($separator === false) {
throw new SecurityException('Invalid signed closure');
}
$hash = substr($data, 1, $separator - 1);
$closure = substr($data, $separator + 1);

$this->__unserialize(['hash' => $hash, 'closure' => $closure]);
} else {
$data = json_decode(substr($data, 1), true);
if (!is_array($data)) {
throw new SecurityException('Invalid signed closure');
}
$this->__unserialize($data);
}
} else {
$this->__unserialize(['closure' => $data]);
}
}

/**
* Resolve the use variables after unserialization.
*
Expand Down