diff options
author | Côme Chilliet <91878298+come-nc@users.noreply.github.com> | 2022-06-21 14:11:54 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-21 14:11:54 +0300 |
commit | eda7f53c14e153a31a8b70d752f43325025db098 (patch) | |
tree | a1a88e1c77181130c10c922e866b4d2d3c38b15a | |
parent | 70e442d437625996457bb36431fc14f288d4640d (diff) | |
parent | b5f73e95a36edde3bf36bea8c72204692af1a0b5 (diff) |
Merge pull request #1080 from nextcloud/fix/replace-opis-closure-by-laravel-fork
Migrate from opis/closure to laravel/serializable-closure
26 files changed, 2724 insertions, 385 deletions
diff --git a/composer.json b/composer.json index 06239c4d..0099fa05 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "guzzlehttp/guzzle": "^7.4.0", "icewind/searchdav": "^3.0", "icewind/streams": "v0.7.5", + "laravel/serializable-closure": "^1.2", "mexitek/phpcolors": "^1.0", "microsoft/azure-storage-blob": "^1.5", "nextcloud/lognormalizer": "^1.0", diff --git a/composer.lock b/composer.lock index 2bc2ff84..0e643768 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b0f529d60a781dfe43ba422f58e294aa", + "content-hash": "0ac4f55294fd40eceec3134a252cfc24", "packages": [ { "name": "aws/aws-sdk-php", @@ -1765,6 +1765,65 @@ "time": "2020-05-27T16:41:55+00:00" }, { + "name": "laravel/serializable-closure", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "09f0e9fb61829f628205b7c94906c28740ff9540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/09f0e9fb61829f628205b7c94906c28740ff9540", + "reference": "09f0e9fb61829f628205b7c94906c28740ff9540", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.18", + "phpstan/phpstan": "^0.12.98", + "symfony/var-dumper": "^5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2022-05-16T17:09:47+00:00" + }, + { "name": "league/uri", "version": "6.4.0", "source": { @@ -2250,16 +2309,16 @@ }, { "name": "opis/closure", - "version": "3.6.2", + "version": "3.6.3", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6" + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6", - "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6", + "url": "https://api.github.com/repos/opis/closure/zipball/3d81e4309d2a927abbe66df935f4bb60082805ad", + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad", "shasum": "" }, "require": { @@ -2276,12 +2335,12 @@ } }, "autoload": { - "psr-4": { - "Opis\\Closure\\": "src/" - }, "files": [ "functions.php" - ] + ], + "psr-4": { + "Opis\\Closure\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2309,9 +2368,9 @@ ], "support": { "issues": "https://github.com/opis/closure/issues", - "source": "https://github.com/opis/closure/tree/3.6.2" + "source": "https://github.com/opis/closure/tree/3.6.3" }, - "time": "2021-04-09T13:42:10+00:00" + "time": "2022-01-27T09:35:39+00:00" }, { "name": "pear/archive_tar", diff --git a/composer/InstalledVersions.php b/composer/InstalledVersions.php index 41bc143c..c6b54af7 100644 --- a/composer/InstalledVersions.php +++ b/composer/InstalledVersions.php @@ -28,7 +28,7 @@ class InstalledVersions { /** * @var mixed[]|null - * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null */ private static $installed; @@ -39,7 +39,7 @@ class InstalledVersions /** * @var array[] - * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> + * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> */ private static $installedByVendor = array(); @@ -243,7 +243,7 @@ class InstalledVersions /** * @return array - * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} */ public static function getRootPackage() { @@ -257,7 +257,7 @@ class InstalledVersions * * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @return array[] - * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} */ public static function getRawData() { @@ -280,7 +280,7 @@ class InstalledVersions * Returns the raw data of all installed.php which are currently loaded for custom implementations * * @return array[] - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> + * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> */ public static function getAllRawData() { @@ -303,7 +303,7 @@ class InstalledVersions * @param array[] $data A vendor/composer/installed.php data set * @return void * - * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data */ public static function reload($data) { @@ -313,7 +313,7 @@ class InstalledVersions /** * @return array[] - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> + * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> */ private static function getInstalled() { diff --git a/composer/autoload_classmap.php b/composer/autoload_classmap.php index b2a945b9..b5499d8c 100644 --- a/composer/autoload_classmap.php +++ b/composer/autoload_classmap.php @@ -1515,6 +1515,19 @@ return array( 'JsonSchema\\Uri\\UriResolver' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/UriResolver.php', 'JsonSchema\\Uri\\UriRetriever' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php', 'JsonSchema\\Validator' => $vendorDir . '/justinrainbow/json-schema/src/JsonSchema/Validator.php', + 'Laravel\\SerializableClosure\\Contracts\\Serializable' => $vendorDir . '/laravel/serializable-closure/src/Contracts/Serializable.php', + 'Laravel\\SerializableClosure\\Contracts\\Signer' => $vendorDir . '/laravel/serializable-closure/src/Contracts/Signer.php', + 'Laravel\\SerializableClosure\\Exceptions\\InvalidSignatureException' => $vendorDir . '/laravel/serializable-closure/src/Exceptions/InvalidSignatureException.php', + 'Laravel\\SerializableClosure\\Exceptions\\MissingSecretKeyException' => $vendorDir . '/laravel/serializable-closure/src/Exceptions/MissingSecretKeyException.php', + 'Laravel\\SerializableClosure\\Exceptions\\PhpVersionNotSupportedException' => $vendorDir . '/laravel/serializable-closure/src/Exceptions/PhpVersionNotSupportedException.php', + 'Laravel\\SerializableClosure\\SerializableClosure' => $vendorDir . '/laravel/serializable-closure/src/SerializableClosure.php', + 'Laravel\\SerializableClosure\\Serializers\\Native' => $vendorDir . '/laravel/serializable-closure/src/Serializers/Native.php', + 'Laravel\\SerializableClosure\\Serializers\\Signed' => $vendorDir . '/laravel/serializable-closure/src/Serializers/Signed.php', + 'Laravel\\SerializableClosure\\Signers\\Hmac' => $vendorDir . '/laravel/serializable-closure/src/Signers/Hmac.php', + 'Laravel\\SerializableClosure\\Support\\ClosureScope' => $vendorDir . '/laravel/serializable-closure/src/Support/ClosureScope.php', + 'Laravel\\SerializableClosure\\Support\\ClosureStream' => $vendorDir . '/laravel/serializable-closure/src/Support/ClosureStream.php', + 'Laravel\\SerializableClosure\\Support\\ReflectionClosure' => $vendorDir . '/laravel/serializable-closure/src/Support/ReflectionClosure.php', + 'Laravel\\SerializableClosure\\Support\\SelfReference' => $vendorDir . '/laravel/serializable-closure/src/Support/SelfReference.php', 'League\\Uri\\Contracts\\AuthorityInterface' => $vendorDir . '/league/uri-interfaces/src/Contracts/AuthorityInterface.php', 'League\\Uri\\Contracts\\DataPathInterface' => $vendorDir . '/league/uri-interfaces/src/Contracts/DataPathInterface.php', 'League\\Uri\\Contracts\\DomainHostInterface' => $vendorDir . '/league/uri-interfaces/src/Contracts/DomainHostInterface.php', diff --git a/composer/autoload_psr4.php b/composer/autoload_psr4.php index 518c268b..64242249 100644 --- a/composer/autoload_psr4.php +++ b/composer/autoload_psr4.php @@ -60,6 +60,7 @@ return array( 'MicrosoftAzure\\Storage\\Common\\' => array($vendorDir . '/microsoft/azure-storage-common/src/Common'), 'MicrosoftAzure\\Storage\\Blob\\' => array($vendorDir . '/microsoft/azure-storage-blob/src/Blob'), 'League\\Uri\\' => array($vendorDir . '/league/uri/src', $vendorDir . '/league/uri-interfaces/src'), + 'Laravel\\SerializableClosure\\' => array($vendorDir . '/laravel/serializable-closure/src'), 'JsonSchema\\' => array($vendorDir . '/justinrainbow/json-schema/src/JsonSchema'), 'JmesPath\\' => array($vendorDir . '/mtdowling/jmespath.php/src'), 'Icewind\\Streams\\' => array($vendorDir . '/icewind/streams/src'), diff --git a/composer/autoload_static.php b/composer/autoload_static.php index c79fca14..43ff4254 100644 --- a/composer/autoload_static.php +++ b/composer/autoload_static.php @@ -222,6 +222,7 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652 'L' => array ( 'League\\Uri\\' => 11, + 'Laravel\\SerializableClosure\\' => 28, ), 'J' => array ( @@ -502,6 +503,10 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652 0 => __DIR__ . '/..' . '/league/uri/src', 1 => __DIR__ . '/..' . '/league/uri-interfaces/src', ), + 'Laravel\\SerializableClosure\\' => + array ( + 0 => __DIR__ . '/..' . '/laravel/serializable-closure/src', + ), 'JsonSchema\\' => array ( 0 => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema', @@ -2146,6 +2151,19 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652 'JsonSchema\\Uri\\UriResolver' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/UriResolver.php', 'JsonSchema\\Uri\\UriRetriever' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php', 'JsonSchema\\Validator' => __DIR__ . '/..' . '/justinrainbow/json-schema/src/JsonSchema/Validator.php', + 'Laravel\\SerializableClosure\\Contracts\\Serializable' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Contracts/Serializable.php', + 'Laravel\\SerializableClosure\\Contracts\\Signer' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Contracts/Signer.php', + 'Laravel\\SerializableClosure\\Exceptions\\InvalidSignatureException' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Exceptions/InvalidSignatureException.php', + 'Laravel\\SerializableClosure\\Exceptions\\MissingSecretKeyException' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Exceptions/MissingSecretKeyException.php', + 'Laravel\\SerializableClosure\\Exceptions\\PhpVersionNotSupportedException' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Exceptions/PhpVersionNotSupportedException.php', + 'Laravel\\SerializableClosure\\SerializableClosure' => __DIR__ . '/..' . '/laravel/serializable-closure/src/SerializableClosure.php', + 'Laravel\\SerializableClosure\\Serializers\\Native' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Serializers/Native.php', + 'Laravel\\SerializableClosure\\Serializers\\Signed' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Serializers/Signed.php', + 'Laravel\\SerializableClosure\\Signers\\Hmac' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Signers/Hmac.php', + 'Laravel\\SerializableClosure\\Support\\ClosureScope' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Support/ClosureScope.php', + 'Laravel\\SerializableClosure\\Support\\ClosureStream' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Support/ClosureStream.php', + 'Laravel\\SerializableClosure\\Support\\ReflectionClosure' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Support/ReflectionClosure.php', + 'Laravel\\SerializableClosure\\Support\\SelfReference' => __DIR__ . '/..' . '/laravel/serializable-closure/src/Support/SelfReference.php', 'League\\Uri\\Contracts\\AuthorityInterface' => __DIR__ . '/..' . '/league/uri-interfaces/src/Contracts/AuthorityInterface.php', 'League\\Uri\\Contracts\\DataPathInterface' => __DIR__ . '/..' . '/league/uri-interfaces/src/Contracts/DataPathInterface.php', 'League\\Uri\\Contracts\\DomainHostInterface' => __DIR__ . '/..' . '/league/uri-interfaces/src/Contracts/DomainHostInterface.php', diff --git a/composer/installed.json b/composer/installed.json index 8678072d..dd513ba3 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -1834,6 +1834,68 @@ "install-path": "../justinrainbow/json-schema" }, { + "name": "laravel/serializable-closure", + "version": "v1.2.0", + "version_normalized": "1.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "09f0e9fb61829f628205b7c94906c28740ff9540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/09f0e9fb61829f628205b7c94906c28740ff9540", + "reference": "09f0e9fb61829f628205b7c94906c28740ff9540", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.18", + "phpstan/phpstan": "^0.12.98", + "symfony/var-dumper": "^5.3" + }, + "time": "2022-05-16T17:09:47+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "install-path": "../laravel/serializable-closure" + }, + { "name": "league/uri", "version": "6.4.0", "version_normalized": "6.4.0.0", @@ -2343,17 +2405,17 @@ }, { "name": "opis/closure", - "version": "3.6.2", - "version_normalized": "3.6.2.0", + "version": "3.6.3", + "version_normalized": "3.6.3.0", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6" + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6", - "reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6", + "url": "https://api.github.com/repos/opis/closure/zipball/3d81e4309d2a927abbe66df935f4bb60082805ad", + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad", "shasum": "" }, "require": { @@ -2363,7 +2425,7 @@ "jeremeamia/superclosure": "^2.0", "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, - "time": "2021-04-09T13:42:10+00:00", + "time": "2022-01-27T09:35:39+00:00", "type": "library", "extra": { "branch-alias": { @@ -2372,12 +2434,12 @@ }, "installation-source": "dist", "autoload": { - "psr-4": { - "Opis\\Closure\\": "src/" - }, "files": [ "functions.php" - ] + ], + "psr-4": { + "Opis\\Closure\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2405,7 +2467,7 @@ ], "support": { "issues": "https://github.com/opis/closure/issues", - "source": "https://github.com/opis/closure/tree/3.6.2" + "source": "https://github.com/opis/closure/tree/3.6.3" }, "install-path": "../opis/closure" }, @@ -6428,6 +6490,6 @@ "install-path": "../web-auth/webauthn-lib" } ], - "dev": true, + "dev": false, "dev-package-names": [] } diff --git a/composer/installed.php b/composer/installed.php index fc14425a..71d8bbf2 100644 --- a/composer/installed.php +++ b/composer/installed.php @@ -1,319 +1,328 @@ <?php return array( 'root' => array( + 'name' => 'nextcloud/3rdparty', 'pretty_version' => 'dev-master', 'version' => 'dev-master', + 'reference' => '02403021310540a848eb2385e979fcc0563ee730', 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => '59f4851dc2729f449d4a9e6fb211bebe3818cb6f', - 'name' => 'nextcloud/3rdparty', - 'dev' => true, + 'dev' => false, ), 'versions' => array( 'aws/aws-sdk-php' => array( 'pretty_version' => '3.184.6', 'version' => '3.184.6.0', + 'reference' => '0b7187c96ced465d400ad9427157e05ddee68edc', 'type' => 'library', 'install_path' => __DIR__ . '/../aws/aws-sdk-php', 'aliases' => array(), - 'reference' => '0b7187c96ced465d400ad9427157e05ddee68edc', 'dev_requirement' => false, ), 'bantu/ini-get-wrapper' => array( 'pretty_version' => 'v1.0.1', 'version' => '1.0.1.0', + 'reference' => '4770c7feab370c62e23db4f31c112b7c6d90aee2', 'type' => 'library', 'install_path' => __DIR__ . '/../bantu/ini-get-wrapper', 'aliases' => array(), - 'reference' => '4770c7feab370c62e23db4f31c112b7c6d90aee2', 'dev_requirement' => false, ), 'beberlei/assert' => array( 'pretty_version' => 'v3.3.1', 'version' => '3.3.1.0', + 'reference' => '5e721d7e937ca3ba2cdec1e1adf195f9e5188372', 'type' => 'library', 'install_path' => __DIR__ . '/../beberlei/assert', 'aliases' => array(), - 'reference' => '5e721d7e937ca3ba2cdec1e1adf195f9e5188372', 'dev_requirement' => false, ), 'brick/math' => array( 'pretty_version' => '0.9.2', 'version' => '0.9.2.0', + 'reference' => 'dff976c2f3487d42c1db75a3b180e2b9f0e72ce0', 'type' => 'library', 'install_path' => __DIR__ . '/../brick/math', 'aliases' => array(), - 'reference' => 'dff976c2f3487d42c1db75a3b180e2b9f0e72ce0', 'dev_requirement' => false, ), 'christophwurst/id3parser' => array( 'pretty_version' => 'v0.1.4', 'version' => '0.1.4.0', + 'reference' => '050c9d81ea89b0cf53e23a27efc4e1840f9ab260', 'type' => 'library', 'install_path' => __DIR__ . '/../christophwurst/id3parser', 'aliases' => array(), - 'reference' => '050c9d81ea89b0cf53e23a27efc4e1840f9ab260', 'dev_requirement' => false, ), 'composer/package-versions-deprecated' => array( 'pretty_version' => '1.11.99.4', 'version' => '1.11.99.4', + 'reference' => 'b174585d1fe49ceed21928a945138948cb394600', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/./package-versions-deprecated', 'aliases' => array(), - 'reference' => 'b174585d1fe49ceed21928a945138948cb394600', 'dev_requirement' => false, ), 'cweagans/composer-patches' => array( 'pretty_version' => '1.7.1', 'version' => '1.7.1.0', + 'reference' => '9888dcc74993c030b75f3dd548bb5e20cdbd740c', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../cweagans/composer-patches', 'aliases' => array(), - 'reference' => '9888dcc74993c030b75f3dd548bb5e20cdbd740c', 'dev_requirement' => false, ), 'deepdiver/zipstreamer' => array( 'pretty_version' => '2.0.0', 'version' => '2.0.0.0', + 'reference' => 'b8c59647ff34fb97e8937aefb2a65de2bc4b4755', 'type' => 'library', 'install_path' => __DIR__ . '/../deepdiver/zipstreamer', 'aliases' => array(), - 'reference' => 'b8c59647ff34fb97e8937aefb2a65de2bc4b4755', 'dev_requirement' => false, ), 'deepdiver1975/tarstreamer' => array( 'pretty_version' => '2.0.0', 'version' => '2.0.0.0', + 'reference' => 'ad48505d1ab54a8e94e6b1cc5297bbed72e956de', 'type' => 'library', 'install_path' => __DIR__ . '/../deepdiver1975/tarstreamer', 'aliases' => array(), - 'reference' => 'ad48505d1ab54a8e94e6b1cc5297bbed72e956de', 'dev_requirement' => false, ), 'doctrine/cache' => array( 'pretty_version' => '2.1.1', 'version' => '2.1.1.0', + 'reference' => '331b4d5dbaeab3827976273e9356b3b453c300ce', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/cache', 'aliases' => array(), - 'reference' => '331b4d5dbaeab3827976273e9356b3b453c300ce', 'dev_requirement' => false, ), 'doctrine/dbal' => array( 'pretty_version' => '3.1.4', 'version' => '3.1.4.0', + 'reference' => '821b4f01a36ce63ed36c090ea74767b72db367e9', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/dbal', 'aliases' => array(), - 'reference' => '821b4f01a36ce63ed36c090ea74767b72db367e9', 'dev_requirement' => false, ), 'doctrine/deprecations' => array( 'pretty_version' => 'v0.5.3', 'version' => '0.5.3.0', + 'reference' => '9504165960a1f83cc1480e2be1dd0a0478561314', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/deprecations', 'aliases' => array(), - 'reference' => '9504165960a1f83cc1480e2be1dd0a0478561314', 'dev_requirement' => false, ), 'doctrine/event-manager' => array( 'pretty_version' => '1.1.1', 'version' => '1.1.1.0', + 'reference' => '41370af6a30faa9dc0368c4a6814d596e81aba7f', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/event-manager', 'aliases' => array(), - 'reference' => '41370af6a30faa9dc0368c4a6814d596e81aba7f', 'dev_requirement' => false, ), 'doctrine/lexer' => array( 'pretty_version' => '1.2.1', 'version' => '1.2.1.0', + 'reference' => 'e864bbf5904cb8f5bb334f99209b48018522f042', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/lexer', 'aliases' => array(), - 'reference' => 'e864bbf5904cb8f5bb334f99209b48018522f042', 'dev_requirement' => false, ), 'egulias/email-validator' => array( 'pretty_version' => '3.1.1', 'version' => '3.1.1.0', + 'reference' => 'c81f18a3efb941d8c4d2e025f6183b5c6d697307', 'type' => 'library', 'install_path' => __DIR__ . '/../egulias/email-validator', 'aliases' => array(), - 'reference' => 'c81f18a3efb941d8c4d2e025f6183b5c6d697307', 'dev_requirement' => false, ), 'fgrosse/phpasn1' => array( 'pretty_version' => 'v2.3.0', 'version' => '2.3.0.0', + 'reference' => '20299033c35f4300eb656e7e8e88cf52d1d6694e', 'type' => 'library', 'install_path' => __DIR__ . '/../fgrosse/phpasn1', 'aliases' => array(), - 'reference' => '20299033c35f4300eb656e7e8e88cf52d1d6694e', 'dev_requirement' => false, ), 'giggsey/libphonenumber-for-php' => array( 'pretty_version' => '8.12.38', 'version' => '8.12.38.0', + 'reference' => '0a6293c57de9256f4bd0d673280fbfbfd1e47533', 'type' => 'library', 'install_path' => __DIR__ . '/../giggsey/libphonenumber-for-php', 'aliases' => array(), - 'reference' => '0a6293c57de9256f4bd0d673280fbfbfd1e47533', 'dev_requirement' => false, ), 'giggsey/locale' => array( 'pretty_version' => '2.1', 'version' => '2.1.0.0', + 'reference' => '8d324583b5899e6280a875c43bf1fc9658bc6962', 'type' => 'library', 'install_path' => __DIR__ . '/../giggsey/locale', 'aliases' => array(), - 'reference' => '8d324583b5899e6280a875c43bf1fc9658bc6962', 'dev_requirement' => false, ), 'guzzlehttp/guzzle' => array( 'pretty_version' => '7.4.0', 'version' => '7.4.0.0', + 'reference' => '868b3571a039f0ebc11ac8f344f4080babe2cb94', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', 'aliases' => array(), - 'reference' => '868b3571a039f0ebc11ac8f344f4080babe2cb94', 'dev_requirement' => false, ), 'guzzlehttp/promises' => array( 'pretty_version' => '1.5.1', 'version' => '1.5.1.0', + 'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/promises', 'aliases' => array(), - 'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da', 'dev_requirement' => false, ), 'guzzlehttp/psr7' => array( 'pretty_version' => '1.8.5', 'version' => '1.8.5.0', + 'reference' => '337e3ad8e5716c15f9657bd214d16cc5e69df268', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'aliases' => array(), - 'reference' => '337e3ad8e5716c15f9657bd214d16cc5e69df268', 'dev_requirement' => false, ), 'guzzlehttp/uri-template' => array( 'pretty_version' => 'v0.2.0', 'version' => '0.2.0.0', + 'reference' => 'db46525d6d8fee71033b73cc07160f3e5271a8ce', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/uri-template', 'aliases' => array(), - 'reference' => 'db46525d6d8fee71033b73cc07160f3e5271a8ce', 'dev_requirement' => false, ), 'icewind/searchdav' => array( 'pretty_version' => 'v3.0.1', 'version' => '3.0.1.0', + 'reference' => '52c8cfc21bd69271f224671c4924d260b0a8d4fb', 'type' => 'library', 'install_path' => __DIR__ . '/../icewind/searchdav', 'aliases' => array(), - 'reference' => '52c8cfc21bd69271f224671c4924d260b0a8d4fb', 'dev_requirement' => false, ), 'icewind/streams' => array( 'pretty_version' => 'v0.7.5', 'version' => '0.7.5.0', + 'reference' => '0c6aae16ebdadb257f0bd089c1e1e4cf5e20ddc2', 'type' => 'library', 'install_path' => __DIR__ . '/../icewind/streams', 'aliases' => array(), - 'reference' => '0c6aae16ebdadb257f0bd089c1e1e4cf5e20ddc2', 'dev_requirement' => false, ), 'justinrainbow/json-schema' => array( 'pretty_version' => '5.2.10', 'version' => '5.2.10.0', + 'reference' => '2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b', 'type' => 'library', 'install_path' => __DIR__ . '/../justinrainbow/json-schema', 'aliases' => array(), - 'reference' => '2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b', + 'dev_requirement' => false, + ), + 'laravel/serializable-closure' => array( + 'pretty_version' => 'v1.2.0', + 'version' => '1.2.0.0', + 'reference' => '09f0e9fb61829f628205b7c94906c28740ff9540', + 'type' => 'library', + 'install_path' => __DIR__ . '/../laravel/serializable-closure', + 'aliases' => array(), 'dev_requirement' => false, ), 'league/uri' => array( 'pretty_version' => '6.4.0', 'version' => '6.4.0.0', + 'reference' => '09da64118eaf4c5d52f9923a1e6a5be1da52fd9a', 'type' => 'library', 'install_path' => __DIR__ . '/../league/uri', 'aliases' => array(), - 'reference' => '09da64118eaf4c5d52f9923a1e6a5be1da52fd9a', 'dev_requirement' => false, ), 'league/uri-interfaces' => array( 'pretty_version' => '2.2.0', 'version' => '2.2.0.0', + 'reference' => '667f150e589d65d79c89ffe662e426704f84224f', 'type' => 'library', 'install_path' => __DIR__ . '/../league/uri-interfaces', 'aliases' => array(), - 'reference' => '667f150e589d65d79c89ffe662e426704f84224f', 'dev_requirement' => false, ), 'mexitek/phpcolors' => array( 'pretty_version' => 'v1.0.4', 'version' => '1.0.4.0', + 'reference' => '4043974240ca7dc3c2bec3c158588148b605b206', 'type' => 'library', 'install_path' => __DIR__ . '/../mexitek/phpcolors', 'aliases' => array(), - 'reference' => '4043974240ca7dc3c2bec3c158588148b605b206', 'dev_requirement' => false, ), 'microsoft/azure-storage-blob' => array( 'pretty_version' => '1.5.2', 'version' => '1.5.2.0', + 'reference' => '2475330963372d519387cb8135d6a9cfd42272da', 'type' => 'library', 'install_path' => __DIR__ . '/../microsoft/azure-storage-blob', 'aliases' => array(), - 'reference' => '2475330963372d519387cb8135d6a9cfd42272da', 'dev_requirement' => false, ), 'microsoft/azure-storage-common' => array( 'pretty_version' => '1.5.1', 'version' => '1.5.1.0', + 'reference' => 'e5738035891546075bd369954e8af121d65ebd6d', 'type' => 'library', 'install_path' => __DIR__ . '/../microsoft/azure-storage-common', 'aliases' => array(), - 'reference' => 'e5738035891546075bd369954e8af121d65ebd6d', 'dev_requirement' => false, ), 'mtdowling/jmespath.php' => array( 'pretty_version' => '2.6.1', 'version' => '2.6.1.0', + 'reference' => '9b87907a81b87bc76d19a7fb2d61e61486ee9edb', 'type' => 'library', 'install_path' => __DIR__ . '/../mtdowling/jmespath.php', 'aliases' => array(), - 'reference' => '9b87907a81b87bc76d19a7fb2d61e61486ee9edb', 'dev_requirement' => false, ), 'nextcloud/3rdparty' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', + 'reference' => '02403021310540a848eb2385e979fcc0563ee730', 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => '59f4851dc2729f449d4a9e6fb211bebe3818cb6f', 'dev_requirement' => false, ), 'nextcloud/lognormalizer' => array( 'pretty_version' => 'v1.0.0', 'version' => '1.0.0.0', + 'reference' => '87445d69225c247aaff64643b1fc83c6d6df741f', 'type' => 'library', 'install_path' => __DIR__ . '/../nextcloud/lognormalizer', 'aliases' => array(), - 'reference' => '87445d69225c247aaff64643b1fc83c6d6df741f', 'dev_requirement' => false, ), 'nikic/php-parser' => array( 'pretty_version' => 'v4.10.5', 'version' => '4.10.5.0', + 'reference' => '4432ba399e47c66624bc73c8c0f811e5c109576f', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), - 'reference' => '4432ba399e47c66624bc73c8c0f811e5c109576f', 'dev_requirement' => false, ), 'ocramius/package-versions' => array( @@ -323,57 +332,57 @@ ), ), 'opis/closure' => array( - 'pretty_version' => '3.6.2', - 'version' => '3.6.2.0', + 'pretty_version' => '3.6.3', + 'version' => '3.6.3.0', + 'reference' => '3d81e4309d2a927abbe66df935f4bb60082805ad', 'type' => 'library', 'install_path' => __DIR__ . '/../opis/closure', 'aliases' => array(), - 'reference' => '06e2ebd25f2869e54a306dda991f7db58066f7f6', 'dev_requirement' => false, ), 'pear/archive_tar' => array( 'pretty_version' => '1.4.14', 'version' => '1.4.14.0', + 'reference' => '4d761c5334c790e45ef3245f0864b8955c562caa', 'type' => 'library', 'install_path' => __DIR__ . '/../pear/archive_tar', 'aliases' => array(), - 'reference' => '4d761c5334c790e45ef3245f0864b8955c562caa', 'dev_requirement' => false, ), 'pear/console_getopt' => array( 'pretty_version' => 'v1.4.3', 'version' => '1.4.3.0', + 'reference' => 'a41f8d3e668987609178c7c4a9fe48fecac53fa0', 'type' => 'library', 'install_path' => __DIR__ . '/../pear/console_getopt', 'aliases' => array(), - 'reference' => 'a41f8d3e668987609178c7c4a9fe48fecac53fa0', 'dev_requirement' => false, ), 'pear/pear-core-minimal' => array( 'pretty_version' => 'v1.10.10', 'version' => '1.10.10.0', + 'reference' => '625a3c429d9b2c1546438679074cac1b089116a7', 'type' => 'library', 'install_path' => __DIR__ . '/../pear/pear-core-minimal', 'aliases' => array(), - 'reference' => '625a3c429d9b2c1546438679074cac1b089116a7', 'dev_requirement' => false, ), 'pear/pear_exception' => array( 'pretty_version' => 'v1.0.2', 'version' => '1.0.2.0', + 'reference' => 'b14fbe2ddb0b9f94f5b24cf08783d599f776fff0', 'type' => 'class', 'install_path' => __DIR__ . '/../pear/pear_exception', 'aliases' => array(), - 'reference' => 'b14fbe2ddb0b9f94f5b24cf08783d599f776fff0', 'dev_requirement' => false, ), 'php-ds/php-ds' => array( 'pretty_version' => 'v1.3.0', 'version' => '1.3.0.0', + 'reference' => 'b98396862fb8a13cbdbbaf4d18be28ee5c01ed3c', 'type' => 'library', 'install_path' => __DIR__ . '/../php-ds/php-ds', 'aliases' => array(), - 'reference' => 'b98396862fb8a13cbdbbaf4d18be28ee5c01ed3c', 'dev_requirement' => false, ), 'php-http/async-client-implementation' => array( @@ -391,73 +400,73 @@ 'php-http/guzzle7-adapter' => array( 'pretty_version' => '1.0.0', 'version' => '1.0.0.0', + 'reference' => 'fb075a71dbfa4847cf0c2938c4e5a9c478ef8b01', 'type' => 'library', 'install_path' => __DIR__ . '/../php-http/guzzle7-adapter', 'aliases' => array(), - 'reference' => 'fb075a71dbfa4847cf0c2938c4e5a9c478ef8b01', 'dev_requirement' => false, ), 'php-http/httplug' => array( 'pretty_version' => '2.2.0', 'version' => '2.2.0.0', + 'reference' => '191a0a1b41ed026b717421931f8d3bd2514ffbf9', 'type' => 'library', 'install_path' => __DIR__ . '/../php-http/httplug', 'aliases' => array(), - 'reference' => '191a0a1b41ed026b717421931f8d3bd2514ffbf9', 'dev_requirement' => false, ), 'php-http/promise' => array( 'pretty_version' => '1.1.0', 'version' => '1.1.0.0', + 'reference' => '4c4c1f9b7289a2ec57cde7f1e9762a5789506f88', 'type' => 'library', 'install_path' => __DIR__ . '/../php-http/promise', 'aliases' => array(), - 'reference' => '4c4c1f9b7289a2ec57cde7f1e9762a5789506f88', 'dev_requirement' => false, ), 'php-opencloud/openstack' => array( 'pretty_version' => 'v3.1.0', 'version' => '3.1.0.0', + 'reference' => '7b0eeb63defe533fb802514af3c70855c45eaf1e', 'type' => 'library', 'install_path' => __DIR__ . '/../php-opencloud/openstack', 'aliases' => array(), - 'reference' => '7b0eeb63defe533fb802514af3c70855c45eaf1e', 'dev_requirement' => false, ), 'phpseclib/phpseclib' => array( 'pretty_version' => '2.0.32', 'version' => '2.0.32.0', + 'reference' => 'f5c4c19880d45d0be3e7d24ae8ac434844a898cd', 'type' => 'library', 'install_path' => __DIR__ . '/../phpseclib/phpseclib', 'aliases' => array(), - 'reference' => 'f5c4c19880d45d0be3e7d24ae8ac434844a898cd', 'dev_requirement' => false, ), 'pimple/pimple' => array( 'pretty_version' => 'v3.5.0', 'version' => '3.5.0.0', + 'reference' => 'a94b3a4db7fb774b3d78dad2315ddc07629e1bed', 'type' => 'library', 'install_path' => __DIR__ . '/../pimple/pimple', 'aliases' => array(), - 'reference' => 'a94b3a4db7fb774b3d78dad2315ddc07629e1bed', 'dev_requirement' => false, ), 'psr/container' => array( 'pretty_version' => '1.1.1', 'version' => '1.1.1.0', + 'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), - 'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf', 'dev_requirement' => false, ), 'psr/event-dispatcher' => array( 'pretty_version' => '1.0.0', 'version' => '1.0.0.0', + 'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/event-dispatcher', 'aliases' => array(), - 'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0', 'dev_requirement' => false, ), 'psr/event-dispatcher-implementation' => array( @@ -469,10 +478,10 @@ 'psr/http-client' => array( 'pretty_version' => '1.0.1', 'version' => '1.0.1.0', + 'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-client', 'aliases' => array(), - 'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621', 'dev_requirement' => false, ), 'psr/http-client-implementation' => array( @@ -484,19 +493,19 @@ 'psr/http-factory' => array( 'pretty_version' => '1.0.1', 'version' => '1.0.1.0', + 'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-factory', 'aliases' => array(), - 'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be', 'dev_requirement' => false, ), 'psr/http-message' => array( 'pretty_version' => '1.0.1', 'version' => '1.0.1.0', + 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-message', 'aliases' => array(), - 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', 'dev_requirement' => false, ), 'psr/http-message-implementation' => array( @@ -508,10 +517,10 @@ 'psr/log' => array( 'pretty_version' => '1.1.4', 'version' => '1.1.4.0', + 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/log', 'aliases' => array(), - 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', 'dev_requirement' => false, ), 'psr/log-implementation' => array( @@ -535,37 +544,37 @@ 'punic/punic' => array( 'pretty_version' => '1.6.5', 'version' => '1.6.5.0', + 'reference' => '7bc85ce1137cf52db4d2a6298256a4c4a24da99a', 'type' => 'library', 'install_path' => __DIR__ . '/../punic/punic', 'aliases' => array(), - 'reference' => '7bc85ce1137cf52db4d2a6298256a4c4a24da99a', 'dev_requirement' => false, ), 'ralouphie/getallheaders' => array( 'pretty_version' => '3.0.3', 'version' => '3.0.3.0', + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', 'type' => 'library', 'install_path' => __DIR__ . '/../ralouphie/getallheaders', 'aliases' => array(), - 'reference' => '120b605dfeb996808c31b6477290a714d356e822', 'dev_requirement' => false, ), 'ramsey/collection' => array( 'pretty_version' => '1.1.3', 'version' => '1.1.3.0', + 'reference' => '28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1', 'type' => 'library', 'install_path' => __DIR__ . '/../ramsey/collection', 'aliases' => array(), - 'reference' => '28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1', 'dev_requirement' => false, ), 'ramsey/uuid' => array( 'pretty_version' => '4.1.1', 'version' => '4.1.1.0', + 'reference' => 'cd4032040a750077205918c86049aa0f43d22947', 'type' => 'library', 'install_path' => __DIR__ . '/../ramsey/uuid', 'aliases' => array(), - 'reference' => 'cd4032040a750077205918c86049aa0f43d22947', 'dev_requirement' => false, ), 'rhumsaa/uuid' => array( @@ -583,136 +592,136 @@ 'sabre/dav' => array( 'pretty_version' => '4.2.1', 'version' => '4.2.1.0', + 'reference' => '5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/dav', 'aliases' => array(), - 'reference' => '5e651f9ddc2b05745f5b28cd697c8e8c6a0b6146', 'dev_requirement' => false, ), 'sabre/event' => array( 'pretty_version' => '5.1.4', 'version' => '5.1.4.0', + 'reference' => 'd7da22897125d34d7eddf7977758191c06a74497', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/event', 'aliases' => array(), - 'reference' => 'd7da22897125d34d7eddf7977758191c06a74497', 'dev_requirement' => false, ), 'sabre/http' => array( 'pretty_version' => '5.1.3', 'version' => '5.1.3.0', + 'reference' => '315f592adfcba8aeb73c2fd64285205747acbbd7', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/http', 'aliases' => array(), - 'reference' => '315f592adfcba8aeb73c2fd64285205747acbbd7', 'dev_requirement' => false, ), 'sabre/uri' => array( 'pretty_version' => '2.2.2', 'version' => '2.2.2.0', + 'reference' => '7cb0f489578afad5006e85cd60f18ff33f2d440d', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/uri', 'aliases' => array(), - 'reference' => '7cb0f489578afad5006e85cd60f18ff33f2d440d', 'dev_requirement' => false, ), 'sabre/vobject' => array( 'pretty_version' => '4.4.1', 'version' => '4.4.1.0', + 'reference' => '06feff370141fd3118609f808e86d9315864bf14', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/vobject', 'aliases' => array(), - 'reference' => '06feff370141fd3118609f808e86d9315864bf14', 'dev_requirement' => false, ), 'sabre/xml' => array( 'pretty_version' => '2.2.5', 'version' => '2.2.5.0', + 'reference' => 'a6af111850e7536d200d9637c34885cd3c77a86c', 'type' => 'library', 'install_path' => __DIR__ . '/../sabre/xml', 'aliases' => array(), - 'reference' => 'a6af111850e7536d200d9637c34885cd3c77a86c', 'dev_requirement' => false, ), 'scssphp/scssphp' => array( 'pretty_version' => 'v1.8.1', 'version' => '1.8.1.0', + 'reference' => '5e37759a63caf54392a4b709358a39ac7425a69f', 'type' => 'library', 'install_path' => __DIR__ . '/../scssphp/scssphp', 'aliases' => array(), - 'reference' => '5e37759a63caf54392a4b709358a39ac7425a69f', 'dev_requirement' => false, ), 'spomky-labs/base64url' => array( 'pretty_version' => 'v2.0.4', 'version' => '2.0.4.0', + 'reference' => '7752ce931ec285da4ed1f4c5aa27e45e097be61d', 'type' => 'library', 'install_path' => __DIR__ . '/../spomky-labs/base64url', 'aliases' => array(), - 'reference' => '7752ce931ec285da4ed1f4c5aa27e45e097be61d', 'dev_requirement' => false, ), 'spomky-labs/cbor-php' => array( 'pretty_version' => 'v2.0.1', 'version' => '2.0.1.0', + 'reference' => '9776578000be884cd7864eeb7c37a4ac92d8c995', 'type' => 'library', 'install_path' => __DIR__ . '/../spomky-labs/cbor-php', 'aliases' => array(), - 'reference' => '9776578000be884cd7864eeb7c37a4ac92d8c995', 'dev_requirement' => false, ), 'stecman/symfony-console-completion' => array( 'pretty_version' => '0.11.0', 'version' => '0.11.0.0', + 'reference' => 'a9502dab59405e275a9f264536c4e1cb61fc3518', 'type' => 'library', 'install_path' => __DIR__ . '/../stecman/symfony-console-completion', 'aliases' => array(), - 'reference' => 'a9502dab59405e275a9f264536c4e1cb61fc3518', 'dev_requirement' => false, ), 'swiftmailer/swiftmailer' => array( 'pretty_version' => 'v6.2.7', 'version' => '6.2.7.0', + 'reference' => '15f7faf8508e04471f666633addacf54c0ab5933', 'type' => 'library', 'install_path' => __DIR__ . '/../swiftmailer/swiftmailer', 'aliases' => array(), - 'reference' => '15f7faf8508e04471f666633addacf54c0ab5933', 'dev_requirement' => false, ), 'symfony/console' => array( 'pretty_version' => 'v4.4.30', 'version' => '4.4.30.0', + 'reference' => 'a3f7189a0665ee33b50e9e228c46f50f5acbed22', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), - 'reference' => 'a3f7189a0665ee33b50e9e228c46f50f5acbed22', 'dev_requirement' => false, ), 'symfony/deprecation-contracts' => array( 'pretty_version' => 'v2.5.0', 'version' => '2.5.0.0', + 'reference' => '6f981ee24cf69ee7ce9736146d1c57c2780598a8', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), - 'reference' => '6f981ee24cf69ee7ce9736146d1c57c2780598a8', 'dev_requirement' => false, ), 'symfony/event-dispatcher' => array( 'pretty_version' => 'v4.4.30', 'version' => '4.4.30.0', + 'reference' => '2fe81680070043c4c80e7cedceb797e34f377bac', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher', 'aliases' => array(), - 'reference' => '2fe81680070043c4c80e7cedceb797e34f377bac', 'dev_requirement' => false, ), 'symfony/event-dispatcher-contracts' => array( 'pretty_version' => 'v1.1.9', 'version' => '1.1.9.0', + 'reference' => '84e23fdcd2517bf37aecbd16967e83f0caee25a7', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts', 'aliases' => array(), - 'reference' => '84e23fdcd2517bf37aecbd16967e83f0caee25a7', 'dev_requirement' => false, ), 'symfony/event-dispatcher-implementation' => array( @@ -724,127 +733,127 @@ 'symfony/polyfill-ctype' => array( 'pretty_version' => 'v1.23.0', 'version' => '1.23.0.0', + 'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), - 'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce', 'dev_requirement' => false, ), 'symfony/polyfill-iconv' => array( 'pretty_version' => 'v1.23.0', 'version' => '1.23.0.0', + 'reference' => '63b5bb7db83e5673936d6e3b8b3e022ff6474933', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-iconv', 'aliases' => array(), - 'reference' => '63b5bb7db83e5673936d6e3b8b3e022ff6474933', 'dev_requirement' => false, ), 'symfony/polyfill-intl-grapheme' => array( 'pretty_version' => 'v1.23.1', 'version' => '1.23.1.0', + 'reference' => '16880ba9c5ebe3642d1995ab866db29270b36535', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'aliases' => array(), - 'reference' => '16880ba9c5ebe3642d1995ab866db29270b36535', 'dev_requirement' => false, ), 'symfony/polyfill-intl-idn' => array( 'pretty_version' => 'v1.23.0', 'version' => '1.23.0.0', + 'reference' => '65bd267525e82759e7d8c4e8ceea44f398838e65', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', 'aliases' => array(), - 'reference' => '65bd267525e82759e7d8c4e8ceea44f398838e65', 'dev_requirement' => false, ), 'symfony/polyfill-intl-normalizer' => array( 'pretty_version' => 'v1.23.0', 'version' => '1.23.0.0', + 'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', 'aliases' => array(), - 'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8', 'dev_requirement' => false, ), 'symfony/polyfill-mbstring' => array( 'pretty_version' => 'v1.23.1', 'version' => '1.23.1.0', + 'reference' => '9174a3d80210dca8daa7f31fec659150bbeabfc6', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), - 'reference' => '9174a3d80210dca8daa7f31fec659150bbeabfc6', 'dev_requirement' => false, ), 'symfony/polyfill-php72' => array( 'pretty_version' => 'v1.23.0', 'version' => '1.23.0.0', + 'reference' => '9a142215a36a3888e30d0a9eeea9766764e96976', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php72', 'aliases' => array(), - 'reference' => '9a142215a36a3888e30d0a9eeea9766764e96976', 'dev_requirement' => false, ), 'symfony/polyfill-php73' => array( 'pretty_version' => 'v1.23.0', 'version' => '1.23.0.0', + 'reference' => 'fba8933c384d6476ab14fb7b8526e5287ca7e010', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php73', 'aliases' => array(), - 'reference' => 'fba8933c384d6476ab14fb7b8526e5287ca7e010', 'dev_requirement' => false, ), 'symfony/polyfill-php80' => array( 'pretty_version' => 'v1.23.1', 'version' => '1.23.1.0', + 'reference' => '1100343ed1a92e3a38f9ae122fc0eb21602547be', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), - 'reference' => '1100343ed1a92e3a38f9ae122fc0eb21602547be', 'dev_requirement' => false, ), 'symfony/process' => array( 'pretty_version' => 'v4.4.30', 'version' => '4.4.30.0', + 'reference' => '13d3161ef63a8ec21eeccaaf9a4d7f784a87a97d', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), - 'reference' => '13d3161ef63a8ec21eeccaaf9a4d7f784a87a97d', 'dev_requirement' => false, ), 'symfony/routing' => array( 'pretty_version' => 'v4.4.30', 'version' => '4.4.30.0', + 'reference' => '9ddf033927ad9f30ba2bfd167a7b342cafa13e8e', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/routing', 'aliases' => array(), - 'reference' => '9ddf033927ad9f30ba2bfd167a7b342cafa13e8e', 'dev_requirement' => false, ), 'symfony/service-contracts' => array( 'pretty_version' => 'v2.4.0', 'version' => '2.4.0.0', + 'reference' => 'f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), - 'reference' => 'f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb', 'dev_requirement' => false, ), 'symfony/translation' => array( 'pretty_version' => 'v4.4.41', 'version' => '4.4.41.0', + 'reference' => 'dcb67eae126e74507e0b4f0b9ac6ef35b37c3331', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/translation', 'aliases' => array(), - 'reference' => 'dcb67eae126e74507e0b4f0b9ac6ef35b37c3331', 'dev_requirement' => false, ), 'symfony/translation-contracts' => array( 'pretty_version' => 'v2.4.0', 'version' => '2.4.0.0', + 'reference' => '95c812666f3e91db75385749fe219c5e494c7f95', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/translation-contracts', 'aliases' => array(), - 'reference' => '95c812666f3e91db75385749fe219c5e494c7f95', 'dev_requirement' => false, ), 'symfony/translation-implementation' => array( @@ -856,37 +865,37 @@ 'thecodingmachine/safe' => array( 'pretty_version' => 'v1.3.3', 'version' => '1.3.3.0', + 'reference' => 'a8ab0876305a4cdaef31b2350fcb9811b5608dbc', 'type' => 'library', 'install_path' => __DIR__ . '/../thecodingmachine/safe', 'aliases' => array(), - 'reference' => 'a8ab0876305a4cdaef31b2350fcb9811b5608dbc', 'dev_requirement' => false, ), 'web-auth/cose-lib' => array( 'pretty_version' => 'v3.3.9', 'version' => '3.3.9.0', + 'reference' => 'ed172d2dc1a6b87b5c644c07c118cd30c1b3819b', 'type' => 'library', 'install_path' => __DIR__ . '/../web-auth/cose-lib', 'aliases' => array(), - 'reference' => 'ed172d2dc1a6b87b5c644c07c118cd30c1b3819b', 'dev_requirement' => false, ), 'web-auth/metadata-service' => array( 'pretty_version' => 'v3.3.9', 'version' => '3.3.9.0', + 'reference' => '8488d3a832a38cc81c670fce05de1e515c6e64b1', 'type' => 'library', 'install_path' => __DIR__ . '/../web-auth/metadata-service', 'aliases' => array(), - 'reference' => '8488d3a832a38cc81c670fce05de1e515c6e64b1', 'dev_requirement' => false, ), 'web-auth/webauthn-lib' => array( 'pretty_version' => 'v3.3.9', 'version' => '3.3.9.0', + 'reference' => '04b98ee3d39cb79dad68a7c15c297c085bf66bfe', 'type' => 'library', 'install_path' => __DIR__ . '/../web-auth/webauthn-lib', 'aliases' => array(), - 'reference' => '04b98ee3d39cb79dad68a7c15c297c085bf66bfe', 'dev_requirement' => false, ), ), diff --git a/laravel/serializable-closure/LICENSE.md b/laravel/serializable-closure/LICENSE.md new file mode 100644 index 00000000..79810c84 --- /dev/null +++ b/laravel/serializable-closure/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Taylor Otwell + +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. diff --git a/laravel/serializable-closure/README.md b/laravel/serializable-closure/README.md new file mode 100644 index 00000000..a9c25135 --- /dev/null +++ b/laravel/serializable-closure/README.md @@ -0,0 +1,71 @@ +# Serializable Closure + +<a href="https://github.com/laravel/serializable-closure/actions"> + <img src="https://github.com/laravel/serializable-closure/workflows/tests/badge.svg" alt="Build Status"> +</a> +<a href="https://packagist.org/packages/laravel/serializable-closure"> + <img src="https://img.shields.io/packagist/dt/laravel/serializable-closure" alt="Total Downloads"> +</a> +<a href="https://packagist.org/packages/laravel/serializable-closure"> + <img src="https://img.shields.io/packagist/v/laravel/serializable-closure" alt="Latest Stable Version"> +</a> +<a href="https://packagist.org/packages/laravel/serializable-closure"> + <img src="https://img.shields.io/packagist/l/laravel/serializable-closure" alt="License"> +</a> + +## Introduction + +> This project is a fork of the excellent [opis/closure: 3.x](https://github.com/opis/closure) package. At Laravel, we decided to fork this package as the upcoming version [4.x](https://github.com/opis/closure) is a complete rewrite on top of the [FFI extension](https://www.php.net/manual/en/book.ffi.php). As Laravel is a web framework, and FFI is not enabled by default in web requests, this fork allows us to keep using the `3.x` series while adding support for new PHP versions. + +Laravel Serializable Closure provides an easy and secure way to **serialize closures in PHP**. + +## Official Documentation + +### Installation + +> **Requires [PHP 7.4+](https://php.net/releases/)** + +First, install Laravel Serializable Closure via the [Composer](https://getcomposer.org/) package manager: + +```bash +composer require laravel/serializable-closure +``` + +### Usage + +You may serialize a closure this way: + +```php +use Laravel\SerializableClosure\SerializableClosure; + +$closure = fn () => 'james'; + +// Recommended +SerializableClosure::setSecretKey('secret'); + +$serialized = serialize(new SerializableClosure($closure)); +$closure = unserialize($serialized)->getClosure(); + +echo $closure(); // james; +``` + +### Caveats + +1. Creating **anonymous classes** within closures is not supported. +2. Using attributes within closures is not supported. + +## Contributing + +Thank you for considering contributing to Serializable Closure! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). + +## Code of Conduct + +In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). + +## Security Vulnerabilities + +Please review [our security policy](https://github.com/laravel/serializable-closure/security/policy) on how to report security vulnerabilities. + +## License + +Serializable Closure is open-sourced software licensed under the [MIT license](LICENSE.md). diff --git a/laravel/serializable-closure/composer.json b/laravel/serializable-closure/composer.json new file mode 100644 index 00000000..5e8fbbc8 --- /dev/null +++ b/laravel/serializable-closure/composer.json @@ -0,0 +1,51 @@ +{ + "name": "laravel/serializable-closure", + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": ["laravel", "Serializable", "closure"], + "license": "MIT", + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.18", + "phpstan/phpstan": "^0.12.98", + "symfony/var-dumper": "^5.3" + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/laravel/serializable-closure/src/Contracts/Serializable.php b/laravel/serializable-closure/src/Contracts/Serializable.php new file mode 100644 index 00000000..1a62922e --- /dev/null +++ b/laravel/serializable-closure/src/Contracts/Serializable.php @@ -0,0 +1,20 @@ +<?php + +namespace Laravel\SerializableClosure\Contracts; + +interface Serializable +{ + /** + * Resolve the closure with the given arguments. + * + * @return mixed + */ + public function __invoke(); + + /** + * Gets the closure that got serialized/unserialized. + * + * @return \Closure + */ + public function getClosure(); +} diff --git a/laravel/serializable-closure/src/Contracts/Signer.php b/laravel/serializable-closure/src/Contracts/Signer.php new file mode 100644 index 00000000..4d0f0fc6 --- /dev/null +++ b/laravel/serializable-closure/src/Contracts/Signer.php @@ -0,0 +1,22 @@ +<?php + +namespace Laravel\SerializableClosure\Contracts; + +interface Signer +{ + /** + * Sign the given serializable. + * + * @param string $serializable + * @return array + */ + public function sign($serializable); + + /** + * Verify the given signature. + * + * @param array $signature + * @return bool + */ + public function verify($signature); +} diff --git a/laravel/serializable-closure/src/Exceptions/InvalidSignatureException.php b/laravel/serializable-closure/src/Exceptions/InvalidSignatureException.php new file mode 100644 index 00000000..83d9e4fc --- /dev/null +++ b/laravel/serializable-closure/src/Exceptions/InvalidSignatureException.php @@ -0,0 +1,19 @@ +<?php + +namespace Laravel\SerializableClosure\Exceptions; + +use Exception; + +class InvalidSignatureException extends Exception +{ + /** + * Create a new exception instance. + * + * @param string $message + * @return void + */ + public function __construct($message = 'Your serialized closure might have been modified or it\'s unsafe to be unserialized.') + { + parent::__construct($message); + } +} diff --git a/laravel/serializable-closure/src/Exceptions/MissingSecretKeyException.php b/laravel/serializable-closure/src/Exceptions/MissingSecretKeyException.php new file mode 100644 index 00000000..b301a3a7 --- /dev/null +++ b/laravel/serializable-closure/src/Exceptions/MissingSecretKeyException.php @@ -0,0 +1,19 @@ +<?php + +namespace Laravel\SerializableClosure\Exceptions; + +use Exception; + +class MissingSecretKeyException extends Exception +{ + /** + * Create a new exception instance. + * + * @param string $message + * @return void + */ + public function __construct($message = 'No serializable closure secret key has been specified.') + { + parent::__construct($message); + } +} diff --git a/laravel/serializable-closure/src/Exceptions/PhpVersionNotSupportedException.php b/laravel/serializable-closure/src/Exceptions/PhpVersionNotSupportedException.php new file mode 100644 index 00000000..b664e00a --- /dev/null +++ b/laravel/serializable-closure/src/Exceptions/PhpVersionNotSupportedException.php @@ -0,0 +1,19 @@ +<?php + +namespace Laravel\SerializableClosure\Exceptions; + +use Exception; + +class PhpVersionNotSupportedException extends Exception +{ + /** + * Create a new exception instance. + * + * @param string $message + * @return void + */ + public function __construct($message = 'PHP 7.3 is not supported.') + { + parent::__construct($message); + } +} diff --git a/laravel/serializable-closure/src/SerializableClosure.php b/laravel/serializable-closure/src/SerializableClosure.php new file mode 100644 index 00000000..e7f9f0cf --- /dev/null +++ b/laravel/serializable-closure/src/SerializableClosure.php @@ -0,0 +1,128 @@ +<?php + +namespace Laravel\SerializableClosure; + +use Closure; +use Laravel\SerializableClosure\Exceptions\InvalidSignatureException; +use Laravel\SerializableClosure\Exceptions\PhpVersionNotSupportedException; +use Laravel\SerializableClosure\Serializers\Signed; +use Laravel\SerializableClosure\Signers\Hmac; + +class SerializableClosure +{ + /** + * The closure's serializable. + * + * @var \Laravel\SerializableClosure\Contracts\Serializable + */ + protected $serializable; + + /** + * Creates a new serializable closure instance. + * + * @param \Closure $closure + * @return void + */ + public function __construct(Closure $closure) + { + if (\PHP_VERSION_ID < 70400) { + throw new PhpVersionNotSupportedException(); + } + + $this->serializable = Serializers\Signed::$signer + ? new Serializers\Signed($closure) + : new Serializers\Native($closure); + } + + /** + * Resolve the closure with the given arguments. + * + * @return mixed + */ + public function __invoke() + { + if (\PHP_VERSION_ID < 70400) { + throw new PhpVersionNotSupportedException(); + } + + return call_user_func_array($this->serializable, func_get_args()); + } + + /** + * Gets the closure. + * + * @return \Closure + */ + public function getClosure() + { + if (\PHP_VERSION_ID < 70400) { + throw new PhpVersionNotSupportedException(); + } + + return $this->serializable->getClosure(); + } + + /** + * Sets the serializable closure secret key. + * + * @param string|null $secret + * @return void + */ + public static function setSecretKey($secret) + { + Serializers\Signed::$signer = $secret + ? new Hmac($secret) + : null; + } + + /** + * Sets the serializable closure secret key. + * + * @param \Closure|null $transformer + * @return void + */ + public static function transformUseVariablesUsing($transformer) + { + Serializers\Native::$transformUseVariables = $transformer; + } + + /** + * Sets the serializable closure secret key. + * + * @param \Closure|null $resolver + * @return void + */ + public static function resolveUseVariablesUsing($resolver) + { + Serializers\Native::$resolveUseVariables = $resolver; + } + + /** + * Get the serializable representation of the closure. + * + * @return array + */ + public function __serialize() + { + return [ + 'serializable' => $this->serializable, + ]; + } + + /** + * Restore the closure after serialization. + * + * @param array $data + * @return void + * + * @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException + */ + public function __unserialize($data) + { + if (Signed::$signer && ! $data['serializable'] instanceof Signed) { + throw new InvalidSignatureException(); + } + + $this->serializable = $data['serializable']; + } +} diff --git a/laravel/serializable-closure/src/Serializers/Native.php b/laravel/serializable-closure/src/Serializers/Native.php new file mode 100644 index 00000000..c04ead03 --- /dev/null +++ b/laravel/serializable-closure/src/Serializers/Native.php @@ -0,0 +1,506 @@ +<?php + +namespace Laravel\SerializableClosure\Serializers; + +use Closure; +use Laravel\SerializableClosure\Contracts\Serializable; +use Laravel\SerializableClosure\SerializableClosure; +use Laravel\SerializableClosure\Support\ClosureScope; +use Laravel\SerializableClosure\Support\ClosureStream; +use Laravel\SerializableClosure\Support\ReflectionClosure; +use Laravel\SerializableClosure\Support\SelfReference; +use ReflectionObject; +use UnitEnum; + +class Native implements Serializable +{ + /** + * Transform the use variables before serialization. + * + * @var \Closure|null + */ + public static $transformUseVariables; + + /** + * Resolve the use variables after unserialization. + * + * @var \Closure|null + */ + public static $resolveUseVariables; + + /** + * The closure to be serialized/unserialized. + * + * @var \Closure + */ + protected $closure; + + /** + * The closure's reflection. + * + * @var \Laravel\SerializableClosure\Support\ReflectionClosure|null + */ + protected $reflector; + + /** + * The closure's code. + * + * @var array|null + */ + protected $code; + + /** + * The closure's reference. + * + * @var string + */ + protected $reference; + + /** + * The closure's scope. + * + * @var \Laravel\SerializableClosure\Support\ClosureScope|null + */ + protected $scope; + + /** + * The "key" that marks an array as recursive. + */ + const ARRAY_RECURSIVE_KEY = 'LARAVEL_SERIALIZABLE_RECURSIVE_KEY'; + + /** + * Creates a new serializable closure instance. + * + * @param \Closure $closure + * @return void + */ + public function __construct(Closure $closure) + { + $this->closure = $closure; + } + + /** + * Resolve the closure with the given arguments. + * + * @return mixed + */ + public function __invoke() + { + return call_user_func_array($this->closure, func_get_args()); + } + + /** + * Gets the closure. + * + * @return \Closure + */ + public function getClosure() + { + return $this->closure; + } + + /** + * Get the serializable representation of the closure. + * + * @return array + */ + 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; + } + + $this->reference = spl_object_hash($this->closure); + + $this->scope[$this->closure] = $this; + + $use = $reflector->getUseVariables(); + + if (static::$transformUseVariables) { + $use = call_user_func(static::$transformUseVariables, $reflector->getUseVariables()); + } + + $code = $reflector->getCode(); + + $this->mapByReference($use); + + $data = [ + 'use' => $use, + 'function' => $code, + 'scope' => $scope, + 'this' => $object, + 'self' => $this->reference, + ]; + + if (! --$this->scope->serializations && ! --$this->scope->toSerialize) { + $this->scope = null; + } + + return $data; + } + + /** + * Restore the closure after serialization. + * + * @param array $data + * @return void + */ + public function __unserialize($data) + { + ClosureStream::register(); + + $this->code = $data; + unset($data); + + $this->code['objects'] = []; + + if ($this->code['use']) { + $this->scope = new ClosureScope(); + + if (static::$resolveUseVariables) { + $this->code['use'] = call_user_func(static::$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']; + } + + /** + * Ensures the given closures are serializable. + * + * @param mixed $data + * @param \Laravel\SerializableClosure\Support\ClosureScope $storage + * @return void + */ + public static function wrapClosures(&$data, $storage) + { + if ($data instanceof Closure) { + $data = new static($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 && ! $data instanceof UnitEnum) { + 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()); + } + } + + /** + * Gets the closure's reflector. + * + * @return \Laravel\SerializableClosure\Support\ReflectionClosure + */ + public function getReflector() + { + if ($this->reflector === null) { + $this->code = null; + $this->reflector = new ReflectionClosure($this->closure); + } + + return $this->reflector; + } + + /** + * Internal method used to map closure pointers. + * + * @param mixed $data + * @return void + */ + 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'][] = [ + '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. + * + * @param mixed $data + * @return void + */ + 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); + + $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; + + if ($data instanceof UnitEnum) { + $this->scope[$instance] = $data; + + return; + } + + $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()); + } + } +} diff --git a/laravel/serializable-closure/src/Serializers/Signed.php b/laravel/serializable-closure/src/Serializers/Signed.php new file mode 100644 index 00000000..a47d367e --- /dev/null +++ b/laravel/serializable-closure/src/Serializers/Signed.php @@ -0,0 +1,88 @@ +<?php + +namespace Laravel\SerializableClosure\Serializers; + +use Laravel\SerializableClosure\Contracts\Serializable; +use Laravel\SerializableClosure\Exceptions\InvalidSignatureException; +use Laravel\SerializableClosure\Exceptions\MissingSecretKeyException; + +class Signed implements Serializable +{ + /** + * The signer that will sign and verify the closure's signature. + * + * @var \Laravel\SerializableClosure\Contracts\Signer|null + */ + public static $signer; + + /** + * The closure to be serialized/unserialized. + * + * @var \Closure + */ + protected $closure; + + /** + * Creates a new serializable closure instance. + * + * @param \Closure $closure + * @return void + */ + public function __construct($closure) + { + $this->closure = $closure; + } + + /** + * Resolve the closure with the given arguments. + * + * @return mixed + */ + public function __invoke() + { + return call_user_func_array($this->closure, func_get_args()); + } + + /** + * Gets the closure. + * + * @return \Closure + */ + public function getClosure() + { + return $this->closure; + } + + /** + * Get the serializable representation of the closure. + * + * @return array + */ + public function __serialize() + { + if (! static::$signer) { + throw new MissingSecretKeyException(); + } + + return static::$signer->sign( + serialize(new Native($this->closure)) + ); + } + + /** + * Restore the closure after serialization. + * + * @param array $signature + * @return void + * + * @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException + */ + public function __unserialize($signature) + { + if (static::$signer && ! static::$signer->verify($signature)) { + throw new InvalidSignatureException(); + } + + $this->closure = unserialize($signature['serializable'])->getClosure(); + } +} diff --git a/laravel/serializable-closure/src/Signers/Hmac.php b/laravel/serializable-closure/src/Signers/Hmac.php new file mode 100644 index 00000000..d94b0a2a --- /dev/null +++ b/laravel/serializable-closure/src/Signers/Hmac.php @@ -0,0 +1,53 @@ +<?php + +namespace Laravel\SerializableClosure\Signers; + +use Laravel\SerializableClosure\Contracts\Signer; + +class Hmac implements Signer +{ + /** + * The secret key. + * + * @var string + */ + protected $secret; + + /** + * Creates a new signer instance. + * + * @param string $secret + * @return void + */ + public function __construct($secret) + { + $this->secret = $secret; + } + + /** + * Sign the given serializable. + * + * @param string $serialized + * @return array + */ + public function sign($serialized) + { + return [ + 'serializable' => $serialized, + 'hash' => base64_encode(hash_hmac('sha256', $serialized, $this->secret, true)), + ]; + } + + /** + * Verify the given signature. + * + * @param array $signature + * @return bool + */ + public function verify($signature) + { + return hash_equals(base64_encode( + hash_hmac('sha256', $signature['serializable'], $this->secret, true) + ), $signature['hash']); + } +} diff --git a/laravel/serializable-closure/src/Support/ClosureScope.php b/laravel/serializable-closure/src/Support/ClosureScope.php new file mode 100644 index 00000000..64ca19a3 --- /dev/null +++ b/laravel/serializable-closure/src/Support/ClosureScope.php @@ -0,0 +1,22 @@ +<?php + +namespace Laravel\SerializableClosure\Support; + +use SplObjectStorage; + +class ClosureScope extends SplObjectStorage +{ + /** + * The number of serializations in current scope. + * + * @var int + */ + public $serializations = 0; + + /** + * The number of closures that have to be serialized. + * + * @var int + */ + public $toSerialize = 0; +} diff --git a/laravel/serializable-closure/src/Support/ClosureStream.php b/laravel/serializable-closure/src/Support/ClosureStream.php new file mode 100644 index 00000000..b54558b8 --- /dev/null +++ b/laravel/serializable-closure/src/Support/ClosureStream.php @@ -0,0 +1,178 @@ +<?php + +namespace Laravel\SerializableClosure\Support; + +class ClosureStream +{ + /** + * The stream protocol. + */ + const STREAM_PROTO = 'laravel-serializable-closure'; + + /** + * Checks if this stream is registered. + * + * @var bool + */ + protected static $isRegistered = false; + + /** + * The stream content. + * + * @var string + */ + protected $content; + + /** + * The stream content. + * + * @var int + */ + protected $length; + + /** + * The stream pointer. + * + * @var int + */ + protected $pointer = 0; + + /** + * Opens file or URL. + * + * @param string $path + * @param string $mode + * @param string $options + * @param string|null $opened_path + * @return bool + */ + public 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; + } + + /** + * Read from stream. + * + * @param int $count + * @return string + */ + public function stream_read($count) + { + $value = substr($this->content, $this->pointer, $count); + + $this->pointer += $count; + + return $value; + } + + /** + * Tests for end-of-file on a file pointer. + * + * @return bool + */ + public function stream_eof() + { + return $this->pointer >= $this->length; + } + + /** + * Change stream options. + * + * @param int $option + * @param int $arg1 + * @param int $arg2 + * @return bool + */ + public function stream_set_option($option, $arg1, $arg2) + { + return false; + } + + /** + * Retrieve information about a file resource. + * + * @return array|bool + */ + public function stream_stat() + { + $stat = stat(__FILE__); + // @phpstan-ignore-next-line + $stat[7] = $stat['size'] = $this->length; + + return $stat; + } + + /** + * Retrieve information about a file. + * + * @param string $path + * @param int $flags + * @return array|bool + */ + public function url_stat($path, $flags) + { + $stat = stat(__FILE__); + // @phpstan-ignore-next-line + $stat[7] = $stat['size'] = $this->length; + + return $stat; + } + + /** + * Seeks to specific location in a stream. + * + * @param int $offset + * @param int $whence + * @return bool + */ + 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; + } + + /** + * Retrieve the current position of a stream. + * + * @return int + */ + public function stream_tell() + { + return $this->pointer; + } + + /** + * Registers the stream. + * + * @return void + */ + public static function register() + { + if (! static::$isRegistered) { + static::$isRegistered = stream_wrapper_register(static::STREAM_PROTO, __CLASS__); + } + } +} diff --git a/laravel/serializable-closure/src/Support/ReflectionClosure.php b/laravel/serializable-closure/src/Support/ReflectionClosure.php new file mode 100644 index 00000000..a0d37075 --- /dev/null +++ b/laravel/serializable-closure/src/Support/ReflectionClosure.php @@ -0,0 +1,1195 @@ +<?php + +namespace Laravel\SerializableClosure\Support; + +defined('T_NAME_QUALIFIED') || define('T_NAME_QUALIFIED', -4); +defined('T_NAME_FULLY_QUALIFIED') || define('T_NAME_FULLY_QUALIFIED', -5); +defined('T_FN') || define('T_FN', -6); +defined('T_NULLSAFE_OBJECT_OPERATOR') || define('T_NULLSAFE_OBJECT_OPERATOR', -7); + +use Closure; +use ReflectionFunction; + +class ReflectionClosure extends ReflectionFunction +{ + protected $code; + protected $tokens; + protected $hashedName; + protected $useVariables; + protected $isStaticClosure; + protected $isScopeRequired; + protected $isBindingRequired; + protected $isShortClosure; + + protected static $files = []; + protected static $classes = []; + protected static $functions = []; + protected static $constants = []; + protected static $structures = []; + + /** + * Creates a new reflection closure instance. + * + * @param \Closure $closure + * @param string|null $code + * @return void + */ + public function __construct(Closure $closure, $code = null) + { + parent::__construct($closure); + } + + /** + * Checks if the closure is "static". + * + * @return bool + */ + public function isStatic(): bool + { + if ($this->isStaticClosure === null) { + $this->isStaticClosure = strtolower(substr($this->getCode(), 0, 6)) === 'static'; + } + + return $this->isStaticClosure; + } + + /** + * Checks if the closure is a "short closure". + * + * @return bool + */ + public function isShortClosure() + { + if ($this->isShortClosure === null) { + $code = $this->getCode(); + + if ($this->isStatic()) { + $code = substr($code, 6); + } + + $this->isShortClosure = strtolower(substr(trim($code), 0, 2)) === 'fn'; + } + + return $this->isShortClosure; + } + + /** + * Get the closure's code. + * + * @return string + */ + public function getCode() + { + if ($this->code !== null) { + return $this->code; + } + + $fileName = $this->getFileName(); + $line = $this->getStartLine() - 1; + + $className = null; + + if (null !== $className = $this->getClosureScopeClass()) { + $className = '\\'.trim($className->getName(), '\\'); + } + + $builtin_types = self::getBuiltinTypes(); + $class_keywords = ['self', 'static', 'parent']; + + $ns = $this->getClosureNamespaceName(); + $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_structure = false; + $isFirstClassCallable = false; + $isShortClosure = false; + + $inside_structure_mark = 0; + $open = 0; + $code = ''; + $id_start = $id_start_ci = $id_name = $context = ''; + $classes = $functions = $constants = null; + $use = []; + $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'; + } elseif ($token[0] === T_FN) { + $isShortClosure = true; + $code .= $token[1]; + $state = 'closure_args'; + } elseif ($token[0] === T_PUBLIC || $token[0] === T_PROTECTED || $token[0] === T_PRIVATE) { + $code = ''; + $isFirstClassCallable = true; + } + 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'; + } + } elseif ($token[0] === T_FN) { + $isShortClosure = true; + $code .= $token[1]; + $state = 'closure_args'; + } else { + $code = ''; + $state = 'start'; + } + break; + case 'function': + switch ($token[0]) { + case T_STRING: + if ($isFirstClassCallable) { + $state = 'closure_args'; + break; + } + + $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'; + } elseif ($token[0] === T_FN) { + $isShortClosure = true; + $code .= $token[1]; + $state = 'closure_args'; + } + break; + case 'closure_args': + switch ($token[0]) { + case T_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $context = 'args'; + $state = 'id_name'; + $lastState = 'closure_args'; + break; + 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 T_DOUBLE_ARROW: + $code .= $token[1]; + if ($isShortClosure) { + $state = 'closure'; + } + 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 T_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $context = 'return_type'; + $state = 'id_name'; + $lastState = 'return'; + break 2; + case T_DOUBLE_ARROW: + $code .= $token[1]; + if ($isShortClosure) { + $state = 'closure'; + } + break; + 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 '{': + $code .= is_array($token) ? $token[1] : $token; + $open++; + break; + case '}': + $code .= '}'; + if (--$open === 0 && ! $isShortClosure) { + break 3; + } elseif ($inside_structure) { + $inside_structure = ! ($open === $inside_structure_mark); + } + break; + case '(': + case '[': + $code .= $token[0]; + if ($isShortClosure) { + $open++; + } + break; + case ')': + case ']': + if ($isShortClosure) { + if ($open === 0) { + break 3; + } + $open--; + } + $code .= $token[0]; + break; + case ',': + case ';': + if ($isShortClosure && $open === 0) { + break 3; + } + $code .= $token[0]; + 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 .= $inside_structure ? $token[1] : $_class; + break; + case T_FUNC_C: + $code .= $inside_structure ? $token[1] : $_function; + break; + case T_METHOD_C: + $code .= $inside_structure ? $token[1] : $_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_structure) { + $isUsingThisObject = true; + } + $code .= $token[1]; + break; + case T_STATIC: + 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_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $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: + case T_INSTEADOF: + $code .= $token[1]; + $context = 'instanceof'; + $state = 'id_start'; + $lastState = 'closure'; + break; + case T_OBJECT_OPERATOR: + case T_NULLSAFE_OBJECT_OPERATOR: + case T_DOUBLE_COLON: + $code .= $token[1]; + $lastState = 'closure'; + $state = 'ignore_next'; + break; + case T_FUNCTION: + $code .= $token[1]; + $state = 'closure_args'; + if (! $inside_structure) { + $inside_structure = true; + $inside_structure_mark = $open; + } + 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_NAME_FULLY_QUALIFIED: + 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_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $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]) { + // named arguments... + case ':': + if ($lastState === 'closure' && $context === 'root') { + $state = 'ignore_next'; + $lastState = 'closure'; + $code .= $id_start.$token; + } + + break; + case T_NAME_QUALIFIED: + case T_NS_SEPARATOR: + case T_STRING: + case T_WHITESPACE: + case T_COMMENT: + case T_DOC_COMMENT: + $id_name .= $token[1]; + break; + case '(': + if ($isShortClosure) { + $open++; + } + if ($context === 'new' || false !== strpos($id_name, '\\')) { + if ($id_start_ci === 'self' || $id_start_ci === 'static') { + if (! $inside_structure) { + $isUsingScope = true; + } + } elseif ($id_start !== '\\' && ! in_array($id_start_ci, $class_keywords)) { + 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]; + } elseif ($nsf !== '\\' && function_exists($nsf.'\\'.$id_start)) { + $id_start = $nsf.'\\'.$id_start; + // Cache it to functions array + $functions[$id_start_ci] = $id_start; + } + } + } + $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 === 'parent') { + if (! $inside_structure) { + $isUsingScope = true; + } + } elseif ($id_start_ci === 'static') { + if (! $inside_structure) { + $isUsingScope = $token[0] === T_DOUBLE_COLON; + } + } elseif (! (\PHP_MAJOR_VERSION >= 7 && in_array($id_start_ci, $builtin_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 !== '\\' && ! defined($id_start)) { + if ($constants === null) { + $constants = $this->getConstants(); + } + if (isset($constants[$id_start])) { + $id_start = $constants[$id_start]; + } elseif ($context === 'new') { + if (in_array($id_start_ci, $class_keywords)) { + if (! $inside_structure) { + $isUsingScope = true; + } + } else { + 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; + } + } + } elseif ($context === 'use' || + $context === 'instanceof' || + $context === 'args' || + $context === 'return_type' || + $context === 'extends' || + $context === 'root' + ) { + if (in_array($id_start_ci, $class_keywords)) { + if (! $inside_structure && ! $id_start_ci === 'static') { + $isUsingScope = true; + } + } elseif (! (\PHP_MAJOR_VERSION >= 7 && in_array($id_start_ci, $builtin_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; + $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_structure) { + $inside_structure = true; + $inside_structure_mark = $open; + } + $i--; + break; + default: + $code .= is_array($token) ? $token[1] : $token; + } + break; + } + } + + if ($isShortClosure) { + $this->useVariables = $this->getStaticVariables(); + } else { + $this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use)); + } + + $this->isShortClosure = $isShortClosure; + $this->isBindingRequired = $isUsingThisObject; + $this->isScopeRequired = $isUsingScope; + + if (PHP_VERSION_ID >= 80100) { + $attributesCode = array_map(function ($attribute) { + $arguments = $attribute->getArguments(); + + $name = $attribute->getName(); + $arguments = implode(', ', array_map(function ($argument, $key) { + $argument = sprintf("'%s'", str_replace("'", "\\'", $argument)); + + if (is_string($key)) { + $argument = sprintf('%s: %s', $key, $argument); + } + + return $argument; + }, $arguments, array_keys($arguments))); + + return "#[$name($arguments)]"; + }, $this->getAttributes()); + + if (! empty($attributesCode)) { + $code = implode("\n", array_merge($attributesCode, [$code])); + } + } + + $this->code = $code; + + return $this->code; + } + + /** + * Get PHP native built in types. + * + * @return array + */ + protected static function getBuiltinTypes() + { + // PHP 8.1 + if (PHP_VERSION_ID >= 80100) { + return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object', 'mixed', 'false', 'null', 'never']; + } + + // PHP 8 + if (\PHP_MAJOR_VERSION === 8) { + return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object', 'mixed', 'false', 'null']; + } + + // PHP 7 + switch (\PHP_MINOR_VERSION) { + case 0: + return ['array', 'callable', 'string', 'int', 'bool', 'float']; + case 1: + return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void']; + default: + return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object']; + } + } + + /** + * Gets the use variables by the closure. + * + * @return array + */ + public function getUseVariables() + { + if ($this->useVariables !== null) { + return $this->useVariables; + } + + $tokens = $this->getTokens(); + $use = []; + $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; + } + + /** + * Checks if binding is required. + * + * @return bool + */ + public function isBindingRequired() + { + if ($this->isBindingRequired === null) { + $this->getCode(); + } + + return $this->isBindingRequired; + } + + /** + * Checks if access to the scope is required. + * + * @return bool + */ + public function isScopeRequired() + { + if ($this->isScopeRequired === null) { + $this->getCode(); + } + + return $this->isScopeRequired; + } + + /** + * The the hash of the current file name. + * + * @return string + */ + protected function getHashedFileName() + { + if ($this->hashedName === null) { + $this->hashedName = sha1($this->getFileName()); + } + + return $this->hashedName; + } + + /** + * Get the file tokens. + * + * @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]; + } + + /** + * Get the tokens. + * + * @return array + */ + protected function getTokens() + { + if ($this->tokens === null) { + $tokens = $this->getFileTokens(); + $startLine = $this->getStartLine(); + $endLine = $this->getEndLine(); + $results = []; + $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; + } + + /** + * Get the classes. + * + * @return array + */ + protected function getClasses() + { + $key = $this->getHashedFileName(); + + if (! isset(static::$classes[$key])) { + $this->fetchItems(); + } + + return static::$classes[$key]; + } + + /** + * Get the functions. + * + * @return array + */ + protected function getFunctions() + { + $key = $this->getHashedFileName(); + + if (! isset(static::$functions[$key])) { + $this->fetchItems(); + } + + return static::$functions[$key]; + } + + /** + * Gets the constants. + * + * @return array + */ + protected function getConstants() + { + $key = $this->getHashedFileName(); + + if (! isset(static::$constants[$key])) { + $this->fetchItems(); + } + + return static::$constants[$key]; + } + + /** + * Get the structures. + * + * @return array + */ + protected function getStructures() + { + $key = $this->getHashedFileName(); + + if (! isset(static::$structures[$key])) { + $this->fetchItems(); + } + + return static::$structures[$key]; + } + + /** + * Fetch the items. + * + * @return void. + */ + protected function fetchItems() + { + $key = $this->getHashedFileName(); + + $classes = []; + $functions = []; + $constants = []; + $structures = []; + $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_NAME_QUALIFIED: + $name .= $token[1]; + $pieces = explode('\\', $token[1]); + $alias = end($pieces); + 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_NAME_QUALIFIED: + $name .= $token[1]; + $pieces = explode('\\', $token[1]); + $alias = end($pieces); + 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: + $open++; + break; + case '}': + if (--$open == 0) { + if (! $structIgnore) { + $structures[] = [ + '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; + } + + /** + * Returns the namespace associated to the closure. + * + * @return string + */ + protected function getClosureNamespaceName() + { + $ns = $this->getNamespaceName(); + + // First class callables... + if ($this->getName() !== '{closure}' && empty($ns) && ! is_null($this->getClosureScopeClass())) { + $ns = $this->getClosureScopeClass()->getNamespaceName(); + } + + return $ns; + } + + /** + * Parse the given token. + * + * @param string $token + * @return array + */ + protected function parseNameQualified($token) + { + $pieces = explode('\\', $token); + + $id_start = array_shift($pieces); + + $id_start_ci = strtolower($id_start); + + $id_name = '\\'.implode('\\', $pieces); + + return [$id_start, $id_start_ci, $id_name]; + } +} diff --git a/laravel/serializable-closure/src/Support/SelfReference.php b/laravel/serializable-closure/src/Support/SelfReference.php new file mode 100644 index 00000000..58319504 --- /dev/null +++ b/laravel/serializable-closure/src/Support/SelfReference.php @@ -0,0 +1,24 @@ +<?php + +namespace Laravel\SerializableClosure\Support; + +class SelfReference +{ + /** + * The unique hash representing the object. + * + * @var string + */ + public $hash; + + /** + * Creates a new self reference instance. + * + * @param string $hash + * @return void + */ + public function __construct($hash) + { + $this->hash = $hash; + } +} diff --git a/opis/closure/CHANGELOG.md b/opis/closure/CHANGELOG.md deleted file mode 100644 index 16c9e3da..00000000 --- a/opis/closure/CHANGELOG.md +++ /dev/null @@ -1,260 +0,0 @@ -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 diff --git a/opis/closure/autoload.php b/opis/closure/autoload.php index 48b10f66..2354ea56 100644 --- a/opis/closure/autoload.php +++ b/opis/closure/autoload.php @@ -5,7 +5,7 @@ * Licensed under the MIT License * =========================================================================== */ -require_once 'functions.php'; +require_once __DIR__ . '/functions.php'; spl_autoload_register(function($class){ |