提交代码
This commit is contained in:
207
vendor/opis/closure/CHANGELOG.md
vendored
Normal file
207
vendor/opis/closure/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
CHANGELOG
|
||||
---------
|
||||
|
||||
### 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.
|
||||
98
vendor/opis/closure/README.md
vendored
Normal file
98
vendor/opis/closure/README.md
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
Opis Closure
|
||||
====================
|
||||
[](https://travis-ci.org/opis/closure)
|
||||
[](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
|
||||
|
||||
## 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.4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
This feature was primarily introduced in order to support serializing an object bound
|
||||
to a closure and available via `$this`. The implementation is far from being perfect
|
||||
and it's really hard to make it work flawless. I will try to improve this, but I can
|
||||
not guarantee anything. So my advice regarding the `Opis\Closure\serialize|unserialize`
|
||||
functions is to use them with caution.
|
||||
|
||||
### SuperClosure support
|
||||
|
||||
**Opis Closure** is shipped with an analyzer(`Opis\Closure\Analyzer`) which
|
||||
aims to provide *Opis Closure*'s parsing precision and speed to [SuperClosure].
|
||||
|
||||
[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"
|
||||
[SuperClosure]: https://github.com/jeremeamia/super_closure "SuperClosure"
|
||||
[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-2019 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
require_once '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;
|
||||
|
||||
});
|
||||
40
vendor/opis/closure/composer.json
vendored
Normal file
40
vendor/opis/closure/composer.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"require-dev": {
|
||||
"jeremeamia/superclosure": "^2.0",
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Opis\\Closure\\": "src/"
|
||||
},
|
||||
"files": ["functions.php"]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Opis\\Closure\\Test\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.3.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
38
vendor/opis/closure/functions.php
vendored
Normal file
38
vendor/opis/closure/functions.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2019 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
/**
|
||||
* Serialize
|
||||
*
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
function serialize($data)
|
||||
{
|
||||
SerializableClosure::enterContext();
|
||||
SerializableClosure::wrapClosures($data);
|
||||
$data = \serialize($data);
|
||||
SerializableClosure::exitContext();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize
|
||||
*
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
function unserialize($data)
|
||||
{
|
||||
SerializableClosure::enterContext();
|
||||
$data = \unserialize($data);
|
||||
SerializableClosure::unwrapClosures($data);
|
||||
SerializableClosure::exitContext();
|
||||
return $data;
|
||||
}
|
||||
59
vendor/opis/closure/src/Analyzer.php
vendored
Normal file
59
vendor/opis/closure/src/Analyzer.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2019 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
use Closure;
|
||||
use SuperClosure\Analyzer\ClosureAnalyzer;
|
||||
|
||||
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-2019 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-2019 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;
|
||||
}
|
||||
94
vendor/opis/closure/src/ClosureStream.php
vendored
Normal file
94
vendor/opis/closure/src/ClosureStream.php
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2019 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_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-2019 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);
|
||||
}
|
||||
939
vendor/opis/closure/src/ReflectionClosure.php
vendored
Normal file
939
vendor/opis/closure/src/ReflectionClosure.php
vendored
Normal file
@@ -0,0 +1,939 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2019 Zindex Software
|
||||
*
|
||||
* Licensed under the MIT License
|
||||
* =========================================================================== */
|
||||
|
||||
namespace Opis\Closure;
|
||||
|
||||
use Closure;
|
||||
use ReflectionFunction;
|
||||
|
||||
class ReflectionClosure extends ReflectionFunction
|
||||
{
|
||||
protected $code;
|
||||
protected $tokens;
|
||||
protected $hashedName;
|
||||
protected $useVariables;
|
||||
protected $isStaticClosure;
|
||||
protected $isScopeRequired;
|
||||
protected $isBindingRequired;
|
||||
|
||||
protected static $files = array();
|
||||
protected static $classes = array();
|
||||
protected static $functions = array();
|
||||
protected static $constants = array();
|
||||
protected static $structures = array();
|
||||
|
||||
|
||||
/**
|
||||
* ReflectionClosure constructor.
|
||||
* @param Closure $closure
|
||||
* @param string|null $code
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function __construct(Closure $closure, $code = null)
|
||||
{
|
||||
$this->code = $code;
|
||||
parent::__construct($closure);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isStatic()
|
||||
{
|
||||
if ($this->isStaticClosure === null) {
|
||||
$this->isStaticClosure = strtolower(substr($this->getCode(), 0, 6)) === 'static';
|
||||
}
|
||||
|
||||
return $this->isStaticClosure;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCode()
|
||||
{
|
||||
if($this->code !== null){
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
$fileName = $this->getFileName();
|
||||
$line = $this->getStartLine() - 1;
|
||||
|
||||
$match = ClosureStream::STREAM_PROTO . '://';
|
||||
|
||||
if ($line === 1 && substr($fileName, 0, strlen($match)) === $match) {
|
||||
return $this->code = substr($fileName, strlen($match));
|
||||
}
|
||||
|
||||
$className = null;
|
||||
|
||||
|
||||
if (null !== $className = $this->getClosureScopeClass()) {
|
||||
$className = '\\' . trim($className->getName(), '\\');
|
||||
}
|
||||
|
||||
|
||||
if($php7 = PHP_MAJOR_VERSION === 7){
|
||||
switch (PHP_MINOR_VERSION){
|
||||
case 0:
|
||||
$php7_types = array('string', 'int', 'bool', 'float');
|
||||
break;
|
||||
case 1:
|
||||
$php7_types = array('string', 'int', 'bool', 'float', 'void');
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
$php7_types = array('string', 'int', 'bool', 'float', 'void', 'object');
|
||||
}
|
||||
}
|
||||
|
||||
$ns = $this->getNamespaceName();
|
||||
$nsf = $ns == '' ? '' : ($ns[0] == '\\' ? $ns : '\\' . $ns);
|
||||
|
||||
$_file = var_export($fileName, true);
|
||||
$_dir = var_export(dirname($fileName), true);
|
||||
$_namespace = var_export($ns, true);
|
||||
$_class = var_export(trim($className, '\\'), true);
|
||||
$_function = $ns . ($ns == '' ? '' : '\\') . '{closure}';
|
||||
$_method = ($className == '' ? '' : trim($className, '\\') . '::') . $_function;
|
||||
$_function = var_export($_function, true);
|
||||
$_method = var_export($_method, true);
|
||||
$_trait = null;
|
||||
|
||||
$tokens = $this->getTokens();
|
||||
$state = $lastState = 'start';
|
||||
$inside_anonymous = false;
|
||||
$anonymous_mark = 0;
|
||||
$open = 0;
|
||||
$code = '';
|
||||
$id_start = $id_start_ci = $id_name = $context = '';
|
||||
$classes = $functions = $constants = null;
|
||||
$use = array();
|
||||
$lineAdd = 0;
|
||||
$isUsingScope = false;
|
||||
$isUsingThisObject = false;
|
||||
|
||||
for($i = 0, $l = count($tokens); $i < $l; $i++) {
|
||||
$token = $tokens[$i];
|
||||
switch ($state) {
|
||||
case 'start':
|
||||
if ($token[0] === T_FUNCTION || $token[0] === T_STATIC) {
|
||||
$code .= $token[1];
|
||||
$state = $token[0] === T_FUNCTION ? 'function' : 'static';
|
||||
}
|
||||
break;
|
||||
case 'static':
|
||||
if ($token[0] === T_WHITESPACE || $token[0] === T_COMMENT || $token[0] === T_FUNCTION) {
|
||||
$code .= $token[1];
|
||||
if ($token[0] === T_FUNCTION) {
|
||||
$state = 'function';
|
||||
}
|
||||
} else {
|
||||
$code = '';
|
||||
$state = 'start';
|
||||
}
|
||||
break;
|
||||
case 'function':
|
||||
switch ($token[0]){
|
||||
case T_STRING:
|
||||
$code = '';
|
||||
$state = 'named_function';
|
||||
break;
|
||||
case '(':
|
||||
$code .= '(';
|
||||
$state = 'closure_args';
|
||||
break;
|
||||
default:
|
||||
$code .= is_array($token) ? $token[1] : $token;
|
||||
}
|
||||
break;
|
||||
case 'named_function':
|
||||
if($token[0] === T_FUNCTION || $token[0] === T_STATIC){
|
||||
$code = $token[1];
|
||||
$state = $token[0] === T_FUNCTION ? 'function' : 'static';
|
||||
}
|
||||
break;
|
||||
case 'closure_args':
|
||||
switch ($token[0]){
|
||||
case T_NS_SEPARATOR:
|
||||
case T_STRING:
|
||||
$id_start = $token[1];
|
||||
$id_start_ci = strtolower($id_start);
|
||||
$id_name = '';
|
||||
$context = 'args';
|
||||
$state = 'id_name';
|
||||
$lastState = 'closure_args';
|
||||
break;
|
||||
case T_USE:
|
||||
$code .= $token[1];
|
||||
$state = 'use';
|
||||
break;
|
||||
case '=':
|
||||
$code .= $token;
|
||||
$lastState = 'closure_args';
|
||||
$state = 'ignore_next';
|
||||
break;
|
||||
case ':':
|
||||
$code .= ':';
|
||||
$state = 'return';
|
||||
break;
|
||||
case '{':
|
||||
$code .= '{';
|
||||
$state = 'closure';
|
||||
$open++;
|
||||
break;
|
||||
default:
|
||||
$code .= is_array($token) ? $token[1] : $token;
|
||||
}
|
||||
break;
|
||||
case 'use':
|
||||
switch ($token[0]){
|
||||
case T_VARIABLE:
|
||||
$use[] = substr($token[1], 1);
|
||||
$code .= $token[1];
|
||||
break;
|
||||
case '{':
|
||||
$code .= '{';
|
||||
$state = 'closure';
|
||||
$open++;
|
||||
break;
|
||||
case ':':
|
||||
$code .= ':';
|
||||
$state = 'return';
|
||||
break;
|
||||
default:
|
||||
$code .= is_array($token) ? $token[1] : $token;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'return':
|
||||
switch ($token[0]){
|
||||
case T_WHITESPACE:
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
$code .= $token[1];
|
||||
break;
|
||||
case T_NS_SEPARATOR:
|
||||
case T_STRING:
|
||||
$id_start = $token[1];
|
||||
$id_start_ci = strtolower($id_start);
|
||||
$id_name = '';
|
||||
$context = 'return_type';
|
||||
$state = 'id_name';
|
||||
$lastState = 'return';
|
||||
break 2;
|
||||
case '{':
|
||||
$code .= '{';
|
||||
$state = 'closure';
|
||||
$open++;
|
||||
break;
|
||||
default:
|
||||
$code .= is_array($token) ? $token[1] : $token;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'closure':
|
||||
switch ($token[0]){
|
||||
case T_CURLY_OPEN:
|
||||
case T_DOLLAR_OPEN_CURLY_BRACES:
|
||||
case T_STRING_VARNAME:
|
||||
case '{':
|
||||
$code .= '{';
|
||||
$open++;
|
||||
break;
|
||||
case '}':
|
||||
$code .= '}';
|
||||
if(--$open === 0){
|
||||
break 3;
|
||||
} elseif ($inside_anonymous) {
|
||||
$inside_anonymous = !($open === $anonymous_mark);
|
||||
}
|
||||
break;
|
||||
case T_LINE:
|
||||
$code .= $token[2] - $line + $lineAdd;
|
||||
break;
|
||||
case T_FILE:
|
||||
$code .= $_file;
|
||||
break;
|
||||
case T_DIR:
|
||||
$code .= $_dir;
|
||||
break;
|
||||
case T_NS_C:
|
||||
$code .= $_namespace;
|
||||
break;
|
||||
case T_CLASS_C:
|
||||
$code .= $_class;
|
||||
break;
|
||||
case T_FUNC_C:
|
||||
$code .= $_function;
|
||||
break;
|
||||
case T_METHOD_C:
|
||||
$code .= $_method;
|
||||
break;
|
||||
case T_COMMENT:
|
||||
if (substr($token[1], 0, 8) === '#trackme') {
|
||||
$timestamp = time();
|
||||
$code .= '/**' . PHP_EOL;
|
||||
$code .= '* Date : ' . date(DATE_W3C, $timestamp) . PHP_EOL;
|
||||
$code .= '* Timestamp : ' . $timestamp . PHP_EOL;
|
||||
$code .= '* Line : ' . ($line + 1) . PHP_EOL;
|
||||
$code .= '* File : ' . $_file . PHP_EOL . '*/' . PHP_EOL;
|
||||
$lineAdd += 5;
|
||||
} else {
|
||||
$code .= $token[1];
|
||||
}
|
||||
break;
|
||||
case T_VARIABLE:
|
||||
if($token[1] == '$this' && !$inside_anonymous){
|
||||
$isUsingThisObject = true;
|
||||
}
|
||||
$code .= $token[1];
|
||||
break;
|
||||
case T_STATIC:
|
||||
$isUsingScope = true;
|
||||
$code .= $token[1];
|
||||
break;
|
||||
case T_NS_SEPARATOR:
|
||||
case T_STRING:
|
||||
$id_start = $token[1];
|
||||
$id_start_ci = strtolower($id_start);
|
||||
$id_name = '';
|
||||
$context = 'root';
|
||||
$state = 'id_name';
|
||||
$lastState = 'closure';
|
||||
break 2;
|
||||
case T_NEW:
|
||||
$code .= $token[1];
|
||||
$context = 'new';
|
||||
$state = 'id_start';
|
||||
$lastState = 'closure';
|
||||
break 2;
|
||||
case T_USE:
|
||||
$code .= $token[1];
|
||||
$context = 'use';
|
||||
$state = 'id_start';
|
||||
$lastState = 'closure';
|
||||
break;
|
||||
case T_INSTANCEOF:
|
||||
$code .= $token[1];
|
||||
$context = 'instanceof';
|
||||
$state = 'id_start';
|
||||
$lastState = 'closure';
|
||||
break;
|
||||
case T_OBJECT_OPERATOR:
|
||||
case T_DOUBLE_COLON:
|
||||
$code .= $token[1];
|
||||
$lastState = 'closure';
|
||||
$state = 'ignore_next';
|
||||
break;
|
||||
case T_FUNCTION:
|
||||
$code .= $token[1];
|
||||
$state = 'closure_args';
|
||||
break;
|
||||
case T_TRAIT_C:
|
||||
if ($_trait === null) {
|
||||
$startLine = $this->getStartLine();
|
||||
$endLine = $this->getEndLine();
|
||||
$structures = $this->getStructures();
|
||||
|
||||
$_trait = '';
|
||||
|
||||
foreach ($structures as &$struct) {
|
||||
if ($struct['type'] === 'trait' &&
|
||||
$struct['start'] <= $startLine &&
|
||||
$struct['end'] >= $endLine
|
||||
) {
|
||||
$_trait = ($ns == '' ? '' : $ns . '\\') . $struct['name'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$_trait = var_export($_trait, true);
|
||||
}
|
||||
|
||||
$code .= $_trait;
|
||||
break;
|
||||
default:
|
||||
$code .= is_array($token) ? $token[1] : $token;
|
||||
}
|
||||
break;
|
||||
case 'ignore_next':
|
||||
switch ($token[0]){
|
||||
case T_WHITESPACE:
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
$code .= $token[1];
|
||||
break;
|
||||
case T_CLASS:
|
||||
case T_NEW:
|
||||
case T_STATIC:
|
||||
case T_VARIABLE:
|
||||
case T_STRING:
|
||||
case T_CLASS_C:
|
||||
case T_FILE:
|
||||
case T_DIR:
|
||||
case T_METHOD_C:
|
||||
case T_FUNC_C:
|
||||
case T_FUNCTION:
|
||||
case T_INSTANCEOF:
|
||||
case T_LINE:
|
||||
case T_NS_C:
|
||||
case T_TRAIT_C:
|
||||
case T_USE:
|
||||
$code .= $token[1];
|
||||
$state = $lastState;
|
||||
break;
|
||||
default:
|
||||
$state = $lastState;
|
||||
$i--;
|
||||
}
|
||||
break;
|
||||
case 'id_start':
|
||||
switch ($token[0]){
|
||||
case T_WHITESPACE:
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
$code .= $token[1];
|
||||
break;
|
||||
case T_NS_SEPARATOR:
|
||||
case T_STRING:
|
||||
case T_STATIC:
|
||||
$id_start = $token[1];
|
||||
$id_start_ci = strtolower($id_start);
|
||||
$id_name = '';
|
||||
$state = 'id_name';
|
||||
break 2;
|
||||
case T_VARIABLE:
|
||||
$code .= $token[1];
|
||||
$state = $lastState;
|
||||
break;
|
||||
case T_CLASS:
|
||||
$code .= $token[1];
|
||||
$state = 'anonymous';
|
||||
break;
|
||||
default:
|
||||
$i--;//reprocess last
|
||||
$state = 'id_name';
|
||||
}
|
||||
break;
|
||||
case 'id_name':
|
||||
switch ($token[0]){
|
||||
case T_NS_SEPARATOR:
|
||||
case T_STRING:
|
||||
$id_name .= $token[1];
|
||||
break;
|
||||
case T_WHITESPACE:
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
$id_name .= $token[1];
|
||||
break;
|
||||
case '(':
|
||||
if($context === 'new' || false !== strpos($id_name, '\\')){
|
||||
if($id_start !== '\\'){
|
||||
if ($classes === null) {
|
||||
$classes = $this->getClasses();
|
||||
}
|
||||
if (isset($classes[$id_start_ci])) {
|
||||
$id_start = $classes[$id_start_ci];
|
||||
}
|
||||
if($id_start[0] !== '\\'){
|
||||
$id_start = $nsf . '\\' . $id_start;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if($id_start !== '\\'){
|
||||
if($functions === null){
|
||||
$functions = $this->getFunctions();
|
||||
}
|
||||
if(isset($functions[$id_start_ci])){
|
||||
$id_start = $functions[$id_start_ci];
|
||||
}
|
||||
}
|
||||
}
|
||||
$code .= $id_start . $id_name . '(';
|
||||
$state = $lastState;
|
||||
break;
|
||||
case T_VARIABLE:
|
||||
case T_DOUBLE_COLON:
|
||||
if($id_start !== '\\') {
|
||||
if($id_start_ci === 'self' || $id_start_ci === 'static' || $id_start_ci === 'parent'){
|
||||
$isUsingScope = true;
|
||||
} elseif (!($php7 && in_array($id_start_ci, $php7_types))){
|
||||
if ($classes === null) {
|
||||
$classes = $this->getClasses();
|
||||
}
|
||||
if (isset($classes[$id_start_ci])) {
|
||||
$id_start = $classes[$id_start_ci];
|
||||
}
|
||||
if($id_start[0] !== '\\'){
|
||||
$id_start = $nsf . '\\' . $id_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
$code .= $id_start . $id_name . $token[1];
|
||||
$state = $token[0] === T_DOUBLE_COLON ? 'ignore_next' : $lastState;
|
||||
break;
|
||||
default:
|
||||
if($id_start !== '\\'){
|
||||
if($context === 'use' ||
|
||||
$context === 'instanceof' ||
|
||||
$context === 'args' ||
|
||||
$context === 'return_type' ||
|
||||
$context === 'extends'
|
||||
){
|
||||
if($id_start_ci === 'self' || $id_start_ci === 'static' || $id_start_ci === 'parent'){
|
||||
$isUsingScope = true;
|
||||
} elseif (!($php7 && in_array($id_start_ci, $php7_types))){
|
||||
if($classes === null){
|
||||
$classes = $this->getClasses();
|
||||
}
|
||||
if(isset($classes[$id_start_ci])){
|
||||
$id_start = $classes[$id_start_ci];
|
||||
}
|
||||
if($id_start[0] !== '\\'){
|
||||
$id_start = $nsf . '\\' . $id_start;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if($constants === null){
|
||||
$constants = $this->getConstants();
|
||||
}
|
||||
if(isset($constants[$id_start])){
|
||||
$id_start = $constants[$id_start];
|
||||
}
|
||||
}
|
||||
}
|
||||
$code .= $id_start . $id_name;
|
||||
$state = $lastState;
|
||||
$i--;//reprocess last token
|
||||
}
|
||||
break;
|
||||
case 'anonymous':
|
||||
switch ($token[0]) {
|
||||
case T_NS_SEPARATOR:
|
||||
case T_STRING:
|
||||
$id_start = $token[1];
|
||||
$id_start_ci = strtolower($id_start);
|
||||
$id_name = '';
|
||||
$state = 'id_name';
|
||||
$context = 'extends';
|
||||
$lastState = 'anonymous';
|
||||
break;
|
||||
case '{':
|
||||
$state = 'closure';
|
||||
if (!$inside_anonymous) {
|
||||
$inside_anonymous = true;
|
||||
$anonymous_mark = $open;
|
||||
}
|
||||
$i--;
|
||||
break;
|
||||
default:
|
||||
$code .= is_array($token) ? $token[1] : $token;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->isBindingRequired = $isUsingThisObject;
|
||||
$this->isScopeRequired = $isUsingScope;
|
||||
$this->code = $code;
|
||||
$this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use));
|
||||
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getUseVariables()
|
||||
{
|
||||
if($this->useVariables !== null){
|
||||
return $this->useVariables;
|
||||
}
|
||||
|
||||
$tokens = $this->getTokens();
|
||||
$use = array();
|
||||
$state = 'start';
|
||||
|
||||
foreach ($tokens as &$token) {
|
||||
$is_array = is_array($token);
|
||||
|
||||
switch ($state) {
|
||||
case 'start':
|
||||
if ($is_array && $token[0] === T_USE) {
|
||||
$state = 'use';
|
||||
}
|
||||
break;
|
||||
case 'use':
|
||||
if ($is_array) {
|
||||
if ($token[0] === T_VARIABLE) {
|
||||
$use[] = substr($token[1], 1);
|
||||
}
|
||||
} elseif ($token == ')') {
|
||||
break 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use));
|
||||
|
||||
return $this->useVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* return bool
|
||||
*/
|
||||
public function isBindingRequired()
|
||||
{
|
||||
if($this->isBindingRequired === null){
|
||||
$this->getCode();
|
||||
}
|
||||
|
||||
return $this->isBindingRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* return bool
|
||||
*/
|
||||
public function isScopeRequired()
|
||||
{
|
||||
if($this->isScopeRequired === null){
|
||||
$this->getCode();
|
||||
}
|
||||
|
||||
return $this->isScopeRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getHashedFileName()
|
||||
{
|
||||
if ($this->hashedName === null) {
|
||||
$this->hashedName = sha1($this->getFileName());
|
||||
}
|
||||
|
||||
return $this->hashedName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileTokens()
|
||||
{
|
||||
$key = $this->getHashedFileName();
|
||||
|
||||
if (!isset(static::$files[$key])) {
|
||||
static::$files[$key] = token_get_all(file_get_contents($this->getFileName()));
|
||||
}
|
||||
|
||||
return static::$files[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens()
|
||||
{
|
||||
if ($this->tokens === null) {
|
||||
$tokens = $this->getFileTokens();
|
||||
$startLine = $this->getStartLine();
|
||||
$endLine = $this->getEndLine();
|
||||
$results = array();
|
||||
$start = false;
|
||||
|
||||
foreach ($tokens as &$token) {
|
||||
if (!is_array($token)) {
|
||||
if ($start) {
|
||||
$results[] = $token;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$line = $token[2];
|
||||
|
||||
if ($line <= $endLine) {
|
||||
if ($line >= $startLine) {
|
||||
$start = true;
|
||||
$results[] = $token;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$this->tokens = $results;
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getClasses()
|
||||
{
|
||||
$key = $this->getHashedFileName();
|
||||
|
||||
if (!isset(static::$classes[$key])) {
|
||||
$this->fetchItems();
|
||||
}
|
||||
|
||||
return static::$classes[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getFunctions()
|
||||
{
|
||||
$key = $this->getHashedFileName();
|
||||
|
||||
if (!isset(static::$functions[$key])) {
|
||||
$this->fetchItems();
|
||||
}
|
||||
|
||||
return static::$functions[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getConstants()
|
||||
{
|
||||
$key = $this->getHashedFileName();
|
||||
|
||||
if (!isset(static::$constants[$key])) {
|
||||
$this->fetchItems();
|
||||
}
|
||||
|
||||
return static::$constants[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getStructures()
|
||||
{
|
||||
$key = $this->getHashedFileName();
|
||||
|
||||
if (!isset(static::$structures[$key])) {
|
||||
$this->fetchItems();
|
||||
}
|
||||
|
||||
return static::$structures[$key];
|
||||
}
|
||||
|
||||
protected function fetchItems()
|
||||
{
|
||||
$key = $this->getHashedFileName();
|
||||
|
||||
$classes = array();
|
||||
$functions = array();
|
||||
$constants = array();
|
||||
$structures = array();
|
||||
$tokens = $this->getFileTokens();
|
||||
|
||||
$open = 0;
|
||||
$state = 'start';
|
||||
$lastState = '';
|
||||
$prefix = '';
|
||||
$name = '';
|
||||
$alias = '';
|
||||
$isFunc = $isConst = false;
|
||||
|
||||
$startLine = $endLine = 0;
|
||||
$structType = $structName = '';
|
||||
$structIgnore = false;
|
||||
|
||||
foreach ($tokens as $token) {
|
||||
|
||||
switch ($state) {
|
||||
case 'start':
|
||||
switch ($token[0]) {
|
||||
case T_CLASS:
|
||||
case T_INTERFACE:
|
||||
case T_TRAIT:
|
||||
$state = 'before_structure';
|
||||
$startLine = $token[2];
|
||||
$structType = $token[0] == T_CLASS
|
||||
? 'class'
|
||||
: ($token[0] == T_INTERFACE ? 'interface' : 'trait');
|
||||
break;
|
||||
case T_USE:
|
||||
$state = 'use';
|
||||
$prefix = $name = $alias = '';
|
||||
$isFunc = $isConst = false;
|
||||
break;
|
||||
case T_FUNCTION:
|
||||
$state = 'structure';
|
||||
$structIgnore = true;
|
||||
break;
|
||||
case T_NEW:
|
||||
$state = 'new';
|
||||
break;
|
||||
case T_OBJECT_OPERATOR:
|
||||
case T_DOUBLE_COLON:
|
||||
$state = 'invoke';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'use':
|
||||
switch ($token[0]) {
|
||||
case T_FUNCTION:
|
||||
$isFunc = true;
|
||||
break;
|
||||
case T_CONST:
|
||||
$isConst = true;
|
||||
break;
|
||||
case T_NS_SEPARATOR:
|
||||
$name .= $token[1];
|
||||
break;
|
||||
case T_STRING:
|
||||
$name .= $token[1];
|
||||
$alias = $token[1];
|
||||
break;
|
||||
case T_AS:
|
||||
$lastState = 'use';
|
||||
$state = 'alias';
|
||||
break;
|
||||
case '{':
|
||||
$prefix = $name;
|
||||
$name = $alias = '';
|
||||
$state = 'use-group';
|
||||
break;
|
||||
case ',':
|
||||
case ';':
|
||||
if ($name === '' || $name[0] !== '\\') {
|
||||
$name = '\\' . $name;
|
||||
}
|
||||
|
||||
if ($alias !== '') {
|
||||
if ($isFunc) {
|
||||
$functions[strtolower($alias)] = $name;
|
||||
} elseif ($isConst) {
|
||||
$constants[$alias] = $name;
|
||||
} else {
|
||||
$classes[strtolower($alias)] = $name;
|
||||
}
|
||||
}
|
||||
$name = $alias = '';
|
||||
$state = $token === ';' ? 'start' : 'use';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'use-group':
|
||||
switch ($token[0]) {
|
||||
case T_NS_SEPARATOR:
|
||||
$name .= $token[1];
|
||||
break;
|
||||
case T_STRING:
|
||||
$name .= $token[1];
|
||||
$alias = $token[1];
|
||||
break;
|
||||
case T_AS:
|
||||
$lastState = 'use-group';
|
||||
$state = 'alias';
|
||||
break;
|
||||
case ',':
|
||||
case '}':
|
||||
|
||||
if ($prefix === '' || $prefix[0] !== '\\') {
|
||||
$prefix = '\\' . $prefix;
|
||||
}
|
||||
|
||||
if ($alias !== '') {
|
||||
if ($isFunc) {
|
||||
$functions[strtolower($alias)] = $prefix . $name;
|
||||
} elseif ($isConst) {
|
||||
$constants[$alias] = $prefix . $name;
|
||||
} else {
|
||||
$classes[strtolower($alias)] = $prefix . $name;
|
||||
}
|
||||
}
|
||||
$name = $alias = '';
|
||||
$state = $token === '}' ? 'use' : 'use-group';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'alias':
|
||||
if ($token[0] === T_STRING) {
|
||||
$alias = $token[1];
|
||||
$state = $lastState;
|
||||
}
|
||||
break;
|
||||
case 'new':
|
||||
switch ($token[0]) {
|
||||
case T_WHITESPACE:
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
break 2;
|
||||
case T_CLASS:
|
||||
$state = 'structure';
|
||||
$structIgnore = true;
|
||||
break;
|
||||
default:
|
||||
$state = 'start';
|
||||
}
|
||||
break;
|
||||
case 'invoke':
|
||||
switch ($token[0]) {
|
||||
case T_WHITESPACE:
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
break 2;
|
||||
default:
|
||||
$state = 'start';
|
||||
}
|
||||
break;
|
||||
case 'before_structure':
|
||||
if ($token[0] == T_STRING) {
|
||||
$structName = $token[1];
|
||||
$state = 'structure';
|
||||
}
|
||||
break;
|
||||
case 'structure':
|
||||
switch ($token[0]) {
|
||||
case '{':
|
||||
case T_CURLY_OPEN:
|
||||
case T_DOLLAR_OPEN_CURLY_BRACES:
|
||||
case T_STRING_VARNAME:
|
||||
$open++;
|
||||
break;
|
||||
case '}':
|
||||
if (--$open == 0) {
|
||||
if(!$structIgnore){
|
||||
$structures[] = array(
|
||||
'type' => $structType,
|
||||
'name' => $structName,
|
||||
'start' => $startLine,
|
||||
'end' => $endLine,
|
||||
);
|
||||
}
|
||||
$structIgnore = false;
|
||||
$state = 'start';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (is_array($token)) {
|
||||
$endLine = $token[2];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static::$classes[$key] = $classes;
|
||||
static::$functions[$key] = $functions;
|
||||
static::$constants[$key] = $constants;
|
||||
static::$structures[$key] = $structures;
|
||||
}
|
||||
}
|
||||
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-2019 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-2019 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-2019 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;
|
||||
}
|
||||
}
|
||||
668
vendor/opis/closure/src/SerializableClosure.php
vendored
Normal file
668
vendor/opis/closure/src/SerializableClosure.php
vendored
Normal file
@@ -0,0 +1,668 @@
|
||||
<?php
|
||||
/* ===========================================================================
|
||||
* Copyright (c) 2018-2019 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);
|
||||
$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;
|
||||
}
|
||||
} elseif($reflector->isScopeRequired()) {
|
||||
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;
|
||||
}
|
||||
|
||||
if ($this->code['scope'] !== null || $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);
|
||||
$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);
|
||||
$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);
|
||||
$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);
|
||||
$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