updated-packages
This commit is contained in:
260
vendor/opis/closure/CHANGELOG.md
vendored
Normal file
260
vendor/opis/closure/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
CHANGELOG
|
||||
---------
|
||||
|
||||
### v3.6.2, 2021.04.09
|
||||
|
||||
- Fixed string interpolation
|
||||
|
||||
### v3.6.1, 2020.11.07
|
||||
|
||||
- Fixed serialization error [#84](https://github.com/opis/closure/issues/84)
|
||||
|
||||
### v3.6.0, 2020.10.12
|
||||
|
||||
- Initial PHP 8 Support [#67](https://github.com/opis/closure/issues/67).
|
||||
|
||||
### v3.5.7, 2020.09.06
|
||||
|
||||
- Fixed issue [#76](https://github.com/opis/closure/issues/76).
|
||||
- Fixed issue [#78](https://github.com/opis/closure/issues/78).
|
||||
|
||||
### v3.5.6, 2020.08.11
|
||||
|
||||
- Fixed issue [#70](https://github.com/opis/closure/issues/70)
|
||||
|
||||
### v3.5.5, 2020.06.17
|
||||
|
||||
- Fixed a false-positive when using `Opis\Closure\ReflectionClosure::isScopeRequired` method
|
||||
|
||||
### v3.5.4, 2020.06.07
|
||||
|
||||
- Fixed a false-positive when using `Opis\Closure\ReflectionClosure::isScopeRequired` method
|
||||
- Fixed a bug related to `T_STRING_VARNAME`
|
||||
|
||||
### v3.5.3, 2020.05.25
|
||||
|
||||
- Improved parser
|
||||
- The class scope optimisation is no longer used. We always bind now to the closure's original class scope.
|
||||
When the class scope was `null`, the optimisation failed to work as expected and kept the wrong `SerializableClosure` scope.
|
||||
|
||||
### v3.5.2, 2020.05.21
|
||||
|
||||
- Removed extra semicolon in short closures, since is not part of the closure's body.
|
||||
|
||||
### v3.5.1, 2019.11.30
|
||||
|
||||
- Bugfix. See #47
|
||||
|
||||
### v3.5.0, 2019.11.29
|
||||
|
||||
- Added support for short closures (arrow functions)
|
||||
- Added `isShortClosure` method to `Opis\Closure\ReflectionClosure`
|
||||
|
||||
### v3.4.2, 2019.11.29
|
||||
|
||||
- Added `stream_set_option()`
|
||||
|
||||
### v3.4.1, 2019.10.19
|
||||
|
||||
- Fixed a [bug](https://github.com/opis/closure/issues/40) that prevented serialization to work correctly.
|
||||
|
||||
### v3.4.0, 2019.09.03
|
||||
|
||||
- Added `createClosure` static method in `Opis\Closure\SerializableClosure`.
|
||||
This method creates a new closure from arbitrary code, emulating `create_function`,
|
||||
but without using eval
|
||||
|
||||
### v3.3.1, 2019.07.10
|
||||
|
||||
- Use `sha1` instead of `md5` for hashing file names in `Opis\Closure\ReflectionClosure` class
|
||||
|
||||
### v3.3.0, 2019.05.31
|
||||
|
||||
- Fixed a bug that prevented signed closures to properly work when the serialized string
|
||||
contains invalid UTF-8 chars. Starting with this version `json_encode` is no longer used
|
||||
when signing a closure. Backward compatibility is maintained and all closures that were
|
||||
previously signed using the old method will continue to work.
|
||||
|
||||
### v3.2.0, 2019.05.05
|
||||
|
||||
- Since an unsigned closure can be unserialized when no security provider is set,
|
||||
there is no reason to treat differently a signed closure in the same situation.
|
||||
Therefore, the `Opis\Closure\SecurityException` exception is no longer thrown when
|
||||
unserializing a signed closure, if no security provider is set.
|
||||
|
||||
### v3.1.6, 2019.02.22
|
||||
|
||||
- Fixed a bug that occurred when trying to set properties of classes that were not defined in user-land.
|
||||
Those properties are now ignored.
|
||||
|
||||
### v3.1.5, 2019.01.14
|
||||
|
||||
- Improved parser
|
||||
|
||||
### v3.1.4, 2019.01.14
|
||||
|
||||
- Added support for static methods that are named using PHP keywords or magic constants.
|
||||
Ex: `A::new()`, `A::use()`, `A::if()`, `A::function()`, `A::__DIR__()`, etc.
|
||||
- Used `@internal` to mark classes & methods that are for internal use only and
|
||||
backward compatibility is not guaranteed.
|
||||
|
||||
### v3.1.3, 2019.01.07
|
||||
|
||||
- Fixed a bug that prevented traits to be correctly resolved when used by an
|
||||
anonymous class
|
||||
- Fixed a bug that occurred when `$this` keyword was used inside an anonymous class
|
||||
|
||||
### v3.1.2, 2018.12.16
|
||||
|
||||
* Fixed a bug regarding comma trail in group-use statements. See [issue 23](https://github.com/opis/closure/issues/23)
|
||||
|
||||
### v3.1.1, 2018.10.02
|
||||
|
||||
* Fixed a bug where `parent` keyword was treated like a class-name and scope was not added to the
|
||||
serialized closure
|
||||
* Fixed a bug where return type was not properly handled for nested closures
|
||||
* Support for anonymous classes was improved
|
||||
|
||||
### v3.1.0, 2018.09.20
|
||||
|
||||
* Added `transformUseVariables` and `resolveUseVariables` to
|
||||
`Opis\Closure\SerializableClosure` class.
|
||||
* Added `removeSecurityProvider` static method to
|
||||
`Opis\Closure\SerializableClosure` class.
|
||||
* Fixed some security related issues where a user was able to unserialize an unsigned
|
||||
closure, even when a security provider was in use.
|
||||
|
||||
### v3.0.12, 2018.02.23
|
||||
|
||||
* Bugfix. See [issue 20](https://github.com/opis/closure/issues/20)
|
||||
|
||||
### v3.0.11, 2018.01.22
|
||||
|
||||
* Bugfix. See [issue 18](https://github.com/opis/closure/issues/18)
|
||||
|
||||
### v3.0.10, 2018.01.04
|
||||
|
||||
* Improved support for PHP 7.1 & 7.2
|
||||
|
||||
### v3.0.9, 2018.01.04
|
||||
|
||||
* Fixed a bug where the return type was not properly resolved.
|
||||
See [issue 17](https://github.com/opis/closure/issues/17)
|
||||
* Added more tests
|
||||
|
||||
### v3.0.8, 2017.12.18
|
||||
|
||||
* Fixed a bug. See [issue 16](https://github.com/opis/closure/issues/16)
|
||||
|
||||
### v3.0.7, 2017.10.31
|
||||
|
||||
* Bugfix: static properties are ignored now, since they are not serializable
|
||||
|
||||
### v3.0.6, 2017.10.06
|
||||
|
||||
* Fixed a bug introduced by accident in 3.0.5
|
||||
|
||||
### v3.0.5, 2017.09.18
|
||||
|
||||
* Fixed a bug related to nested references
|
||||
|
||||
### v3.0.4, 2017.09.18
|
||||
|
||||
* \[*internal*\] Refactored `SerializableClosure::mapPointers` method
|
||||
* \[*internal*\] Added a new optional argument to `SerializableClosure::unwrapClosures`
|
||||
* \[*internal*\] Removed `SerializableClosure::getClosurePointer` method
|
||||
* Fixed various bugs
|
||||
|
||||
### v3.0.3, 2017.09.06
|
||||
|
||||
* Fixed a bug related to nested object references
|
||||
* \[*internal*\] `Opis\Closure\ClosureScope` now extends `SplObjectStorage`
|
||||
* \[*internal*\] The `storage` property was removed from `Opis\Closure\ClosureScope`
|
||||
* \[*internal*\] The `instances` and `objects` properties were removed from `Opis\Closure\ClosureContext`
|
||||
|
||||
### v3.0.2, 2017.08.28
|
||||
|
||||
* Fixed a bug where `$this` object was not handled properly inside the
|
||||
`SerializableClosre::serialize` method.
|
||||
|
||||
### v3.0.1, 2017.04.13
|
||||
|
||||
* Fixed a bug in 'ignore_next' state
|
||||
|
||||
### v3.0.0, 2017.04.07
|
||||
|
||||
* Dropped PHP 5.3 support
|
||||
* Moved source files from `lib` to `src` folder
|
||||
* Removed second parameter from `Opis\Closure\SerializableClosure::from` method and from constructor
|
||||
* Removed `Opis\Closure\{SecurityProviderInterface, DefaultSecurityProvider, SecureClosure}` classes
|
||||
* Refactored how signed closures were handled
|
||||
* Added `wrapClosures` and `unwrapClosures` static methods to `Opis\Closure\SerializableClosure` class
|
||||
* Added `Opis\Colosure\serialize` and `Opis\Closure\unserialize` functions
|
||||
* Improved serialization. You can now serialize arbitrary objects and the library will automatically wrap all closures
|
||||
|
||||
### v2.4.0, 2016.12.16
|
||||
|
||||
* The parser was refactored and improved
|
||||
* Refactored `Opis\Closure\SerializableClosure::__invoke` method
|
||||
* `Opis\Closure\{ISecurityProvider, SecurityProvider}` were added
|
||||
* `Opis\Closure\{SecurityProviderInterface, DefaultSecurityProvider, SecureClosure}` were deprecated
|
||||
and they will be removed in the next major version
|
||||
* `setSecretKey` and `addSecurityProvider` static methods were added to `Opis\Closure\SerializableClosure`
|
||||
|
||||
### v2.3.2, 2016.12.15
|
||||
|
||||
* Fixed a bug that prevented namespace resolution to be done properly
|
||||
|
||||
### v2.3.1, 2016.12.13
|
||||
|
||||
* Hotfix. See [PR](https://github.com/opis/closure/pull/7)
|
||||
|
||||
### v2.3.0, 2016.11.17
|
||||
|
||||
* Added `isBindingRequired` and `isScopeRequired` to the `Opis\Closure\ReflectionClosure` class
|
||||
* Automatically detects when the scope and/or the bound object of a closure needs to be serialized.
|
||||
|
||||
### v2.2.1, 2016.08.20
|
||||
|
||||
* Fixed a bug in `Opis\Closure\ReflectionClosure::fetchItems`
|
||||
|
||||
### v2.2.0, 2016.07.26
|
||||
|
||||
* Fixed CS
|
||||
* `Opis\Closure\ClosureContext`, `Opis\Closure\ClosureScope`, `Opis\Closure\SelfReference`
|
||||
and `Opis\Closure\SecurityException` classes were moved into separate files
|
||||
* Added support for PHP7 syntax
|
||||
* Fixed some bugs in `Opis\Closure\ReflectionClosure` class
|
||||
* Improved closure parser
|
||||
* Added an analyzer for SuperClosure library
|
||||
|
||||
### v2.1.0, 2015.09.30
|
||||
|
||||
* Added support for the missing `__METHOD__`, `__FUNCTION__` and `__TRAIT__` magic constants
|
||||
* Added some security related classes and interfaces: `Opis\Closure\SecurityProviderInterface`,
|
||||
`Opis\Closure\DefaultSecurityProvider`, `Opis\Closure\SecureClosure`, `Opis\Closure\SecurityException`.
|
||||
* Fiexed a bug in `Opis\Closure\ReflectionClosure::getClasses` method
|
||||
* Other minor bugfixes
|
||||
* Added support for static closures
|
||||
* Added public `isStatic` method to `Opis\Closure\ReflectionClosure` class
|
||||
|
||||
|
||||
### v2.0.1, 2015.09.23
|
||||
|
||||
* Removed `branch-alias` property from `composer.json`
|
||||
* Bugfix. See [issue #6](https://github.com/opis/closure/issues/6)
|
||||
|
||||
### v2.0.0, 2015.07.31
|
||||
|
||||
* The closure parser was improved
|
||||
* Class names are now automatically resolved
|
||||
* Added support for the `#trackme` directive which allows tracking closure's residing source
|
||||
|
||||
### v1.3.0, 2014.10.18
|
||||
|
||||
* Added autoload file
|
||||
* Changed README file
|
||||
|
||||
### Opis Closure 1.2.2
|
||||
|
||||
* Started changelog
|
||||
20
vendor/opis/closure/LICENSE
vendored
Normal file
20
vendor/opis/closure/LICENSE
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2019 Zindex Software
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
9
vendor/opis/closure/NOTICE
vendored
Normal file
9
vendor/opis/closure/NOTICE
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
Opis Closure
|
||||
Copyright 2018-2019 Zindex Software
|
||||
|
||||
This product includes software developed at
|
||||
Zindex Software (http://zindex.software).
|
||||
|
||||
This software was originally developed by Marius Sarca and Sorin Sarca
|
||||
(Copyright 2014-2018). The copyright info was changed with the permission
|
||||
of the original authors.
|
||||
92
vendor/opis/closure/README.md
vendored
Normal file
92
vendor/opis/closure/README.md
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
Opis Closure
|
||||
====================
|
||||
[](https://github.com/opis/closure/actions)
|
||||
[](https://packagist.org/packages/opis/closure)
|
||||
[](https://packagist.org/packages/opis/closure)
|
||||
[](https://packagist.org/packages/opis/closure)
|
||||
|
||||
Serializable closures
|
||||
---------------------
|
||||
**Opis Closure** is a library that aims to overcome PHP's limitations regarding closure
|
||||
serialization by providing a wrapper that will make all closures serializable.
|
||||
|
||||
**The library's key features:**
|
||||
|
||||
- Serialize any closure
|
||||
- Serialize arbitrary objects
|
||||
- Doesn't use `eval` for closure serialization or unserialization
|
||||
- Works with any PHP version that has support for closures
|
||||
- Supports PHP 7 syntax
|
||||
- Handles all variables referenced/imported in `use()` and automatically wraps all referenced/imported closures for
|
||||
proper serialization
|
||||
- Handles recursive closures
|
||||
- Handles magic constants like `__FILE__`, `__DIR__`, `__LINE__`, `__NAMESPACE__`, `__CLASS__`,
|
||||
`__TRAIT__`, `__METHOD__` and `__FUNCTION__`.
|
||||
- Automatically resolves all class names, function names and constant names used inside the closure
|
||||
- Track closure's residing source by using the `#trackme` directive
|
||||
- Simple and very fast parser
|
||||
- Any error or exception, that might occur when executing an unserialized closure, can be caught and treated properly
|
||||
- You can serialize/unserialize any closure unlimited times, even those previously unserialized
|
||||
(this is possible because `eval()` is not used for unserialization)
|
||||
- Handles static closures
|
||||
- Supports cryptographically signed closures
|
||||
- Provides a reflector that can give you information about the serialized closure
|
||||
- Provides an analyzer for *SuperClosure* library
|
||||
- Automatically detects when the scope and/or the bound object of a closure needs to be serialized
|
||||
in order for the closure to work after deserialization
|
||||
|
||||
## Documentation
|
||||
|
||||
The full documentation for this library can be found [here][documentation].
|
||||
|
||||
## License
|
||||
|
||||
**Opis Closure** is licensed under the [MIT License (MIT)][license].
|
||||
|
||||
## Requirements
|
||||
|
||||
* PHP ^5.4 || ^7.0 || ^8.0
|
||||
|
||||
## Installation
|
||||
|
||||
**Opis Closure** is available on [Packagist] and it can be installed from a
|
||||
command line interface by using [Composer].
|
||||
|
||||
```bash
|
||||
composer require opis/closure
|
||||
```
|
||||
|
||||
Or you could directly reference it into your `composer.json` file as a dependency
|
||||
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
"opis/closure": "^3.5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Migrating from 2.x
|
||||
|
||||
If your project needs to support PHP 5.3 you can continue using the `2.x` version
|
||||
of **Opis Closure**. Otherwise, assuming you are not using one of the removed/refactored classes or features(see
|
||||
[CHANGELOG]), migrating to version `3.x` is simply a matter of updating your `composer.json` file.
|
||||
|
||||
### Semantic versioning
|
||||
|
||||
**Opis Closure** follows [semantic versioning][SemVer] specifications.
|
||||
|
||||
### Arbitrary object serialization
|
||||
|
||||
We've added this feature in order to be able to support the serialization of a closure's bound object.
|
||||
The implementation is far from being perfect, and it's really hard to make it work flawless.
|
||||
We will try to improve this, but we can't guarantee anything.
|
||||
So our advice regarding the `Opis\Closure\serialize|unserialize` functions is to use them with caution.
|
||||
|
||||
|
||||
[documentation]: https://www.opis.io/closure "Opis Closure"
|
||||
[license]: http://opensource.org/licenses/MIT "MIT License"
|
||||
[Packagist]: https://packagist.org/packages/opis/closure "Packagist"
|
||||
[Composer]: https://getcomposer.org "Composer"
|
||||
[SemVer]: http://semver.org/ "Semantic versioning"
|
||||
[CHANGELOG]: https://github.com/opis/closure/blob/master/CHANGELOG.md "Changelog"
|
||||
39
vendor/opis/closure/autoload.php
vendored
Normal file
39
vendor/opis/closure/autoload.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
require_once __DIR__ . '/functions.php';
|
||||
|
||||
spl_autoload_register(function($class){
|
||||
|
||||
$class = ltrim($class, '\\');
|
||||
$dir = __DIR__ . '/src';
|
||||
$namespace = 'Opis\Closure';
|
||||
|
||||
if(strpos($class, $namespace) === 0)
|
||||
{
|
||||
$class = substr($class, strlen($namespace));
|
||||
$path = '';
|
||||
if(($pos = strripos($class, '\\')) !== FALSE)
|
||||
{
|
||||
$path = str_replace('\\', '/', substr($class, 0, $pos)) . '/';
|
||||
$class = substr($class, $pos + 1);
|
||||
}
|
||||
$path .= str_replace('_', '/', $class) . '.php';
|
||||
$dir .= '/' . $path;
|
||||
|
||||
if(file_exists($dir))
|
||||
{
|
||||
include $dir;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
});
|
||||
44
vendor/opis/closure/composer.json
vendored
Normal file
44
vendor/opis/closure/composer.json
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "opis/closure",
|
||||
"description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.",
|
||||
"keywords": ["closure", "serialization", "function", "serializable", "serialize", "anonymous functions"],
|
||||
"homepage": "https://opis.io/closure",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marius Sarca",
|
||||
"email": "marius.sarca@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sorin Sarca",
|
||||
"email": "sarca_sorin@hotmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^5.4 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"jeremeamia/superclosure": "^2.0",
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Opis\\Closure\\": "src/"
|
||||
},
|
||||
"files": ["functions.php"]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Opis\\Closure\\Test\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.6.x-dev"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true
|
||||
}
|
||||
}
|
||||
41
vendor/opis/closure/functions.php
vendored
Normal file
41
vendor/opis/closure/functions.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
/**
|
||||
* Serialize
|
||||
*
|
||||
* @param mixed $data
|
||||
* @return string
|
||||
*/
|
||||
function serialize($data)
|
||||
{
|
||||
SerializableClosure::enterContext();
|
||||
SerializableClosure::wrapClosures($data);
|
||||
$data = \serialize($data);
|
||||
SerializableClosure::exitContext();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize
|
||||
*
|
||||
* @param string $data
|
||||
* @param array|null $options
|
||||
* @return mixed
|
||||
*/
|
||||
function unserialize($data, array $options = null)
|
||||
{
|
||||
SerializableClosure::enterContext();
|
||||
$data = ($options === null || \PHP_MAJOR_VERSION < 7)
|
||||
? \unserialize($data)
|
||||
: \unserialize($data, $options);
|
||||
SerializableClosure::unwrapClosures($data);
|
||||
SerializableClosure::exitContext();
|
||||
return $data;
|
||||
}
|
||||
62
vendor/opis/closure/src/Analyzer.php
vendored
Normal file
62
vendor/opis/closure/src/Analyzer.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
use Closure;
|
||||
use SuperClosure\Analyzer\ClosureAnalyzer;
|
||||
|
||||
/**
|
||||
* @deprecated We'll remove this class
|
||||
*/
|
||||
class Analyzer extends ClosureAnalyzer
|
||||
{
|
||||
/**
|
||||
* Analyzer a given closure.
|
||||
*
|
||||
* @param Closure $closure
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function analyze(Closure $closure)
|
||||
{
|
||||
$reflection = new ReflectionClosure($closure);
|
||||
$scope = $reflection->getClosureScopeClass();
|
||||
|
||||
$data = [
|
||||
'reflection' => $reflection,
|
||||
'code' => $reflection->getCode(),
|
||||
'hasThis' => $reflection->isBindingRequired(),
|
||||
'context' => $reflection->getUseVariables(),
|
||||
'hasRefs' => false,
|
||||
'binding' => $reflection->getClosureThis(),
|
||||
'scope' => $scope ? $scope->getName() : null,
|
||||
'isStatic' => $reflection->isStatic(),
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
protected function determineCode(array &$data)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
protected function determineContext(array &$data)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
34
vendor/opis/closure/src/ClosureContext.php
vendored
Normal file
34
vendor/opis/closure/src/ClosureContext.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
/**
|
||||
* Closure context class
|
||||
* @internal
|
||||
*/
|
||||
class ClosureContext
|
||||
{
|
||||
/**
|
||||
* @var ClosureScope Closures scope
|
||||
*/
|
||||
public $scope;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
public $locks;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->scope = new ClosureScope();
|
||||
$this->locks = 0;
|
||||
}
|
||||
}
|
||||
25
vendor/opis/closure/src/ClosureScope.php
vendored
Normal file
25
vendor/opis/closure/src/ClosureScope.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
/**
|
||||
* Closure scope class
|
||||
* @internal
|
||||
*/
|
||||
class ClosureScope extends \SplObjectStorage
|
||||
{
|
||||
/**
|
||||
* @var integer Number of serializations in current scope
|
||||
*/
|
||||
public $serializations = 0;
|
||||
|
||||
/**
|
||||
* @var integer Number of closures that have to be serialized
|
||||
*/
|
||||
public $toserialize = 0;
|
||||
}
|
||||
99
vendor/opis/closure/src/ClosureStream.php
vendored
Normal file
99
vendor/opis/closure/src/ClosureStream.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class ClosureStream
|
||||
{
|
||||
const STREAM_PROTO = 'closure';
|
||||
|
||||
protected static $isRegistered = false;
|
||||
|
||||
protected $content;
|
||||
|
||||
protected $length;
|
||||
|
||||
protected $pointer = 0;
|
||||
|
||||
function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
$this->content = "<?php\nreturn " . substr($path, strlen(static::STREAM_PROTO . '://')) . ";";
|
||||
$this->length = strlen($this->content);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_read($count)
|
||||
{
|
||||
$value = substr($this->content, $this->pointer, $count);
|
||||
$this->pointer += $count;
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function stream_eof()
|
||||
{
|
||||
return $this->pointer >= $this->length;
|
||||
}
|
||||
|
||||
public function stream_set_option($option, $arg1, $arg2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_stat()
|
||||
{
|
||||
$stat = stat(__FILE__);
|
||||
$stat[7] = $stat['size'] = $this->length;
|
||||
return $stat;
|
||||
}
|
||||
|
||||
public function url_stat($path, $flags)
|
||||
{
|
||||
$stat = stat(__FILE__);
|
||||
$stat[7] = $stat['size'] = $this->length;
|
||||
return $stat;
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
$crt = $this->pointer;
|
||||
|
||||
switch ($whence) {
|
||||
case SEEK_SET:
|
||||
$this->pointer = $offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
$this->pointer += $offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
$this->pointer = $this->length + $offset;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->pointer < 0 || $this->pointer >= $this->length) {
|
||||
$this->pointer = $crt;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->pointer;
|
||||
}
|
||||
|
||||
public static function register()
|
||||
{
|
||||
if (!static::$isRegistered) {
|
||||
static::$isRegistered = stream_wrapper_register(static::STREAM_PROTO, __CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
25
vendor/opis/closure/src/ISecurityProvider.php
vendored
Normal file
25
vendor/opis/closure/src/ISecurityProvider.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
interface ISecurityProvider
|
||||
{
|
||||
/**
|
||||
* Sign serialized closure
|
||||
* @param string $closure
|
||||
* @return array
|
||||
*/
|
||||
public function sign($closure);
|
||||
|
||||
/**
|
||||
* Verify signature
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function verify(array $data);
|
||||
}
|
||||
1093
vendor/opis/closure/src/ReflectionClosure.php
vendored
Normal file
1093
vendor/opis/closure/src/ReflectionClosure.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
vendor/opis/closure/src/SecurityException.php
vendored
Normal file
18
vendor/opis/closure/src/SecurityException.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Security exception class
|
||||
*/
|
||||
class SecurityException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
42
vendor/opis/closure/src/SecurityProvider.php
vendored
Normal file
42
vendor/opis/closure/src/SecurityProvider.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
class SecurityProvider implements ISecurityProvider
|
||||
{
|
||||
/** @var string */
|
||||
protected $secret;
|
||||
|
||||
/**
|
||||
* SecurityProvider constructor.
|
||||
* @param string $secret
|
||||
*/
|
||||
public function __construct($secret)
|
||||
{
|
||||
$this->secret = $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function sign($closure)
|
||||
{
|
||||
return array(
|
||||
'closure' => $closure,
|
||||
'hash' => base64_encode(hash_hmac('sha256', $closure, $this->secret, true)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function verify(array $data)
|
||||
{
|
||||
return base64_encode(hash_hmac('sha256', $data['closure'], $this->secret, true)) === $data['hash'];
|
||||
}
|
||||
}
|
||||
31
vendor/opis/closure/src/SelfReference.php
vendored
Normal file
31
vendor/opis/closure/src/SelfReference.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class used to indicate a reference to an object
|
||||
* @internal
|
||||
*/
|
||||
class SelfReference
|
||||
{
|
||||
/**
|
||||
* @var string An unique hash representing the object
|
||||
*/
|
||||
public $hash;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $hash
|
||||
*/
|
||||
public function __construct($hash)
|
||||
{
|
||||
$this->hash = $hash;
|
||||
}
|
||||
}
|
||||
678
vendor/opis/closure/src/SerializableClosure.php
vendored
Normal file
678
vendor/opis/closure/src/SerializableClosure.php
vendored
Normal file
@@ -0,0 +1,678 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2021 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
use Closure;
|
||||
use Serializable;
|
||||
use SplObjectStorage;
|
||||
use ReflectionObject;
|
||||
|
||||
/**
|
||||
* Provides a wrapper for serialization of closures
|
||||
*/
|
||||
class SerializableClosure implements Serializable
|
||||
{
|
||||
/**
|
||||
* @var Closure Wrapped closure
|
||||
*
|
||||
* @see \Opis\Closure\SerializableClosure::getClosure()
|
||||
*/
|
||||
protected $closure;
|
||||
|
||||
/**
|
||||
* @var ReflectionClosure A reflection instance for closure
|
||||
*
|
||||
* @see \Opis\Closure\SerializableClosure::getReflector()
|
||||
*/
|
||||
protected $reflector;
|
||||
|
||||
/**
|
||||
* @var mixed Used at deserialization to hold variables
|
||||
*
|
||||
* @see \Opis\Closure\SerializableClosure::unserialize()
|
||||
* @see \Opis\Closure\SerializableClosure::getReflector()
|
||||
*/
|
||||
protected $code;
|
||||
|
||||
/**
|
||||
* @var string Closure's ID
|
||||
*/
|
||||
protected $reference;
|
||||
|
||||
/**
|
||||
* @var string Closure scope
|
||||
*/
|
||||
protected $scope;
|
||||
|
||||
/**
|
||||
* @var ClosureContext Context of closure, used in serialization
|
||||
*/
|
||||
protected static $context;
|
||||
|
||||
/**
|
||||
* @var ISecurityProvider|null
|
||||
*/
|
||||
protected static $securityProvider;
|
||||
|
||||
/** Array recursive constant*/
|
||||
const ARRAY_RECURSIVE_KEY = '¯\_(ツ)_/¯';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Closure $closure Closure you want to serialize
|
||||
*/
|
||||
public function __construct(Closure $closure)
|
||||
{
|
||||
$this->closure = $closure;
|
||||
if (static::$context !== null) {
|
||||
$this->scope = static::$context->scope;
|
||||
$this->scope->toserialize++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Closure object
|
||||
*
|
||||
* @return Closure The wrapped closure
|
||||
*/
|
||||
public function getClosure()
|
||||
{
|
||||
return $this->closure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reflector for closure
|
||||
*
|
||||
* @return ReflectionClosure
|
||||
*/
|
||||
public function getReflector()
|
||||
{
|
||||
if ($this->reflector === null) {
|
||||
$this->reflector = new ReflectionClosure($this->closure);
|
||||
$this->code = null;
|
||||
}
|
||||
|
||||
return $this->reflector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of magic method __invoke()
|
||||
*/
|
||||
public function __invoke()
|
||||
{
|
||||
return call_user_func_array($this->closure, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Serializable::serialize()
|
||||
*
|
||||
* @return string The serialized closure
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
if ($this->scope === null) {
|
||||
$this->scope = new ClosureScope();
|
||||
$this->scope->toserialize++;
|
||||
}
|
||||
|
||||
$this->scope->serializations++;
|
||||
|
||||
$scope = $object = null;
|
||||
$reflector = $this->getReflector();
|
||||
|
||||
if($reflector->isBindingRequired()){
|
||||
$object = $reflector->getClosureThis();
|
||||
static::wrapClosures($object, $this->scope);
|
||||
if($scope = $reflector->getClosureScopeClass()){
|
||||
$scope = $scope->name;
|
||||
}
|
||||
} else {
|
||||
if($scope = $reflector->getClosureScopeClass()){
|
||||
$scope = $scope->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->reference = spl_object_hash($this->closure);
|
||||
|
||||
$this->scope[$this->closure] = $this;
|
||||
|
||||
$use = $this->transformUseVariables($reflector->getUseVariables());
|
||||
$code = $reflector->getCode();
|
||||
|
||||
$this->mapByReference($use);
|
||||
|
||||
$ret = \serialize(array(
|
||||
'use' => $use,
|
||||
'function' => $code,
|
||||
'scope' => $scope,
|
||||
'this' => $object,
|
||||
'self' => $this->reference,
|
||||
));
|
||||
|
||||
if (static::$securityProvider !== null) {
|
||||
$data = static::$securityProvider->sign($ret);
|
||||
$ret = '@' . $data['hash'] . '.' . $data['closure'];
|
||||
}
|
||||
|
||||
if (!--$this->scope->serializations && !--$this->scope->toserialize) {
|
||||
$this->scope = null;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the use variables before serialization.
|
||||
*
|
||||
* @param array $data The Closure's use variables
|
||||
* @return array
|
||||
*/
|
||||
protected function transformUseVariables($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Serializable::unserialize()
|
||||
*
|
||||
* @param string $data Serialized data
|
||||
* @throws SecurityException
|
||||
*/
|
||||
public function unserialize($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'];
|
||||
}
|
||||
|
||||
$this->code = \unserialize($data);
|
||||
|
||||
// unset data
|
||||
unset($data);
|
||||
|
||||
$this->code['objects'] = array();
|
||||
|
||||
if ($this->code['use']) {
|
||||
$this->scope = new ClosureScope();
|
||||
$this->code['use'] = $this->resolveUseVariables($this->code['use']);
|
||||
$this->mapPointers($this->code['use']);
|
||||
extract($this->code['use'], EXTR_OVERWRITE | EXTR_REFS);
|
||||
$this->scope = null;
|
||||
}
|
||||
|
||||
$this->closure = include(ClosureStream::STREAM_PROTO . '://' . $this->code['function']);
|
||||
|
||||
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'])){
|
||||
foreach ($this->code['objects'] as $item){
|
||||
$item['property']->setValue($item['instance'], $item['object']->getClosure());
|
||||
}
|
||||
}
|
||||
|
||||
$this->code = $this->code['function'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the use variables after unserialization.
|
||||
*
|
||||
* @param array $data The Closure's transformed use variables
|
||||
* @return array
|
||||
*/
|
||||
protected function resolveUseVariables($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a closure and sets the serialization context (if any)
|
||||
*
|
||||
* @param Closure $closure Closure to be wrapped
|
||||
*
|
||||
* @return self The wrapped closure
|
||||
*/
|
||||
public static function from(Closure $closure)
|
||||
{
|
||||
if (static::$context === null) {
|
||||
$instance = new static($closure);
|
||||
} elseif (isset(static::$context->scope[$closure])) {
|
||||
$instance = static::$context->scope[$closure];
|
||||
} else {
|
||||
$instance = new static($closure);
|
||||
static::$context->scope[$closure] = $instance;
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the context lock counter or creates a new context if none exist
|
||||
*/
|
||||
public static function enterContext()
|
||||
{
|
||||
if (static::$context === null) {
|
||||
static::$context = new ClosureContext();
|
||||
}
|
||||
|
||||
static::$context->locks++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the context lock counter and destroy the context when it reaches to 0
|
||||
*/
|
||||
public static function exitContext()
|
||||
{
|
||||
if (static::$context !== null && !--static::$context->locks) {
|
||||
static::$context = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $secret
|
||||
*/
|
||||
public static function setSecretKey($secret)
|
||||
{
|
||||
if(static::$securityProvider === null){
|
||||
static::$securityProvider = new SecurityProvider($secret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ISecurityProvider $securityProvider
|
||||
*/
|
||||
public static function addSecurityProvider(ISecurityProvider $securityProvider)
|
||||
{
|
||||
static::$securityProvider = $securityProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove security provider
|
||||
*/
|
||||
public static function removeSecurityProvider()
|
||||
{
|
||||
static::$securityProvider = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|ISecurityProvider
|
||||
*/
|
||||
public static function getSecurityProvider()
|
||||
{
|
||||
return static::$securityProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap closures
|
||||
*
|
||||
* @internal
|
||||
* @param $data
|
||||
* @param ClosureScope|SplObjectStorage|null $storage
|
||||
*/
|
||||
public static function wrapClosures(&$data, SplObjectStorage $storage = null)
|
||||
{
|
||||
if($storage === null){
|
||||
$storage = static::$context->scope;
|
||||
}
|
||||
|
||||
if($data instanceof Closure){
|
||||
$data = static::from($data);
|
||||
} elseif (is_array($data)){
|
||||
if(isset($data[self::ARRAY_RECURSIVE_KEY])){
|
||||
return;
|
||||
}
|
||||
$data[self::ARRAY_RECURSIVE_KEY] = true;
|
||||
foreach ($data as $key => &$value){
|
||||
if($key === self::ARRAY_RECURSIVE_KEY){
|
||||
continue;
|
||||
}
|
||||
static::wrapClosures($value, $storage);
|
||||
}
|
||||
unset($value);
|
||||
unset($data[self::ARRAY_RECURSIVE_KEY]);
|
||||
} elseif($data instanceof \stdClass){
|
||||
if(isset($storage[$data])){
|
||||
$data = $storage[$data];
|
||||
return;
|
||||
}
|
||||
$data = $storage[$data] = clone($data);
|
||||
foreach ($data as &$value){
|
||||
static::wrapClosures($value, $storage);
|
||||
}
|
||||
unset($value);
|
||||
} elseif (is_object($data) && ! $data instanceof static){
|
||||
if(isset($storage[$data])){
|
||||
$data = $storage[$data];
|
||||
return;
|
||||
}
|
||||
$instance = $data;
|
||||
$reflection = new ReflectionObject($instance);
|
||||
if(!$reflection->isUserDefined()){
|
||||
$storage[$instance] = $data;
|
||||
return;
|
||||
}
|
||||
$storage[$instance] = $data = $reflection->newInstanceWithoutConstructor();
|
||||
|
||||
do{
|
||||
if(!$reflection->isUserDefined()){
|
||||
break;
|
||||
}
|
||||
foreach ($reflection->getProperties() as $property){
|
||||
if($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()){
|
||||
continue;
|
||||
}
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION >= 7.4 && !$property->isInitialized($instance)) {
|
||||
continue;
|
||||
}
|
||||
$value = $property->getValue($instance);
|
||||
if(is_array($value) || is_object($value)){
|
||||
static::wrapClosures($value, $storage);
|
||||
}
|
||||
$property->setValue($data, $value);
|
||||
};
|
||||
} while($reflection = $reflection->getParentClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap closures
|
||||
*
|
||||
* @internal
|
||||
* @param $data
|
||||
* @param SplObjectStorage|null $storage
|
||||
*/
|
||||
public static function unwrapClosures(&$data, SplObjectStorage $storage = null)
|
||||
{
|
||||
if($storage === null){
|
||||
$storage = static::$context->scope;
|
||||
}
|
||||
|
||||
if($data instanceof static){
|
||||
$data = $data->getClosure();
|
||||
} elseif (is_array($data)){
|
||||
if(isset($data[self::ARRAY_RECURSIVE_KEY])){
|
||||
return;
|
||||
}
|
||||
$data[self::ARRAY_RECURSIVE_KEY] = true;
|
||||
foreach ($data as $key => &$value){
|
||||
if($key === self::ARRAY_RECURSIVE_KEY){
|
||||
continue;
|
||||
}
|
||||
static::unwrapClosures($value, $storage);
|
||||
}
|
||||
unset($data[self::ARRAY_RECURSIVE_KEY]);
|
||||
}elseif ($data instanceof \stdClass){
|
||||
if(isset($storage[$data])){
|
||||
return;
|
||||
}
|
||||
$storage[$data] = true;
|
||||
foreach ($data as &$property){
|
||||
static::unwrapClosures($property, $storage);
|
||||
}
|
||||
} elseif (is_object($data) && !($data instanceof Closure)){
|
||||
if(isset($storage[$data])){
|
||||
return;
|
||||
}
|
||||
$storage[$data] = true;
|
||||
$reflection = new ReflectionObject($data);
|
||||
|
||||
do{
|
||||
if(!$reflection->isUserDefined()){
|
||||
break;
|
||||
}
|
||||
foreach ($reflection->getProperties() as $property){
|
||||
if($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()){
|
||||
continue;
|
||||
}
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION >= 7.4 && !$property->isInitialized($data)) {
|
||||
continue;
|
||||
}
|
||||
$value = $property->getValue($data);
|
||||
if(is_array($value) || is_object($value)){
|
||||
static::unwrapClosures($value, $storage);
|
||||
$property->setValue($data, $value);
|
||||
}
|
||||
};
|
||||
} while($reflection = $reflection->getParentClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new closure from arbitrary code,
|
||||
* emulating create_function, but without using eval
|
||||
*
|
||||
* @param string$args
|
||||
* @param string $code
|
||||
* @return Closure
|
||||
*/
|
||||
public static function createClosure($args, $code)
|
||||
{
|
||||
ClosureStream::register();
|
||||
return include(ClosureStream::STREAM_PROTO . '://function(' . $args. '){' . $code . '};');
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method used to map closure pointers
|
||||
* @internal
|
||||
* @param $data
|
||||
*/
|
||||
protected function mapPointers(&$data)
|
||||
{
|
||||
$scope = $this->scope;
|
||||
|
||||
if ($data instanceof static) {
|
||||
$data = &$data->closure;
|
||||
} elseif (is_array($data)) {
|
||||
if(isset($data[self::ARRAY_RECURSIVE_KEY])){
|
||||
return;
|
||||
}
|
||||
$data[self::ARRAY_RECURSIVE_KEY] = true;
|
||||
foreach ($data as $key => &$value){
|
||||
if($key === self::ARRAY_RECURSIVE_KEY){
|
||||
continue;
|
||||
} elseif ($value instanceof static) {
|
||||
$data[$key] = &$value->closure;
|
||||
} elseif ($value instanceof SelfReference && $value->hash === $this->code['self']){
|
||||
$data[$key] = &$this->closure;
|
||||
} else {
|
||||
$this->mapPointers($value);
|
||||
}
|
||||
}
|
||||
unset($value);
|
||||
unset($data[self::ARRAY_RECURSIVE_KEY]);
|
||||
} elseif ($data instanceof \stdClass) {
|
||||
if(isset($scope[$data])){
|
||||
return;
|
||||
}
|
||||
$scope[$data] = true;
|
||||
foreach ($data as $key => &$value){
|
||||
if ($value instanceof SelfReference && $value->hash === $this->code['self']){
|
||||
$data->{$key} = &$this->closure;
|
||||
} elseif(is_array($value) || is_object($value)) {
|
||||
$this->mapPointers($value);
|
||||
}
|
||||
}
|
||||
unset($value);
|
||||
} elseif (is_object($data) && !($data instanceof Closure)){
|
||||
if(isset($scope[$data])){
|
||||
return;
|
||||
}
|
||||
$scope[$data] = true;
|
||||
$reflection = new ReflectionObject($data);
|
||||
do{
|
||||
if(!$reflection->isUserDefined()){
|
||||
break;
|
||||
}
|
||||
foreach ($reflection->getProperties() as $property){
|
||||
if($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()){
|
||||
continue;
|
||||
}
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION >= 7.4 && !$property->isInitialized($data)) {
|
||||
continue;
|
||||
}
|
||||
$item = $property->getValue($data);
|
||||
if ($item instanceof SerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) {
|
||||
$this->code['objects'][] = array(
|
||||
'instance' => $data,
|
||||
'property' => $property,
|
||||
'object' => $item instanceof SelfReference ? $this : $item,
|
||||
);
|
||||
} elseif (is_array($item) || is_object($item)) {
|
||||
$this->mapPointers($item);
|
||||
$property->setValue($data, $item);
|
||||
}
|
||||
}
|
||||
} while($reflection = $reflection->getParentClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method used to map closures by reference
|
||||
*
|
||||
* @internal
|
||||
* @param mixed &$data
|
||||
*/
|
||||
protected function mapByReference(&$data)
|
||||
{
|
||||
if ($data instanceof Closure) {
|
||||
if($data === $this->closure){
|
||||
$data = new SelfReference($this->reference);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->scope[$data])) {
|
||||
$data = $this->scope[$data];
|
||||
return;
|
||||
}
|
||||
|
||||
$instance = new static($data);
|
||||
|
||||
if (static::$context !== null) {
|
||||
static::$context->scope->toserialize--;
|
||||
} else {
|
||||
$instance->scope = $this->scope;
|
||||
}
|
||||
|
||||
$data = $this->scope[$data] = $instance;
|
||||
} elseif (is_array($data)) {
|
||||
if(isset($data[self::ARRAY_RECURSIVE_KEY])){
|
||||
return;
|
||||
}
|
||||
$data[self::ARRAY_RECURSIVE_KEY] = true;
|
||||
foreach ($data as $key => &$value){
|
||||
if($key === self::ARRAY_RECURSIVE_KEY){
|
||||
continue;
|
||||
}
|
||||
$this->mapByReference($value);
|
||||
}
|
||||
unset($value);
|
||||
unset($data[self::ARRAY_RECURSIVE_KEY]);
|
||||
} elseif ($data instanceof \stdClass) {
|
||||
if(isset($this->scope[$data])){
|
||||
$data = $this->scope[$data];
|
||||
return;
|
||||
}
|
||||
$instance = $data;
|
||||
$this->scope[$instance] = $data = clone($data);
|
||||
|
||||
foreach ($data as &$value){
|
||||
$this->mapByReference($value);
|
||||
}
|
||||
unset($value);
|
||||
} elseif (is_object($data) && !$data instanceof SerializableClosure){
|
||||
if(isset($this->scope[$data])){
|
||||
$data = $this->scope[$data];
|
||||
return;
|
||||
}
|
||||
|
||||
$instance = $data;
|
||||
$reflection = new ReflectionObject($data);
|
||||
if(!$reflection->isUserDefined()){
|
||||
$this->scope[$instance] = $data;
|
||||
return;
|
||||
}
|
||||
$this->scope[$instance] = $data = $reflection->newInstanceWithoutConstructor();
|
||||
|
||||
do{
|
||||
if(!$reflection->isUserDefined()){
|
||||
break;
|
||||
}
|
||||
foreach ($reflection->getProperties() as $property){
|
||||
if($property->isStatic() || !$property->getDeclaringClass()->isUserDefined()){
|
||||
continue;
|
||||
}
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION >= 7.4 && !$property->isInitialized($instance)) {
|
||||
continue;
|
||||
}
|
||||
$value = $property->getValue($instance);
|
||||
if(is_array($value) || is_object($value)){
|
||||
$this->mapByReference($value);
|
||||
}
|
||||
$property->setValue($data, $value);
|
||||
}
|
||||
} while($reflection = $reflection->getParentClass());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user