From a3f6a8e8abedbf34dc316f900ee1527ce726aed2 Mon Sep 17 00:00:00 2001 From: hide_d Date: Tue, 8 May 2018 00:38:29 +0900 Subject: [PATCH] =?UTF-8?q?symfony/lock=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 3 +- composer.lock | 171 ++++++++- vendor/composer/autoload_classmap.php | 7 + vendor/composer/autoload_files.php | 2 + vendor/composer/autoload_psr4.php | 2 + vendor/composer/autoload_static.php | 22 ++ vendor/composer/installed.json | 175 +++++++++ vendor/paragonie/random_compat/LICENSE | 22 ++ vendor/paragonie/random_compat/build-phar.sh | 5 + vendor/paragonie/random_compat/composer.json | 37 ++ .../dist/random_compat.phar.pubkey | 5 + .../dist/random_compat.phar.pubkey.asc | 11 + .../random_compat/lib/byte_safe_strings.php | 181 +++++++++ .../random_compat/lib/cast_to_int.php | 75 ++++ .../random_compat/lib/error_polyfill.php | 49 +++ vendor/paragonie/random_compat/lib/random.php | 225 +++++++++++ .../lib/random_bytes_com_dotnet.php | 88 +++++ .../lib/random_bytes_dev_urandom.php | 167 ++++++++ .../lib/random_bytes_libsodium.php | 88 +++++ .../lib/random_bytes_libsodium_legacy.php | 92 +++++ .../random_compat/lib/random_bytes_mcrypt.php | 77 ++++ .../random_compat/lib/random_int.php | 190 ++++++++++ .../random_compat/other/build_phar.php | 57 +++ .../random_compat/psalm-autoload.php | 9 + vendor/paragonie/random_compat/psalm.xml | 18 + vendor/symfony/lock/.gitignore | 3 + vendor/symfony/lock/CHANGELOG.md | 7 + .../lock/Exception/ExceptionInterface.php | 21 ++ .../Exception/InvalidArgumentException.php | 19 + .../lock/Exception/LockAcquiringException.php | 21 ++ .../Exception/LockConflictedException.php | 21 ++ .../lock/Exception/LockExpiredException.php | 21 ++ .../lock/Exception/LockReleasingException.php | 21 ++ .../lock/Exception/LockStorageException.php | 21 ++ .../lock/Exception/NotSupportedException.php | 21 ++ vendor/symfony/lock/Factory.php | 52 +++ vendor/symfony/lock/Key.php | 109 ++++++ vendor/symfony/lock/LICENSE | 19 + vendor/symfony/lock/Lock.php | 173 +++++++++ vendor/symfony/lock/LockInterface.php | 59 +++ vendor/symfony/lock/README.md | 11 + vendor/symfony/lock/Store/CombinedStore.php | 186 +++++++++ vendor/symfony/lock/Store/FlockStore.php | 141 +++++++ vendor/symfony/lock/Store/MemcachedStore.php | 187 +++++++++ vendor/symfony/lock/Store/RedisStore.php | 166 ++++++++ .../symfony/lock/Store/RetryTillSaveStore.php | 102 +++++ vendor/symfony/lock/Store/SemaphoreStore.php | 129 +++++++ vendor/symfony/lock/Store/StoreFactory.php | 40 ++ vendor/symfony/lock/StoreInterface.php | 64 ++++ .../lock/Strategy/ConsensusStrategy.php | 36 ++ .../lock/Strategy/StrategyInterface.php | 43 +++ .../lock/Strategy/UnanimousStrategy.php | 36 ++ vendor/symfony/lock/Tests/FactoryTest.php | 36 ++ vendor/symfony/lock/Tests/LockTest.php | 254 +++++++++++++ .../Tests/Store/AbstractRedisStoreTest.php | 45 +++ .../lock/Tests/Store/AbstractStoreTest.php | 115 ++++++ .../Tests/Store/BlockingStoreTestTrait.php | 97 +++++ .../lock/Tests/Store/CombinedStoreTest.php | 356 ++++++++++++++++++ .../Tests/Store/ExpiringStoreTestTrait.php | 107 ++++++ .../lock/Tests/Store/FlockStoreTest.php | 78 ++++ .../lock/Tests/Store/MemcachedStoreTest.php | 60 +++ .../lock/Tests/Store/PredisStoreTest.php | 36 ++ .../lock/Tests/Store/RedisArrayStoreTest.php | 38 ++ .../lock/Tests/Store/RedisStoreTest.php | 36 ++ .../Tests/Store/RetryTillSaveStoreTest.php | 35 ++ .../lock/Tests/Store/SemaphoreStoreTest.php | 36 ++ .../Tests/Strategy/ConsensusStrategyTest.php | 89 +++++ .../Tests/Strategy/UnanimousStrategyTest.php | 89 +++++ vendor/symfony/lock/composer.json | 38 ++ vendor/symfony/lock/phpunit.xml.dist | 32 ++ vendor/symfony/polyfill-php70/LICENSE | 19 + vendor/symfony/polyfill-php70/Php70.php | 74 ++++ vendor/symfony/polyfill-php70/README.md | 28 ++ .../Resources/stubs/ArithmeticError.php | 5 + .../Resources/stubs/AssertionError.php | 5 + .../Resources/stubs/DivisionByZeroError.php | 5 + .../polyfill-php70/Resources/stubs/Error.php | 5 + .../Resources/stubs/ParseError.php | 5 + ...SessionUpdateTimestampHandlerInterface.php | 23 ++ .../Resources/stubs/TypeError.php | 5 + vendor/symfony/polyfill-php70/bootstrap.php | 27 ++ vendor/symfony/polyfill-php70/composer.json | 33 ++ 82 files changed, 5316 insertions(+), 2 deletions(-) create mode 100644 vendor/paragonie/random_compat/LICENSE create mode 100644 vendor/paragonie/random_compat/build-phar.sh create mode 100644 vendor/paragonie/random_compat/composer.json create mode 100644 vendor/paragonie/random_compat/dist/random_compat.phar.pubkey create mode 100644 vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc create mode 100644 vendor/paragonie/random_compat/lib/byte_safe_strings.php create mode 100644 vendor/paragonie/random_compat/lib/cast_to_int.php create mode 100644 vendor/paragonie/random_compat/lib/error_polyfill.php create mode 100644 vendor/paragonie/random_compat/lib/random.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php create mode 100644 vendor/paragonie/random_compat/lib/random_int.php create mode 100644 vendor/paragonie/random_compat/other/build_phar.php create mode 100644 vendor/paragonie/random_compat/psalm-autoload.php create mode 100644 vendor/paragonie/random_compat/psalm.xml create mode 100644 vendor/symfony/lock/.gitignore create mode 100644 vendor/symfony/lock/CHANGELOG.md create mode 100644 vendor/symfony/lock/Exception/ExceptionInterface.php create mode 100644 vendor/symfony/lock/Exception/InvalidArgumentException.php create mode 100644 vendor/symfony/lock/Exception/LockAcquiringException.php create mode 100644 vendor/symfony/lock/Exception/LockConflictedException.php create mode 100644 vendor/symfony/lock/Exception/LockExpiredException.php create mode 100644 vendor/symfony/lock/Exception/LockReleasingException.php create mode 100644 vendor/symfony/lock/Exception/LockStorageException.php create mode 100644 vendor/symfony/lock/Exception/NotSupportedException.php create mode 100644 vendor/symfony/lock/Factory.php create mode 100644 vendor/symfony/lock/Key.php create mode 100644 vendor/symfony/lock/LICENSE create mode 100644 vendor/symfony/lock/Lock.php create mode 100644 vendor/symfony/lock/LockInterface.php create mode 100644 vendor/symfony/lock/README.md create mode 100644 vendor/symfony/lock/Store/CombinedStore.php create mode 100644 vendor/symfony/lock/Store/FlockStore.php create mode 100644 vendor/symfony/lock/Store/MemcachedStore.php create mode 100644 vendor/symfony/lock/Store/RedisStore.php create mode 100644 vendor/symfony/lock/Store/RetryTillSaveStore.php create mode 100644 vendor/symfony/lock/Store/SemaphoreStore.php create mode 100644 vendor/symfony/lock/Store/StoreFactory.php create mode 100644 vendor/symfony/lock/StoreInterface.php create mode 100644 vendor/symfony/lock/Strategy/ConsensusStrategy.php create mode 100644 vendor/symfony/lock/Strategy/StrategyInterface.php create mode 100644 vendor/symfony/lock/Strategy/UnanimousStrategy.php create mode 100644 vendor/symfony/lock/Tests/FactoryTest.php create mode 100644 vendor/symfony/lock/Tests/LockTest.php create mode 100644 vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/AbstractStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php create mode 100644 vendor/symfony/lock/Tests/Store/CombinedStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php create mode 100644 vendor/symfony/lock/Tests/Store/FlockStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/PredisStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/RedisStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php create mode 100644 vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php create mode 100644 vendor/symfony/lock/composer.json create mode 100644 vendor/symfony/lock/phpunit.xml.dist create mode 100644 vendor/symfony/polyfill-php70/LICENSE create mode 100644 vendor/symfony/polyfill-php70/Php70.php create mode 100644 vendor/symfony/polyfill-php70/README.md create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/Error.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php create mode 100644 vendor/symfony/polyfill-php70/bootstrap.php create mode 100644 vendor/symfony/polyfill-php70/composer.json diff --git a/composer.json b/composer.json index c8b0e570..ea4ebc53 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ "firephp/firephp-core": "^0.4.0", "vlucas/valitron": "^1.4", "php-extended/php-tail": "^2.1", - "pguardiario/phpuri": "^1.0" + "pguardiario/phpuri": "^1.0", + "symfony/lock": "^3.4" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 43411eaf..5ce4f436 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "1753c2c2ad9fe40ecc5c6ae541dd2e78", + "content-hash": "a329d39be5161c87438d41f9adf4417b", "packages": [ { "name": "brandonwamboldt/utilphp", @@ -454,6 +454,54 @@ ], "time": "2017-06-19T01:22:40+00:00" }, + { + "name": "paragonie/random_compat", + "version": "v2.0.12", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2018-04-04T21:24:14+00:00" + }, { "name": "pguardiario/phpuri", "version": "1.0", @@ -702,6 +750,127 @@ ], "time": "2014-06-16T22:40:22+00:00" }, + { + "name": "symfony/lock", + "version": "v3.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/lock.git", + "reference": "3a707193326d31603824706e34a95af899a59788" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/lock/zipball/3a707193326d31603824706e34a95af899a59788", + "reference": "3a707193326d31603824706e34a95af899a59788", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0", + "symfony/polyfill-php70": "~1.0" + }, + "require-dev": { + "predis/predis": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Lock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Jérémy Derussé", + "email": "jeremy@derusse.com" + } + ], + "description": "Symfony Lock Component", + "homepage": "https://symfony.com", + "keywords": [ + "cas", + "flock", + "locking", + "mutex", + "redlock", + "semaphore" + ], + "time": "2018-04-29T14:44:26+00:00" + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/77454693d8f10dd23bb24955cffd2d82db1007a6", + "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2018-04-26T10:06:28+00:00" + }, { "name": "vlucas/valitron", "version": "v1.4.2", diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 0f375530..e8398d99 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,14 +6,21 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', + 'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', 'DB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'DBHelper' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'DBTransaction' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', + 'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php', 'FB' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/fb.php', 'FirePHP' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php', 'MeekroDB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBEval' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBException' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', + 'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', + 'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', 'WhereClause' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'kakao\\KakaoKey' => $baseDir . '/d_setting/KakaoKey.php', 'sammo\\RootDB' => $baseDir . '/d_setting/RootDB.php', diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index 325499f6..350100b3 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,8 +6,10 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', + '023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', '5b154887902198b16314243c6e0e3e19' => $vendorDir . '/pguardiario/phpuri/phpuri.php', '870dc64919afa8b0f700701bb2c6a783' => $baseDir . '/f_config/config.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index a422d325..c11d2d90 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -8,6 +8,8 @@ $baseDir = dirname($vendorDir); return array( 'sammo\\' => array($baseDir . '/src/sammo'), 'kakao\\' => array($baseDir . '/src/kakao'), + 'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'), + 'Symfony\\Component\\Lock\\' => array($vendorDir . '/symfony/lock'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'PhpExtended\\Tail\\' => array($vendorDir . '/php-extended/php-tail/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 78b46bcf..0811ecbf 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -7,8 +7,10 @@ namespace Composer\Autoload; class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a { public static $files = array ( + '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', + '023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', '5b154887902198b16314243c6e0e3e19' => __DIR__ . '/..' . '/pguardiario/phpuri/phpuri.php', '870dc64919afa8b0f700701bb2c6a783' => __DIR__ . '/../..' . '/f_config/config.php', @@ -23,6 +25,11 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a array ( 'kakao\\' => 6, ), + 'S' => + array ( + 'Symfony\\Polyfill\\Php70\\' => 23, + 'Symfony\\Component\\Lock\\' => 23, + ), 'P' => array ( 'Psr\\Log\\' => 8, @@ -56,6 +63,14 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a array ( 0 => __DIR__ . '/../..' . '/src/kakao', ), + 'Symfony\\Polyfill\\Php70\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php70', + ), + 'Symfony\\Component\\Lock\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/lock', + ), 'Psr\\Log\\' => array ( 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', @@ -116,14 +131,21 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a ); public static $classMap = array ( + 'ArithmeticError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', + 'AssertionError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', 'DB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'DBHelper' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'DBTransaction' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'DivisionByZeroError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', + 'Error' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/Error.php', 'FB' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/fb.php', 'FirePHP' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php', 'MeekroDB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBEval' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBException' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'ParseError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', + 'SessionUpdateTimestampHandlerInterface' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', + 'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', 'WhereClause' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'kakao\\KakaoKey' => __DIR__ . '/../..' . '/d_setting/KakaoKey.php', 'sammo\\RootDB' => __DIR__ . '/../..' . '/d_setting/RootDB.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index c2931551..5c44110b 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -463,6 +463,56 @@ "psr-3" ] }, + { + "name": "paragonie/random_compat", + "version": "v2.0.12", + "version_normalized": "2.0.12.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "time": "2018-04-04T21:24:14+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ] + }, { "name": "pguardiario/phpuri", "version": "1.0", @@ -723,6 +773,131 @@ "pdo" ] }, + { + "name": "symfony/lock", + "version": "v3.4.9", + "version_normalized": "3.4.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/lock.git", + "reference": "3a707193326d31603824706e34a95af899a59788" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/lock/zipball/3a707193326d31603824706e34a95af899a59788", + "reference": "3a707193326d31603824706e34a95af899a59788", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0", + "symfony/polyfill-php70": "~1.0" + }, + "require-dev": { + "predis/predis": "~1.0" + }, + "time": "2018-04-29T14:44:26+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Lock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Jérémy Derussé", + "email": "jeremy@derusse.com" + } + ], + "description": "Symfony Lock Component", + "homepage": "https://symfony.com", + "keywords": [ + "cas", + "flock", + "locking", + "mutex", + "redlock", + "semaphore" + ] + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.8.0", + "version_normalized": "1.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/77454693d8f10dd23bb24955cffd2d82db1007a6", + "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0", + "php": ">=5.3.3" + }, + "time": "2018-04-26T10:06:28+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ] + }, { "name": "vlucas/valitron", "version": "v1.4.2", diff --git a/vendor/paragonie/random_compat/LICENSE b/vendor/paragonie/random_compat/LICENSE new file mode 100644 index 00000000..45c7017d --- /dev/null +++ b/vendor/paragonie/random_compat/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paragon Initiative Enterprises + +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/vendor/paragonie/random_compat/build-phar.sh b/vendor/paragonie/random_compat/build-phar.sh new file mode 100644 index 00000000..b4a5ba31 --- /dev/null +++ b/vendor/paragonie/random_compat/build-phar.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) ) + +php -dphar.readonly=0 "$basedir/other/build_phar.php" $* \ No newline at end of file diff --git a/vendor/paragonie/random_compat/composer.json b/vendor/paragonie/random_compat/composer.json new file mode 100644 index 00000000..1c5978c6 --- /dev/null +++ b/vendor/paragonie/random_compat/composer.json @@ -0,0 +1,37 @@ +{ + "name": "paragonie/random_compat", + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "random", + "pseudorandom" + ], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "support": { + "issues": "https://github.com/paragonie/random_compat/issues", + "email": "info@paragonie.com", + "source": "https://github.com/paragonie/random_compat" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "autoload": { + "files": [ + "lib/random.php" + ] + } +} diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey new file mode 100644 index 00000000..eb50ebfc --- /dev/null +++ b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm +pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p ++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc +-----END PUBLIC KEY----- diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc new file mode 100644 index 00000000..6a1d7f30 --- /dev/null +++ b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (MingW32) + +iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip +QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg +1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW +NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA +NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV +JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74= +=B6+8 +-----END PGP SIGNATURE----- diff --git a/vendor/paragonie/random_compat/lib/byte_safe_strings.php b/vendor/paragonie/random_compat/lib/byte_safe_strings.php new file mode 100644 index 00000000..3de86b22 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/byte_safe_strings.php @@ -0,0 +1,181 @@ + RandomCompat_strlen($binary_string)) { + return ''; + } + + return (string) mb_substr($binary_string, $start, $length, '8bit'); + } + + } else { + + /** + * substr() implementation that isn't brittle to mbstring.func_overload + * + * This version just uses the default substr() + * + * @param string $binary_string + * @param int $start + * @param int $length (optional) + * + * @throws TypeError + * + * @return string + */ + function RandomCompat_substr($binary_string, $start, $length = null) + { + if (!is_string($binary_string)) { + throw new TypeError( + 'RandomCompat_substr(): First argument should be a string' + ); + } + + if (!is_int($start)) { + throw new TypeError( + 'RandomCompat_substr(): Second argument should be an integer' + ); + } + + if ($length !== null) { + if (!is_int($length)) { + throw new TypeError( + 'RandomCompat_substr(): Third argument should be an integer, or omitted' + ); + } + + return (string) substr($binary_string, $start, $length); + } + + return (string) substr($binary_string, $start); + } + } +} diff --git a/vendor/paragonie/random_compat/lib/cast_to_int.php b/vendor/paragonie/random_compat/lib/cast_to_int.php new file mode 100644 index 00000000..9a4fab99 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/cast_to_int.php @@ -0,0 +1,75 @@ + operators might accidentally let a float + * through. + * + * @param int|float $number The number we want to convert to an int + * @param bool $fail_open Set to true to not throw an exception + * + * @return float|int + * @psalm-suppress InvalidReturnType + * + * @throws TypeError + */ + function RandomCompat_intval($number, $fail_open = false) + { + if (is_int($number) || is_float($number)) { + $number += 0; + } elseif (is_numeric($number)) { + $number += 0; + } + + if ( + is_float($number) + && + $number > ~PHP_INT_MAX + && + $number < PHP_INT_MAX + ) { + $number = (int) $number; + } + + if (is_int($number)) { + return (int) $number; + } elseif (!$fail_open) { + throw new TypeError( + 'Expected an integer.' + ); + } + return $number; + } +} diff --git a/vendor/paragonie/random_compat/lib/error_polyfill.php b/vendor/paragonie/random_compat/lib/error_polyfill.php new file mode 100644 index 00000000..6a91990c --- /dev/null +++ b/vendor/paragonie/random_compat/lib/error_polyfill.php @@ -0,0 +1,49 @@ += 70000) { + return; +} + +if (!defined('RANDOM_COMPAT_READ_BUFFER')) { + define('RANDOM_COMPAT_READ_BUFFER', 8); +} + +$RandomCompatDIR = dirname(__FILE__); + +require_once $RandomCompatDIR . '/byte_safe_strings.php'; +require_once $RandomCompatDIR . '/cast_to_int.php'; +require_once $RandomCompatDIR . '/error_polyfill.php'; + +if (!is_callable('random_bytes')) { + /** + * PHP 5.2.0 - 5.6.x way to implement random_bytes() + * + * We use conditional statements here to define the function in accordance + * to the operating environment. It's a micro-optimization. + * + * In order of preference: + * 1. Use libsodium if available. + * 2. fread() /dev/urandom if available (never on Windows) + * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) + * 4. COM('CAPICOM.Utilities.1')->GetRandom() + * + * See RATIONALE.md for our reasoning behind this particular order + */ + if (extension_loaded('libsodium')) { + // See random_bytes_libsodium.php + if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) { + require_once $RandomCompatDIR . '/random_bytes_libsodium.php'; + } elseif (method_exists('Sodium', 'randombytes_buf')) { + require_once $RandomCompatDIR . '/random_bytes_libsodium_legacy.php'; + } + } + + /** + * Reading directly from /dev/urandom: + */ + if (DIRECTORY_SEPARATOR === '/') { + // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast + // way to exclude Windows. + $RandomCompatUrandom = true; + $RandomCompat_basedir = ini_get('open_basedir'); + + if (!empty($RandomCompat_basedir)) { + $RandomCompat_open_basedir = explode( + PATH_SEPARATOR, + strtolower($RandomCompat_basedir) + ); + $RandomCompatUrandom = (array() !== array_intersect( + array('/dev', '/dev/', '/dev/urandom'), + $RandomCompat_open_basedir + )); + $RandomCompat_open_basedir = null; + } + + if ( + !is_callable('random_bytes') + && + $RandomCompatUrandom + && + @is_readable('/dev/urandom') + ) { + // Error suppression on is_readable() in case of an open_basedir + // or safe_mode failure. All we care about is whether or not we + // can read it at this point. If the PHP environment is going to + // panic over trying to see if the file can be read in the first + // place, that is not helpful to us here. + + // See random_bytes_dev_urandom.php + require_once $RandomCompatDIR . '/random_bytes_dev_urandom.php'; + } + // Unset variables after use + $RandomCompat_basedir = null; + } else { + $RandomCompatUrandom = false; + } + + /** + * mcrypt_create_iv() + * + * We only want to use mcypt_create_iv() if: + * + * - random_bytes() hasn't already been defined + * - the mcrypt extensions is loaded + * - One of these two conditions is true: + * - We're on Windows (DIRECTORY_SEPARATOR !== '/') + * - We're not on Windows and /dev/urandom is readabale + * (i.e. we're not in a chroot jail) + * - Special case: + * - If we're not on Windows, but the PHP version is between + * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will + * hang indefinitely. This is bad. + * - If we're on Windows, we want to use PHP >= 5.3.7 or else + * we get insufficient entropy errors. + */ + if ( + !is_callable('random_bytes') + && + // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be. + (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) + && + // Prevent this code from hanging indefinitely on non-Windows; + // see https://bugs.php.net/bug.php?id=69833 + ( + DIRECTORY_SEPARATOR !== '/' || + (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) + ) + && + extension_loaded('mcrypt') + ) { + // See random_bytes_mcrypt.php + require_once $RandomCompatDIR . '/random_bytes_mcrypt.php'; + } + $RandomCompatUrandom = null; + + /** + * This is a Windows-specific fallback, for when the mcrypt extension + * isn't loaded. + */ + if ( + !is_callable('random_bytes') + && + extension_loaded('com_dotnet') + && + class_exists('COM') + ) { + $RandomCompat_disabled_classes = preg_split( + '#\s*,\s*#', + strtolower(ini_get('disable_classes')) + ); + + if (!in_array('com', $RandomCompat_disabled_classes)) { + try { + $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); + if (method_exists($RandomCompatCOMtest, 'GetRandom')) { + // See random_bytes_com_dotnet.php + require_once $RandomCompatDIR . '/random_bytes_com_dotnet.php'; + } + } catch (com_exception $e) { + // Don't try to use it. + } + } + $RandomCompat_disabled_classes = null; + $RandomCompatCOMtest = null; + } + + /** + * throw new Exception + */ + if (!is_callable('random_bytes')) { + /** + * We don't have any more options, so let's throw an exception right now + * and hope the developer won't let it fail silently. + * + * @param mixed $length + * @psalm-suppress MissingReturnType + * @throws Exception + * @return string + */ + function random_bytes($length) + { + unset($length); // Suppress "variable not used" warnings. + throw new Exception( + 'There is no suitable CSPRNG installed on your system' + ); + return ''; + } + } +} + +if (!is_callable('random_int')) { + require_once $RandomCompatDIR . '/random_int.php'; +} + +$RandomCompatDIR = null; diff --git a/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php new file mode 100644 index 00000000..fc1926e5 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php @@ -0,0 +1,88 @@ +GetRandom($bytes, 0)); + if (RandomCompat_strlen($buf) >= $bytes) { + /** + * Return our random entropy buffer here: + */ + return RandomCompat_substr($buf, 0, $bytes); + } + ++$execCount; + } while ($execCount < $bytes); + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} \ No newline at end of file diff --git a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php new file mode 100644 index 00000000..df5b9152 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php @@ -0,0 +1,167 @@ + 0); + + /** + * Is our result valid? + */ + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + /** + * Return our random entropy buffer here: + */ + return $buf; + } + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Error reading from source device' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php new file mode 100644 index 00000000..4af1a242 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php @@ -0,0 +1,88 @@ + 2147483647) { + $buf = ''; + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= \Sodium\randombytes_buf($n); + } + } else { + $buf = \Sodium\randombytes_buf($bytes); + } + + if ($buf !== false) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php new file mode 100644 index 00000000..705af526 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php @@ -0,0 +1,92 @@ + 2147483647) { + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= Sodium::randombytes_buf((int) $n); + } + } else { + $buf .= Sodium::randombytes_buf((int) $bytes); + } + + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php new file mode 100644 index 00000000..aac9c013 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php @@ -0,0 +1,77 @@ + operators might accidentally let a float + * through. + */ + + try { + $min = RandomCompat_intval($min); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $min must be an integer' + ); + } + + try { + $max = RandomCompat_intval($max); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $max must be an integer' + ); + } + + /** + * Now that we've verified our weak typing system has given us an integer, + * let's validate the logic then we can move forward with generating random + * integers along a given range. + */ + if ($min > $max) { + throw new Error( + 'Minimum value must be less than or equal to the maximum value' + ); + } + + if ($max === $min) { + return (int) $min; + } + + /** + * Initialize variables to 0 + * + * We want to store: + * $bytes => the number of random bytes we need + * $mask => an integer bitmask (for use with the &) operator + * so we can minimize the number of discards + */ + $attempts = $bits = $bytes = $mask = $valueShift = 0; + + /** + * At this point, $range is a positive number greater than 0. It might + * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to + * a float and we will lose some precision. + */ + $range = $max - $min; + + /** + * Test for integer overflow: + */ + if (!is_int($range)) { + + /** + * Still safely calculate wider ranges. + * Provided by @CodesInChaos, @oittaa + * + * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 + * + * We use ~0 as a mask in this case because it generates all 1s + * + * @ref https://eval.in/400356 (32-bit) + * @ref http://3v4l.org/XX9r5 (64-bit) + */ + $bytes = PHP_INT_SIZE; + $mask = ~0; + + } else { + + /** + * $bits is effectively ceil(log($range, 2)) without dealing with + * type juggling + */ + while ($range > 0) { + if ($bits % 8 === 0) { + ++$bytes; + } + ++$bits; + $range >>= 1; + $mask = $mask << 1 | 1; + } + $valueShift = $min; + } + + $val = 0; + /** + * Now that we have our parameters set up, let's begin generating + * random integers until one falls between $min and $max + */ + do { + /** + * The rejection probability is at most 0.5, so this corresponds + * to a failure probability of 2^-128 for a working RNG + */ + if ($attempts > 128) { + throw new Exception( + 'random_int: RNG is broken - too many rejections' + ); + } + + /** + * Let's grab the necessary number of random bytes + */ + $randomByteString = random_bytes($bytes); + + /** + * Let's turn $randomByteString into an integer + * + * This uses bitwise operators (<< and |) to build an integer + * out of the values extracted from ord() + * + * Example: [9F] | [6D] | [32] | [0C] => + * 159 + 27904 + 3276800 + 201326592 => + * 204631455 + */ + $val &= 0; + for ($i = 0; $i < $bytes; ++$i) { + $val |= ord($randomByteString[$i]) << ($i * 8); + } + + /** + * Apply mask + */ + $val &= $mask; + $val += $valueShift; + + ++$attempts; + /** + * If $val overflows to a floating point number, + * ... or is larger than $max, + * ... or smaller than $min, + * then try again. + */ + } while (!is_int($val) || $val > $max || $val < $min); + + return (int) $val; + } +} diff --git a/vendor/paragonie/random_compat/other/build_phar.php b/vendor/paragonie/random_compat/other/build_phar.php new file mode 100644 index 00000000..70ef4b2e --- /dev/null +++ b/vendor/paragonie/random_compat/other/build_phar.php @@ -0,0 +1,57 @@ +buildFromDirectory(dirname(__DIR__).'/lib'); +rename( + dirname(__DIR__).'/lib/index.php', + dirname(__DIR__).'/lib/random.php' +); + +/** + * If we pass an (optional) path to a private key as a second argument, we will + * sign the Phar with OpenSSL. + * + * If you leave this out, it will produce an unsigned .phar! + */ +if ($argc > 1) { + if (!@is_readable($argv[1])) { + echo 'Could not read the private key file:', $argv[1], "\n"; + exit(255); + } + $pkeyFile = file_get_contents($argv[1]); + + $private = openssl_get_privatekey($pkeyFile); + if ($private !== false) { + $pkey = ''; + openssl_pkey_export($private, $pkey); + $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + + /** + * Save the corresponding public key to the file + */ + if (!@is_readable($dist.'/random_compat.phar.pubkey')) { + $details = openssl_pkey_get_details($private); + file_put_contents( + $dist.'/random_compat.phar.pubkey', + $details['key'] + ); + } + } else { + echo 'An error occurred reading the private key from OpenSSL.', "\n"; + exit(255); + } +} diff --git a/vendor/paragonie/random_compat/psalm-autoload.php b/vendor/paragonie/random_compat/psalm-autoload.php new file mode 100644 index 00000000..d71d1b81 --- /dev/null +++ b/vendor/paragonie/random_compat/psalm-autoload.php @@ -0,0 +1,9 @@ + + + + + + + + + + + + + + diff --git a/vendor/symfony/lock/.gitignore b/vendor/symfony/lock/.gitignore new file mode 100644 index 00000000..5414c2c6 --- /dev/null +++ b/vendor/symfony/lock/.gitignore @@ -0,0 +1,3 @@ +composer.lock +phpunit.xml +vendor/ diff --git a/vendor/symfony/lock/CHANGELOG.md b/vendor/symfony/lock/CHANGELOG.md new file mode 100644 index 00000000..8e992b98 --- /dev/null +++ b/vendor/symfony/lock/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +3.4.0 +----- + + * added the component diff --git a/vendor/symfony/lock/Exception/ExceptionInterface.php b/vendor/symfony/lock/Exception/ExceptionInterface.php new file mode 100644 index 00000000..0d419584 --- /dev/null +++ b/vendor/symfony/lock/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * Base ExceptionInterface for the Lock Component. + * + * @author Jérémy Derussé + */ +interface ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/InvalidArgumentException.php b/vendor/symfony/lock/Exception/InvalidArgumentException.php new file mode 100644 index 00000000..f2f74b37 --- /dev/null +++ b/vendor/symfony/lock/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * @author Jérémy Derussé + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockAcquiringException.php b/vendor/symfony/lock/Exception/LockAcquiringException.php new file mode 100644 index 00000000..e6756aec --- /dev/null +++ b/vendor/symfony/lock/Exception/LockAcquiringException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockAcquiringException is thrown when an issue happens during the acquisition of a lock. + * + * @author Jérémy Derussé + */ +class LockAcquiringException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockConflictedException.php b/vendor/symfony/lock/Exception/LockConflictedException.php new file mode 100644 index 00000000..8fcd6a83 --- /dev/null +++ b/vendor/symfony/lock/Exception/LockConflictedException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockConflictedException is thrown when a lock is acquired by someone else. + * + * @author Jérémy Derussé + */ +class LockConflictedException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockExpiredException.php b/vendor/symfony/lock/Exception/LockExpiredException.php new file mode 100644 index 00000000..9b712ae0 --- /dev/null +++ b/vendor/symfony/lock/Exception/LockExpiredException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockExpiredException is thrown when a lock may conflict due to a TTL expiration. + * + * @author Jérémy Derussé + */ +class LockExpiredException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockReleasingException.php b/vendor/symfony/lock/Exception/LockReleasingException.php new file mode 100644 index 00000000..56eedde7 --- /dev/null +++ b/vendor/symfony/lock/Exception/LockReleasingException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockReleasingException is thrown when an issue happens during the release of a lock. + * + * @author Jérémy Derussé + */ +class LockReleasingException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockStorageException.php b/vendor/symfony/lock/Exception/LockStorageException.php new file mode 100644 index 00000000..8c393fc1 --- /dev/null +++ b/vendor/symfony/lock/Exception/LockStorageException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockStorageException is thrown when an issue happens during the manipulation of a lock in a store. + * + * @author Jérémy Derussé + */ +class LockStorageException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/NotSupportedException.php b/vendor/symfony/lock/Exception/NotSupportedException.php new file mode 100644 index 00000000..c9a7f013 --- /dev/null +++ b/vendor/symfony/lock/Exception/NotSupportedException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * NotSupportedException is thrown when an unsupported method is called. + * + * @author Jérémy Derussé + */ +class NotSupportedException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Factory.php b/vendor/symfony/lock/Factory.php new file mode 100644 index 00000000..e9fdde97 --- /dev/null +++ b/vendor/symfony/lock/Factory.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; + +/** + * Factory provides method to create locks. + * + * @author Jérémy Derussé + */ +class Factory implements LoggerAwareInterface +{ + use LoggerAwareTrait; + + private $store; + + public function __construct(StoreInterface $store) + { + $this->store = $store; + + $this->logger = new NullLogger(); + } + + /** + * Creates a lock for the given resource. + * + * @param string $resource The resource to lock + * @param float $ttl Maximum expected lock duration in seconds + * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed + * + * @return Lock + */ + public function createLock($resource, $ttl = 300.0, $autoRelease = true) + { + $lock = new Lock(new Key($resource), $this->store, $ttl, $autoRelease); + $lock->setLogger($this->logger); + + return $lock; + } +} diff --git a/vendor/symfony/lock/Key.php b/vendor/symfony/lock/Key.php new file mode 100644 index 00000000..8be4f3a2 --- /dev/null +++ b/vendor/symfony/lock/Key.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +/** + * Key is a container for the state of the locks in stores. + * + * @author Jérémy Derussé + */ +final class Key +{ + private $resource; + private $expiringTime; + private $state = array(); + + /** + * @param string $resource + */ + public function __construct($resource) + { + $this->resource = (string) $resource; + } + + public function __toString() + { + return $this->resource; + } + + /** + * @param string $stateKey + * + * @return bool + */ + public function hasState($stateKey) + { + return isset($this->state[$stateKey]); + } + + /** + * @param string $stateKey + * @param mixed $state + */ + public function setState($stateKey, $state) + { + $this->state[$stateKey] = $state; + } + + /** + * @param string $stateKey + */ + public function removeState($stateKey) + { + unset($this->state[$stateKey]); + } + + /** + * @param $stateKey + * + * @return mixed + */ + public function getState($stateKey) + { + return $this->state[$stateKey]; + } + + public function resetLifetime() + { + $this->expiringTime = null; + } + + /** + * @param float $ttl the expiration delay of locks in seconds + */ + public function reduceLifetime($ttl) + { + $newTime = microtime(true) + $ttl; + + if (null === $this->expiringTime || $this->expiringTime > $newTime) { + $this->expiringTime = $newTime; + } + } + + /** + * Returns the remaining lifetime. + * + * @return float|null Remaining lifetime in seconds. Null when the key won't expire. + */ + public function getRemainingLifetime() + { + return null === $this->expiringTime ? null : $this->expiringTime - microtime(true); + } + + /** + * @return bool + */ + public function isExpired() + { + return null !== $this->expiringTime && $this->expiringTime <= microtime(true); + } +} diff --git a/vendor/symfony/lock/LICENSE b/vendor/symfony/lock/LICENSE new file mode 100644 index 00000000..fcd3fa76 --- /dev/null +++ b/vendor/symfony/lock/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2016-2018 Fabien Potencier + +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/vendor/symfony/lock/Lock.php b/vendor/symfony/lock/Lock.php new file mode 100644 index 00000000..77fd032b --- /dev/null +++ b/vendor/symfony/lock/Lock.php @@ -0,0 +1,173 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockAcquiringException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockExpiredException; +use Symfony\Component\Lock\Exception\LockReleasingException; + +/** + * Lock is the default implementation of the LockInterface. + * + * @author Jérémy Derussé + */ +final class Lock implements LockInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + private $store; + private $key; + private $ttl; + private $autoRelease; + private $dirty = false; + + /** + * @param Key $key Resource to lock + * @param StoreInterface $store Store used to handle lock persistence + * @param float|null $ttl Maximum expected lock duration in seconds + * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed + */ + public function __construct(Key $key, StoreInterface $store, $ttl = null, $autoRelease = true) + { + $this->store = $store; + $this->key = $key; + $this->ttl = $ttl; + $this->autoRelease = (bool) $autoRelease; + + $this->logger = new NullLogger(); + } + + /** + * Automatically releases the underlying lock when the object is destructed. + */ + public function __destruct() + { + if (!$this->autoRelease || !$this->dirty || !$this->isAcquired()) { + return; + } + + $this->release(); + } + + /** + * {@inheritdoc} + */ + public function acquire($blocking = false) + { + try { + if (!$blocking) { + $this->store->save($this->key); + } else { + $this->store->waitAndSave($this->key); + } + + $this->dirty = true; + $this->logger->info('Successfully acquired the "{resource}" lock.', array('resource' => $this->key)); + + if ($this->ttl) { + $this->refresh(); + } + + if ($this->key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $this->key)); + } + + return true; + } catch (LockConflictedException $e) { + $this->dirty = false; + $this->logger->notice('Failed to acquire the "{resource}" lock. Someone else already acquired the lock.', array('resource' => $this->key)); + + if ($blocking) { + throw $e; + } + + return false; + } catch (\Exception $e) { + $this->logger->notice('Failed to acquire the "{resource}" lock.', array('resource' => $this->key, 'exception' => $e)); + throw new LockAcquiringException(sprintf('Failed to acquire the "%s" lock.', $this->key), 0, $e); + } + } + + /** + * {@inheritdoc} + */ + public function refresh() + { + if (!$this->ttl) { + throw new InvalidArgumentException('You have to define an expiration duration.'); + } + + try { + $this->key->resetLifetime(); + $this->store->putOffExpiration($this->key, $this->ttl); + $this->dirty = true; + + if ($this->key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $this->key)); + } + + $this->logger->info('Expiration defined for "{resource}" lock for "{ttl}" seconds.', array('resource' => $this->key, 'ttl' => $this->ttl)); + } catch (LockConflictedException $e) { + $this->dirty = false; + $this->logger->notice('Failed to define an expiration for the "{resource}" lock, someone else acquired the lock.', array('resource' => $this->key)); + throw $e; + } catch (\Exception $e) { + $this->logger->notice('Failed to define an expiration for the "{resource}" lock.', array('resource' => $this->key, 'exception' => $e)); + throw new LockAcquiringException(sprintf('Failed to define an expiration for the "%s" lock.', $this->key), 0, $e); + } + } + + /** + * {@inheritdoc} + */ + public function isAcquired() + { + return $this->dirty = $this->store->exists($this->key); + } + + /** + * {@inheritdoc} + */ + public function release() + { + $this->store->delete($this->key); + $this->dirty = false; + + if ($this->store->exists($this->key)) { + $this->logger->notice('Failed to release the "{resource}" lock.', array('resource' => $this->key)); + throw new LockReleasingException(sprintf('Failed to release the "%s" lock.', $this->key)); + } + } + + /** + * @return bool + */ + public function isExpired() + { + return $this->key->isExpired(); + } + + /** + * Returns the remaining lifetime. + * + * @return float|null Remaining lifetime in seconds. Null when the lock won't expire. + */ + public function getRemainingLifetime() + { + return $this->key->getRemainingLifetime(); + } +} diff --git a/vendor/symfony/lock/LockInterface.php b/vendor/symfony/lock/LockInterface.php new file mode 100644 index 00000000..437a4cc2 --- /dev/null +++ b/vendor/symfony/lock/LockInterface.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +use Symfony\Component\Lock\Exception\LockAcquiringException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockReleasingException; + +/** + * LockInterface defines an interface to manipulate the status of a lock. + * + * @author Jérémy Derussé + */ +interface LockInterface +{ + /** + * Acquires the lock. If the lock is acquired by someone else, the parameter `blocking` determines whether or not + * the the call should block until the release of the lock. + * + * @param bool $blocking Whether or not the Lock should wait for the release of someone else + * + * @return bool whether or not the lock had been acquired + * + * @throws LockConflictedException If the lock is acquired by someone else in blocking mode + * @throws LockAcquiringException If the lock can not be acquired + */ + public function acquire($blocking = false); + + /** + * Increase the duration of an acquired lock. + * + * @throws LockConflictedException If the lock is acquired by someone else + * @throws LockAcquiringException If the lock can not be refreshed + */ + public function refresh(); + + /** + * Returns whether or not the lock is acquired. + * + * @return bool + */ + public function isAcquired(); + + /** + * Release the lock. + * + * @throws LockReleasingException If the lock can not be released + */ + public function release(); +} diff --git a/vendor/symfony/lock/README.md b/vendor/symfony/lock/README.md new file mode 100644 index 00000000..0be0bfd4 --- /dev/null +++ b/vendor/symfony/lock/README.md @@ -0,0 +1,11 @@ +Lock Component +============== + +Resources +--------- + + * [Documentation](https://symfony.com/doc/master/components/lock.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/lock/Store/CombinedStore.php b/vendor/symfony/lock/Store/CombinedStore.php new file mode 100644 index 00000000..50258fe6 --- /dev/null +++ b/vendor/symfony/lock/Store/CombinedStore.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockExpiredException; +use Symfony\Component\Lock\Exception\NotSupportedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\Strategy\StrategyInterface; +use Symfony\Component\Lock\StoreInterface; + +/** + * CombinedStore is a StoreInterface implementation able to manage and synchronize several StoreInterfaces. + * + * @author Jérémy Derussé + */ +class CombinedStore implements StoreInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + /** @var StoreInterface[] */ + private $stores; + /** @var StrategyInterface */ + private $strategy; + + /** + * @param StoreInterface[] $stores The list of synchronized stores + * @param StrategyInterface $strategy + * + * @throws InvalidArgumentException + */ + public function __construct(array $stores, StrategyInterface $strategy) + { + foreach ($stores as $store) { + if (!$store instanceof StoreInterface) { + throw new InvalidArgumentException(sprintf('The store must implement "%s". Got "%s".', StoreInterface::class, get_class($store))); + } + } + + $this->stores = $stores; + $this->strategy = $strategy; + $this->logger = new NullLogger(); + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $successCount = 0; + $failureCount = 0; + $storesCount = count($this->stores); + + foreach ($this->stores as $store) { + try { + $store->save($key); + ++$successCount; + } catch (\Exception $e) { + $this->logger->warning('One store failed to save the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'exception' => $e)); + ++$failureCount; + } + + if (!$this->strategy->canBeMet($failureCount, $storesCount)) { + break; + } + } + + if ($this->strategy->isMet($successCount, $storesCount)) { + return; + } + + $this->logger->warning('Failed to store the "{resource}" lock. Quorum has not been met.', array('resource' => $key, 'success' => $successCount, 'failure' => $failureCount)); + + // clean up potential locks + $this->delete($key); + + throw new LockConflictedException(); + } + + public function waitAndSave(Key $key) + { + throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', get_class($this))); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + $successCount = 0; + $failureCount = 0; + $storesCount = count($this->stores); + $expireAt = microtime(true) + $ttl; + + foreach ($this->stores as $store) { + try { + if (0.0 >= $adjustedTtl = $expireAt - microtime(true)) { + $this->logger->warning('Stores took to long to put off the expiration of the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'ttl' => $ttl)); + $key->reduceLifetime(0); + break; + } + + $store->putOffExpiration($key, $adjustedTtl); + ++$successCount; + } catch (\Exception $e) { + $this->logger->warning('One store failed to put off the expiration of the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'exception' => $e)); + ++$failureCount; + } + + if (!$this->strategy->canBeMet($failureCount, $storesCount)) { + break; + } + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key)); + } + + if ($this->strategy->isMet($successCount, $storesCount)) { + return; + } + + $this->logger->warning('Failed to define the expiration for the "{resource}" lock. Quorum has not been met.', array('resource' => $key, 'success' => $successCount, 'failure' => $failureCount)); + + // clean up potential locks + $this->delete($key); + + throw new LockConflictedException(); + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + foreach ($this->stores as $store) { + try { + $store->delete($key); + } catch (\Exception $e) { + $this->logger->notice('One store failed to delete the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'exception' => $e)); + } catch (\Throwable $e) { + $this->logger->notice('One store failed to delete the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'exception' => $e)); + } + } + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + $successCount = 0; + $failureCount = 0; + $storesCount = count($this->stores); + + foreach ($this->stores as $store) { + if ($store->exists($key)) { + ++$successCount; + } else { + ++$failureCount; + } + + if ($this->strategy->isMet($successCount, $storesCount)) { + return true; + } + if (!$this->strategy->canBeMet($failureCount, $storesCount)) { + return false; + } + } + + return false; + } +} diff --git a/vendor/symfony/lock/Store/FlockStore.php b/vendor/symfony/lock/Store/FlockStore.php new file mode 100644 index 00000000..287d6fb5 --- /dev/null +++ b/vendor/symfony/lock/Store/FlockStore.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockStorageException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * FlockStore is a StoreInterface implementation using the FileSystem flock. + * + * Original implementation in \Symfony\Component\Filesystem\LockHandler. + * + * @author Jérémy Derussé + * @author Grégoire Pineau + * @author Romain Neutron + * @author Nicolas Grekas + */ +class FlockStore implements StoreInterface +{ + private $lockPath; + + /** + * @param string|null $lockPath the directory to store the lock, defaults to the system's temporary directory + * + * @throws LockStorageException If the lock directory doesn’t exist or is not writable + */ + public function __construct($lockPath = null) + { + if (null === $lockPath) { + $lockPath = sys_get_temp_dir(); + } + if (!is_dir($lockPath) || !is_writable($lockPath)) { + throw new InvalidArgumentException(sprintf('The directory "%s" is not writable.', $lockPath)); + } + + $this->lockPath = $lockPath; + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $this->lock($key, false); + } + + /** + * {@inheritdoc} + */ + public function waitAndSave(Key $key) + { + $this->lock($key, true); + } + + private function lock(Key $key, $blocking) + { + // The lock is maybe already acquired. + if ($key->hasState(__CLASS__)) { + return; + } + + $fileName = sprintf('%s/sf.%s.%s.lock', + $this->lockPath, + preg_replace('/[^a-z0-9\._-]+/i', '-', $key), + strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_') + ); + + // Silence error reporting + set_error_handler(function () { + }); + if (!$handle = fopen($fileName, 'r')) { + if ($handle = fopen($fileName, 'x')) { + chmod($fileName, 0444); + } elseif (!$handle = fopen($fileName, 'r')) { + usleep(100); // Give some time for chmod() to complete + $handle = fopen($fileName, 'r'); + } + } + restore_error_handler(); + + if (!$handle) { + $error = error_get_last(); + throw new LockStorageException($error['message'], 0, null); + } + + // On Windows, even if PHP doc says the contrary, LOCK_NB works, see + // https://bugs.php.net/54129 + if (!flock($handle, LOCK_EX | ($blocking ? 0 : LOCK_NB))) { + fclose($handle); + throw new LockConflictedException(); + } + + $key->setState(__CLASS__, $handle); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + // do nothing, the flock locks forever. + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + // The lock is maybe not acquired. + if (!$key->hasState(__CLASS__)) { + return; + } + + $handle = $key->getState(__CLASS__); + + flock($handle, LOCK_UN | LOCK_NB); + fclose($handle); + + $key->removeState(__CLASS__); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $key->hasState(__CLASS__); + } +} diff --git a/vendor/symfony/lock/Store/MemcachedStore.php b/vendor/symfony/lock/Store/MemcachedStore.php new file mode 100644 index 00000000..8e9db10c --- /dev/null +++ b/vendor/symfony/lock/Store/MemcachedStore.php @@ -0,0 +1,187 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockExpiredException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * MemcachedStore is a StoreInterface implementation using Memcached as store engine. + * + * @author Jérémy Derussé + */ +class MemcachedStore implements StoreInterface +{ + private $memcached; + private $initialTtl; + /** @var bool */ + private $useExtendedReturn; + + public static function isSupported() + { + return extension_loaded('memcached'); + } + + /** + * @param \Memcached $memcached + * @param int $initialTtl the expiration delay of locks in seconds + */ + public function __construct(\Memcached $memcached, $initialTtl = 300) + { + if (!static::isSupported()) { + throw new InvalidArgumentException('Memcached extension is required'); + } + + if ($initialTtl < 1) { + throw new InvalidArgumentException(sprintf('%s() expects a strictly positive TTL. Got %d.', __METHOD__, $initialTtl)); + } + + $this->memcached = $memcached; + $this->initialTtl = $initialTtl; + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $token = $this->getToken($key); + $key->reduceLifetime($this->initialTtl); + if (!$this->memcached->add((string) $key, $token, (int) ceil($this->initialTtl))) { + // the lock is already acquired. It could be us. Let's try to put off. + $this->putOffExpiration($key, $this->initialTtl); + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $key)); + } + } + + public function waitAndSave(Key $key) + { + throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', get_class($this))); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + if ($ttl < 1) { + throw new InvalidArgumentException(sprintf('%s() expects a TTL greater or equals to 1. Got %s.', __METHOD__, $ttl)); + } + + // Interface defines a float value but Store required an integer. + $ttl = (int) ceil($ttl); + + $token = $this->getToken($key); + + list($value, $cas) = $this->getValueAndCas($key); + + $key->reduceLifetime($ttl); + // Could happens when we ask a putOff after a timeout but in luck nobody steal the lock + if (\Memcached::RES_NOTFOUND === $this->memcached->getResultCode()) { + if ($this->memcached->add((string) $key, $token, $ttl)) { + return; + } + + // no luck, with concurrency, someone else acquire the lock + throw new LockConflictedException(); + } + + // Someone else steal the lock + if ($value !== $token) { + throw new LockConflictedException(); + } + + if (!$this->memcached->cas($cas, (string) $key, $token, $ttl)) { + throw new LockConflictedException(); + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key)); + } + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + $token = $this->getToken($key); + + list($value, $cas) = $this->getValueAndCas($key); + + if ($value !== $token) { + // we are not the owner of the lock. Nothing to do. + return; + } + + // To avoid concurrency in deletion, the trick is to extends the TTL then deleting the key + if (!$this->memcached->cas($cas, (string) $key, $token, 2)) { + // Someone steal our lock. It does not belongs to us anymore. Nothing to do. + return; + } + + // Now, we are the owner of the lock for 2 more seconds, we can delete it. + $this->memcached->delete((string) $key); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $this->memcached->get((string) $key) === $this->getToken($key); + } + + /** + * Retrieve an unique token for the given key. + * + * @param Key $key + * + * @return string + */ + private function getToken(Key $key) + { + if (!$key->hasState(__CLASS__)) { + $token = base64_encode(random_bytes(32)); + $key->setState(__CLASS__, $token); + } + + return $key->getState(__CLASS__); + } + + private function getValueAndCas(Key $key) + { + if (null === $this->useExtendedReturn) { + $this->useExtendedReturn = version_compare(phpversion('memcached'), '2.9.9', '>'); + } + + if ($this->useExtendedReturn) { + $extendedReturn = $this->memcached->get((string) $key, null, \Memcached::GET_EXTENDED); + if (\Memcached::GET_ERROR_RETURN_VALUE === $extendedReturn) { + return array($extendedReturn, 0.0); + } + + return array($extendedReturn['value'], $extendedReturn['cas']); + } + + $cas = 0.0; + $value = $this->memcached->get((string) $key, null, $cas); + + return array($value, $cas); + } +} diff --git a/vendor/symfony/lock/Store/RedisStore.php b/vendor/symfony/lock/Store/RedisStore.php new file mode 100644 index 00000000..4d057337 --- /dev/null +++ b/vendor/symfony/lock/Store/RedisStore.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Cache\Traits\RedisProxy; +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockExpiredException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * RedisStore is a StoreInterface implementation using Redis as store engine. + * + * @author Jérémy Derussé + */ +class RedisStore implements StoreInterface +{ + private $redis; + private $initialTtl; + + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient + * @param float $initialTtl the expiration delay of locks in seconds + */ + public function __construct($redisClient, $initialTtl = 300.0) + { + if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) { + throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, is_object($redisClient) ? get_class($redisClient) : gettype($redisClient))); + } + + if ($initialTtl <= 0) { + throw new InvalidArgumentException(sprintf('%s() expects a strictly positive TTL. Got %d.', __METHOD__, $initialTtl)); + } + + $this->redis = $redisClient; + $this->initialTtl = $initialTtl; + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $script = ' + if redis.call("GET", KEYS[1]) == ARGV[1] then + return redis.call("PEXPIRE", KEYS[1], ARGV[2]) + else + return redis.call("set", KEYS[1], ARGV[1], "NX", "PX", ARGV[2]) + end + '; + + $key->reduceLifetime($this->initialTtl); + if (!$this->evaluate($script, (string) $key, array($this->getToken($key), (int) ceil($this->initialTtl * 1000)))) { + throw new LockConflictedException(); + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $key)); + } + } + + public function waitAndSave(Key $key) + { + throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', get_class($this))); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + $script = ' + if redis.call("GET", KEYS[1]) == ARGV[1] then + return redis.call("PEXPIRE", KEYS[1], ARGV[2]) + else + return 0 + end + '; + + $key->reduceLifetime($ttl); + if (!$this->evaluate($script, (string) $key, array($this->getToken($key), (int) ceil($ttl * 1000)))) { + throw new LockConflictedException(); + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key)); + } + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + $script = ' + if redis.call("GET", KEYS[1]) == ARGV[1] then + return redis.call("DEL", KEYS[1]) + else + return 0 + end + '; + + $this->evaluate($script, (string) $key, array($this->getToken($key))); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $this->redis->get((string) $key) === $this->getToken($key); + } + + /** + * Evaluates a script in the corresponding redis client. + * + * @param string $script + * @param string $resource + * @param array $args + * + * @return mixed + */ + private function evaluate($script, $resource, array $args) + { + if ($this->redis instanceof \Redis || $this->redis instanceof \RedisCluster || $this->redis instanceof RedisProxy) { + return $this->redis->eval($script, array_merge(array($resource), $args), 1); + } + + if ($this->redis instanceof \RedisArray) { + return $this->redis->_instance($this->redis->_target($resource))->eval($script, array_merge(array($resource), $args), 1); + } + + if ($this->redis instanceof \Predis\Client) { + return call_user_func_array(array($this->redis, 'eval'), array_merge(array($script, 1, $resource), $args)); + } + + throw new InvalidArgumentException(sprintf('%s() expects been initialized with a Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, is_object($this->redis) ? get_class($this->redis) : gettype($this->redis))); + } + + /** + * Retrieves an unique token for the given key. + * + * @param Key $key + * + * @return string + */ + private function getToken(Key $key) + { + if (!$key->hasState(__CLASS__)) { + $token = base64_encode(random_bytes(32)); + $key->setState(__CLASS__, $token); + } + + return $key->getState(__CLASS__); + } +} diff --git a/vendor/symfony/lock/Store/RetryTillSaveStore.php b/vendor/symfony/lock/Store/RetryTillSaveStore.php new file mode 100644 index 00000000..dfc3b266 --- /dev/null +++ b/vendor/symfony/lock/Store/RetryTillSaveStore.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * RetryTillSaveStore is a StoreInterface implementation which decorate a non blocking StoreInterface to provide a + * blocking storage. + * + * @author Jérémy Derussé + */ +class RetryTillSaveStore implements StoreInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + private $decorated; + private $retrySleep; + private $retryCount; + + /** + * @param StoreInterface $decorated The decorated StoreInterface + * @param int $retrySleep Duration in ms between 2 retry + * @param int $retryCount Maximum amount of retry + */ + public function __construct(StoreInterface $decorated, $retrySleep = 100, $retryCount = PHP_INT_MAX) + { + $this->decorated = $decorated; + $this->retrySleep = $retrySleep; + $this->retryCount = $retryCount; + + $this->logger = new NullLogger(); + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $this->decorated->save($key); + } + + /** + * {@inheritdoc} + */ + public function waitAndSave(Key $key) + { + $retry = 0; + $sleepRandomness = (int) ($this->retrySleep / 10); + do { + try { + $this->decorated->save($key); + + return; + } catch (LockConflictedException $e) { + usleep(($this->retrySleep + random_int(-$sleepRandomness, $sleepRandomness)) * 1000); + } + } while (++$retry < $this->retryCount); + + $this->logger->warning('Failed to store the "{resource}" lock. Abort after {retry} retry.', array('resource' => $key, 'retry' => $retry)); + + throw new LockConflictedException(); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + $this->decorated->putOffExpiration($key, $ttl); + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + $this->decorated->delete($key); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $this->decorated->exists($key); + } +} diff --git a/vendor/symfony/lock/Store/SemaphoreStore.php b/vendor/symfony/lock/Store/SemaphoreStore.php new file mode 100644 index 00000000..a6cc9ea8 --- /dev/null +++ b/vendor/symfony/lock/Store/SemaphoreStore.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\NotSupportedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * SemaphoreStore is a StoreInterface implementation using Semaphore as store engine. + * + * @author Jérémy Derussé + */ +class SemaphoreStore implements StoreInterface +{ + /** + * Returns whether or not the store is supported. + * + * @param bool|null $blocking when not null, checked again the blocking mode + * + * @return bool + * + * @internal + */ + public static function isSupported($blocking = null) + { + if (!extension_loaded('sysvsem')) { + return false; + } + + if (false === $blocking && \PHP_VERSION_ID < 50601) { + return false; + } + + return true; + } + + public function __construct() + { + if (!static::isSupported()) { + throw new InvalidArgumentException('Semaphore extension (sysvsem) is required'); + } + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $this->lock($key, false); + } + + /** + * {@inheritdoc} + */ + public function waitAndSave(Key $key) + { + $this->lock($key, true); + } + + private function lock(Key $key, $blocking) + { + if ($key->hasState(__CLASS__)) { + return; + } + + $resource = sem_get(crc32($key)); + + if (\PHP_VERSION_ID < 50601) { + if (!$blocking) { + throw new NotSupportedException(sprintf('The store "%s" does not supports non blocking locks.', get_class($this))); + } + + $acquired = sem_acquire($resource); + } else { + $acquired = sem_acquire($resource, !$blocking); + } + + if (!$acquired) { + throw new LockConflictedException(); + } + + $key->setState(__CLASS__, $resource); + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + // The lock is maybe not acquired. + if (!$key->hasState(__CLASS__)) { + return; + } + + $resource = $key->getState(__CLASS__); + + sem_release($resource); + + $key->removeState(__CLASS__); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + // do nothing, the semaphore locks forever. + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $key->hasState(__CLASS__); + } +} diff --git a/vendor/symfony/lock/Store/StoreFactory.php b/vendor/symfony/lock/Store/StoreFactory.php new file mode 100644 index 00000000..a768d197 --- /dev/null +++ b/vendor/symfony/lock/Store/StoreFactory.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Cache\Traits\RedisProxy; +use Symfony\Component\Lock\Exception\InvalidArgumentException; + +/** + * StoreFactory create stores and connections. + * + * @author Jérémy Derussé + */ +class StoreFactory +{ + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|\Memcached $connection + * + * @return RedisStore|MemcachedStore + */ + public static function createStore($connection) + { + if ($connection instanceof \Redis || $connection instanceof \RedisArray || $connection instanceof \RedisCluster || $connection instanceof \Predis\Client || $connection instanceof RedisProxy) { + return new RedisStore($connection); + } + if ($connection instanceof \Memcached) { + return new MemcachedStore($connection); + } + + throw new InvalidArgumentException(sprintf('Unsupported Connection: %s.', get_class($connection))); + } +} diff --git a/vendor/symfony/lock/StoreInterface.php b/vendor/symfony/lock/StoreInterface.php new file mode 100644 index 00000000..985c4476 --- /dev/null +++ b/vendor/symfony/lock/StoreInterface.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\NotSupportedException; + +/** + * StoreInterface defines an interface to manipulate a lock store. + * + * @author Jérémy Derussé + */ +interface StoreInterface +{ + /** + * Stores the resource if it's not locked by someone else. + * + * @throws LockConflictedException + */ + public function save(Key $key); + + /** + * Waits until a key becomes free, then stores the resource. + * + * If the store does not support this feature it should throw a NotSupportedException. + * + * @throws LockConflictedException + * @throws NotSupportedException + */ + public function waitAndSave(Key $key); + + /** + * Extends the ttl of a resource. + * + * If the store does not support this feature it should throw a NotSupportedException. + * + * @param float $ttl amount of second to keep the lock in the store + * + * @throws LockConflictedException + * @throws NotSupportedException + */ + public function putOffExpiration(Key $key, $ttl); + + /** + * Removes a resource from the storage. + */ + public function delete(Key $key); + + /** + * Returns whether or not the resource exists in the storage. + * + * @return bool + */ + public function exists(Key $key); +} diff --git a/vendor/symfony/lock/Strategy/ConsensusStrategy.php b/vendor/symfony/lock/Strategy/ConsensusStrategy.php new file mode 100644 index 00000000..047820a4 --- /dev/null +++ b/vendor/symfony/lock/Strategy/ConsensusStrategy.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Strategy; + +/** + * ConsensusStrategy is a StrategyInterface implementation where strictly more than 50% items should be successful. + * + * @author Jérémy Derussé + */ +class ConsensusStrategy implements StrategyInterface +{ + /** + * {@inheritdoc} + */ + public function isMet($numberOfSuccess, $numberOfItems) + { + return $numberOfSuccess > ($numberOfItems / 2); + } + + /** + * {@inheritdoc} + */ + public function canBeMet($numberOfFailure, $numberOfItems) + { + return $numberOfFailure < ($numberOfItems / 2); + } +} diff --git a/vendor/symfony/lock/Strategy/StrategyInterface.php b/vendor/symfony/lock/Strategy/StrategyInterface.php new file mode 100644 index 00000000..beaa7280 --- /dev/null +++ b/vendor/symfony/lock/Strategy/StrategyInterface.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Strategy; + +/** + * StrategyInterface defines an interface to indicate when a quorum is met and can be met. + * + * @author Jérémy Derussé + */ +interface StrategyInterface +{ + /** + * Returns whether or not the quorum is met. + * + * @param int $numberOfSuccess + * @param int $numberOfItems + * + * @return bool + */ + public function isMet($numberOfSuccess, $numberOfItems); + + /** + * Returns whether or not the quorum *could* be met. + * + * This method does not mean the quorum *would* be met for sure, but can be useful to stop a process early when you + * known there is no chance to meet the quorum. + * + * @param int $numberOfFailure + * @param int $numberOfItems + * + * @return bool + */ + public function canBeMet($numberOfFailure, $numberOfItems); +} diff --git a/vendor/symfony/lock/Strategy/UnanimousStrategy.php b/vendor/symfony/lock/Strategy/UnanimousStrategy.php new file mode 100644 index 00000000..27404f3e --- /dev/null +++ b/vendor/symfony/lock/Strategy/UnanimousStrategy.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Strategy; + +/** + * UnanimousStrategy is a StrategyInterface implementation where 100% of elements should be successful. + * + * @author Jérémy Derussé + */ +class UnanimousStrategy implements StrategyInterface +{ + /** + * {@inheritdoc} + */ + public function isMet($numberOfSuccess, $numberOfItems) + { + return $numberOfSuccess === $numberOfItems; + } + + /** + * {@inheritdoc} + */ + public function canBeMet($numberOfFailure, $numberOfItems) + { + return 0 === $numberOfFailure; + } +} diff --git a/vendor/symfony/lock/Tests/FactoryTest.php b/vendor/symfony/lock/Tests/FactoryTest.php new file mode 100644 index 00000000..d6794909 --- /dev/null +++ b/vendor/symfony/lock/Tests/FactoryTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Lock\Factory; +use Symfony\Component\Lock\LockInterface; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +class FactoryTest extends TestCase +{ + public function testCreateLock() + { + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $factory = new Factory($store); + $factory->setLogger($logger); + + $lock = $factory->createLock('foo'); + + $this->assertInstanceOf(LockInterface::class, $lock); + } +} diff --git a/vendor/symfony/lock/Tests/LockTest.php b/vendor/symfony/lock/Tests/LockTest.php new file mode 100644 index 00000000..7913644b --- /dev/null +++ b/vendor/symfony/lock/Tests/LockTest.php @@ -0,0 +1,254 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\Lock; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +class LockTest extends TestCase +{ + public function testAcquireNoBlocking() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store); + + $store + ->expects($this->once()) + ->method('save'); + + $this->assertTrue($lock->acquire(false)); + } + + public function testAcquireReturnsFalse() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store); + + $store + ->expects($this->once()) + ->method('save') + ->willThrowException(new LockConflictedException()); + + $this->assertFalse($lock->acquire(false)); + } + + public function testAcquireBlocking() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store); + + $store + ->expects($this->never()) + ->method('save'); + $store + ->expects($this->once()) + ->method('waitAndSave'); + + $this->assertTrue($lock->acquire(true)); + } + + public function testAcquireSetsTtl() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->once()) + ->method('save'); + $store + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, 10); + + $lock->acquire(); + } + + public function testRefresh() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, 10); + + $lock->refresh(); + } + + public function testIsAquired() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->any()) + ->method('exists') + ->with($key) + ->will($this->onConsecutiveCalls(true, false)); + + $this->assertTrue($lock->isAcquired()); + } + + public function testRelease() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->once()) + ->method('delete') + ->with($key); + + $store + ->expects($this->once()) + ->method('exists') + ->with($key) + ->willReturn(false); + + $lock->release(); + } + + public function testReleaseOnDestruction() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->method('exists') + ->willReturnOnConsecutiveCalls(array(true, false)) + ; + $store + ->expects($this->once()) + ->method('delete') + ; + + $lock->acquire(false); + unset($lock); + } + + public function testNoAutoReleaseWhenNotConfigured() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10, false); + + $store + ->method('exists') + ->willReturnOnConsecutiveCalls(array(true, false)) + ; + $store + ->expects($this->never()) + ->method('delete') + ; + + $lock->acquire(false); + unset($lock); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\LockReleasingException + */ + public function testReleaseThrowsExceptionIfNotWellDeleted() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->once()) + ->method('delete') + ->with($key); + + $store + ->expects($this->once()) + ->method('exists') + ->with($key) + ->willReturn(true); + + $lock->release(); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\LockReleasingException + */ + public function testReleaseThrowsAndLog() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $lock = new Lock($key, $store, 10, true); + $lock->setLogger($logger); + + $logger->expects($this->atLeastOnce()) + ->method('notice') + ->with('Failed to release the "{resource}" lock.', array('resource' => $key)); + + $store + ->expects($this->once()) + ->method('delete') + ->with($key); + + $store + ->expects($this->once()) + ->method('exists') + ->with($key) + ->willReturn(true); + + $lock->release(); + } + + /** + * @dataProvider provideExpiredDates + */ + public function testExpiration($ttls, $expected) + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + foreach ($ttls as $ttl) { + if (null === $ttl) { + $key->resetLifetime(); + } else { + $key->reduceLifetime($ttl); + } + } + $this->assertSame($expected, $lock->isExpired()); + } + + public function provideExpiredDates() + { + yield array(array(-0.1), true); + yield array(array(0.1, -0.1), true); + yield array(array(-0.1, 0.1), true); + + yield array(array(), false); + yield array(array(0.1), false); + yield array(array(-0.1, null), false); + } +} diff --git a/vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php b/vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php new file mode 100644 index 00000000..4b9c81bd --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Store\RedisStore; + +/** + * @author Jérémy Derussé + */ +abstract class AbstractRedisStoreTest extends AbstractStoreTest +{ + use ExpiringStoreTestTrait; + + /** + * {@inheritdoc} + */ + protected function getClockDelay() + { + return 250000; + } + + /** + * Return a RedisConnection. + * + * @return \Redis|\RedisArray|\RedisCluster|\Predis\Client + */ + abstract protected function getRedisConnection(); + + /** + * {@inheritdoc} + */ + public function getStore() + { + return new RedisStore($this->getRedisConnection()); + } +} diff --git a/vendor/symfony/lock/Tests/Store/AbstractStoreTest.php b/vendor/symfony/lock/Tests/Store/AbstractStoreTest.php new file mode 100644 index 00000000..2ab030b2 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/AbstractStoreTest.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +abstract class AbstractStoreTest extends TestCase +{ + /** + * @return StoreInterface + */ + abstract protected function getStore(); + + public function testSave() + { + $store = $this->getStore(); + + $key = new Key(uniqid(__METHOD__, true)); + + $this->assertFalse($store->exists($key)); + $store->save($key); + $this->assertTrue($store->exists($key)); + $store->delete($key); + $this->assertFalse($store->exists($key)); + } + + public function testSaveWithDifferentResources() + { + $store = $this->getStore(); + + $key1 = new Key(uniqid(__METHOD__, true)); + $key2 = new Key(uniqid(__METHOD__, true)); + + $store->save($key1); + $this->assertTrue($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + + $store->save($key2); + $this->assertTrue($store->exists($key1)); + $this->assertTrue($store->exists($key2)); + + $store->delete($key1); + $this->assertFalse($store->exists($key1)); + $this->assertTrue($store->exists($key2)); + + $store->delete($key2); + $this->assertFalse($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + } + + public function testSaveWithDifferentKeysOnSameResources() + { + $store = $this->getStore(); + + $resource = uniqid(__METHOD__, true); + $key1 = new Key($resource); + $key2 = new Key($resource); + + $store->save($key1); + $this->assertTrue($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + + try { + $store->save($key2); + $this->fail('The store shouldn\'t save the second key'); + } catch (LockConflictedException $e) { + } + + // The failure of previous attempt should not impact the state of current locks + $this->assertTrue($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + + $store->delete($key1); + $this->assertFalse($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + + $store->save($key2); + $this->assertFalse($store->exists($key1)); + $this->assertTrue($store->exists($key2)); + + $store->delete($key2); + $this->assertFalse($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + } + + public function testSaveTwice() + { + $store = $this->getStore(); + + $resource = uniqid(__METHOD__, true); + $key = new Key($resource); + + $store->save($key); + $store->save($key); + // just asserts it don't throw an exception + $this->addToAssertionCount(1); + + $store->delete($key); + } +} diff --git a/vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php b/vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php new file mode 100644 index 00000000..93e5a547 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +trait BlockingStoreTestTrait +{ + /** + * @see AbstractStoreTest::getStore() + */ + abstract protected function getStore(); + + /** + * Tests blocking locks thanks to pcntl. + * + * This test is time sensible: the $clockDelay could be adjust. + * + * @requires extension pcntl + * @requires function pcntl_sigwaitinfo + */ + public function testBlockingLocks() + { + // Amount a microsecond used to order async actions + $clockDelay = 50000; + + if (\PHP_VERSION_ID < 50600 || defined('HHVM_VERSION_ID')) { + $this->markTestSkipped('The PHP engine does not keep resource in child forks'); + + return; + } + + /** @var StoreInterface $store */ + $store = $this->getStore(); + $key = new Key(uniqid(__METHOD__, true)); + $parentPID = posix_getpid(); + + // Block SIGHUP signal + pcntl_sigprocmask(SIG_BLOCK, array(SIGHUP)); + + if ($childPID = pcntl_fork()) { + // Wait the start of the child + pcntl_sigwaitinfo(array(SIGHUP), $info); + + try { + // This call should failed given the lock should already by acquired by the child + $store->save($key); + $this->fail('The store saves a locked key.'); + } catch (LockConflictedException $e) { + } + + // send the ready signal to the child + posix_kill($childPID, SIGHUP); + + // This call should be blocked by the child #1 + $store->waitAndSave($key); + $this->assertTrue($store->exists($key)); + $store->delete($key); + + // Now, assert the child process worked well + pcntl_waitpid($childPID, $status1); + $this->assertSame(0, pcntl_wexitstatus($status1), 'The child process couldn\'t lock the resource'); + } else { + // Block SIGHUP signal + pcntl_sigprocmask(SIG_BLOCK, array(SIGHUP)); + try { + $store->save($key); + // send the ready signal to the parent + posix_kill($parentPID, SIGHUP); + + // Wait for the parent to be ready + pcntl_sigwaitinfo(array(SIGHUP), $info); + + // Wait ClockDelay to let parent assert to finish + usleep($clockDelay); + $store->delete($key); + exit(0); + } catch (\Exception $e) { + exit(1); + } + } + } +} diff --git a/vendor/symfony/lock/Tests/Store/CombinedStoreTest.php b/vendor/symfony/lock/Tests/Store/CombinedStoreTest.php new file mode 100644 index 00000000..c7232d40 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/CombinedStoreTest.php @@ -0,0 +1,356 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\Strategy\UnanimousStrategy; +use Symfony\Component\Lock\Strategy\StrategyInterface; +use Symfony\Component\Lock\Store\CombinedStore; +use Symfony\Component\Lock\Store\RedisStore; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +class CombinedStoreTest extends AbstractStoreTest +{ + use ExpiringStoreTestTrait; + + /** + * {@inheritdoc} + */ + protected function getClockDelay() + { + return 250000; + } + + /** + * {@inheritdoc} + */ + public function getStore() + { + $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); + try { + $redis->connect(); + } catch (\Exception $e) { + self::markTestSkipped($e->getMessage()); + } + + return new CombinedStore(array(new RedisStore($redis)), new UnanimousStrategy()); + } + + /** @var \PHPUnit_Framework_MockObject_MockObject */ + private $strategy; + /** @var \PHPUnit_Framework_MockObject_MockObject */ + private $store1; + /** @var \PHPUnit_Framework_MockObject_MockObject */ + private $store2; + /** @var CombinedStore */ + private $store; + + public function setup() + { + $this->strategy = $this->getMockBuilder(StrategyInterface::class)->getMock(); + $this->store1 = $this->getMockBuilder(StoreInterface::class)->getMock(); + $this->store2 = $this->getMockBuilder(StoreInterface::class)->getMock(); + + $this->store = new CombinedStore(array($this->store1, $this->store2), $this->strategy); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\LockConflictedException + */ + public function testSaveThrowsExceptionOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + $this->store->save($key); + } + + public function testSaveCleanupOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + + $this->store1 + ->expects($this->once()) + ->method('delete'); + $this->store2 + ->expects($this->once()) + ->method('delete'); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + try { + $this->store->save($key); + } catch (LockConflictedException $e) { + // Catch the exception given this is not what we want to assert in this tests + } + } + + public function testSaveAbortWhenStrategyCantBeMet() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->never()) + ->method('save'); + + $this->strategy + ->expects($this->once()) + ->method('canBeMet') + ->willReturn(false); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + try { + $this->store->save($key); + } catch (LockConflictedException $e) { + // Catch the exception given this is not what we want to assert in this tests + } + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\LockConflictedException + */ + public function testputOffExpirationThrowsExceptionOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + $ttl = random_int(1, 10); + + $this->store1 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + $this->store->putOffExpiration($key, $ttl); + } + + public function testputOffExpirationCleanupOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + $ttl = random_int(1, 10); + + $this->store1 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + + $this->store1 + ->expects($this->once()) + ->method('delete'); + $this->store2 + ->expects($this->once()) + ->method('delete'); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + try { + $this->store->putOffExpiration($key, $ttl); + } catch (LockConflictedException $e) { + // Catch the exception given this is not what we want to assert in this tests + } + } + + public function testputOffExpirationAbortWhenStrategyCantBeMet() + { + $key = new Key(uniqid(__METHOD__, true)); + $ttl = random_int(1, 10); + + $this->store1 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->never()) + ->method('putOffExpiration'); + + $this->strategy + ->expects($this->once()) + ->method('canBeMet') + ->willReturn(false); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + try { + $this->store->putOffExpiration($key, $ttl); + } catch (LockConflictedException $e) { + // Catch the exception given this is not what we want to assert in this tests + } + } + + public function testPutOffExpirationIgnoreNonExpiringStorage() + { + $store1 = $this->getMockBuilder(StoreInterface::class)->getMock(); + $store2 = $this->getMockBuilder(StoreInterface::class)->getMock(); + + $store = new CombinedStore(array($store1, $store2), $this->strategy); + + $key = new Key(uniqid(__METHOD__, true)); + $ttl = random_int(1, 10); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->once()) + ->method('isMet') + ->with(2, 2) + ->willReturn(true); + + $store->putOffExpiration($key, $ttl); + } + + public function testExistsDontAskToEveryBody() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->any()) + ->method('exists') + ->with($key) + ->willReturn(false); + $this->store2 + ->expects($this->never()) + ->method('exists'); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->once()) + ->method('isMet') + ->willReturn(true); + + $this->assertTrue($this->store->exists($key)); + } + + public function testExistsAbortWhenStrategyCantBeMet() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->any()) + ->method('exists') + ->with($key) + ->willReturn(false); + $this->store2 + ->expects($this->never()) + ->method('exists'); + + $this->strategy + ->expects($this->once()) + ->method('canBeMet') + ->willReturn(false); + $this->strategy + ->expects($this->once()) + ->method('isMet') + ->willReturn(false); + + $this->assertFalse($this->store->exists($key)); + } + + public function testDeleteDontStopOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->once()) + ->method('delete') + ->with($key) + ->willThrowException(new \Exception()); + $this->store2 + ->expects($this->once()) + ->method('delete') + ->with($key); + + $this->store->delete($key); + } +} diff --git a/vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php b/vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php new file mode 100644 index 00000000..10b13273 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +trait ExpiringStoreTestTrait +{ + /** + * Amount a microsecond used to order async actions. + * + * @return int + */ + abstract protected function getClockDelay(); + + /** + * @see AbstractStoreTest::getStore() + */ + abstract protected function getStore(); + + /** + * Tests the store automatically delete the key when it expire. + * + * This test is time sensible: the $clockDelay could be adjust. + */ + public function testExpiration() + { + $key = new Key(uniqid(__METHOD__, true)); + $clockDelay = $this->getClockDelay(); + + /** @var StoreInterface $store */ + $store = $this->getStore(); + + $store->save($key); + $store->putOffExpiration($key, $clockDelay / 1000000); + $this->assertTrue($store->exists($key)); + + usleep(2 * $clockDelay); + $this->assertFalse($store->exists($key)); + } + + /** + * Tests the store thrown exception when TTL expires. + * + * @expectedException \Symfony\Component\Lock\Exception\LockExpiredException + */ + public function testAbortAfterExpiration() + { + $key = new Key(uniqid(__METHOD__, true)); + + /** @var StoreInterface $store */ + $store = $this->getStore(); + + $store->save($key); + $store->putOffExpiration($key, 1 / 1000000); + } + + /** + * Tests the refresh can push the limits to the expiration. + * + * This test is time sensible: the $clockDelay could be adjust. + */ + public function testRefreshLock() + { + // Amount a microsecond used to order async actions + $clockDelay = $this->getClockDelay(); + + // Amount a microsecond used to order async actions + $key = new Key(uniqid(__METHOD__, true)); + + /** @var StoreInterface $store */ + $store = $this->getStore(); + + $store->save($key); + $store->putOffExpiration($key, $clockDelay / 1000000); + $this->assertTrue($store->exists($key)); + + usleep(2 * $clockDelay); + $this->assertFalse($store->exists($key)); + } + + public function testSetExpiration() + { + $key = new Key(uniqid(__METHOD__, true)); + + /** @var StoreInterface $store */ + $store = $this->getStore(); + + $store->save($key); + $store->putOffExpiration($key, 1); + $this->assertGreaterThanOrEqual(0, $key->getRemainingLifetime()); + $this->assertLessThanOrEqual(1, $key->getRemainingLifetime()); + } +} diff --git a/vendor/symfony/lock/Tests/Store/FlockStoreTest.php b/vendor/symfony/lock/Tests/Store/FlockStoreTest.php new file mode 100644 index 00000000..ef3650c3 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/FlockStoreTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\Store\FlockStore; + +/** + * @author Jérémy Derussé + */ +class FlockStoreTest extends AbstractStoreTest +{ + use BlockingStoreTestTrait; + + /** + * {@inheritdoc} + */ + protected function getStore() + { + return new FlockStore(); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\InvalidArgumentException + * @expectedExceptionMessage The directory "/a/b/c/d/e" is not writable. + */ + public function testConstructWhenRepositoryDoesNotExist() + { + if (!getenv('USER') || 'root' === getenv('USER')) { + $this->markTestSkipped('This test will fail if run under superuser'); + } + + new FlockStore('/a/b/c/d/e'); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\InvalidArgumentException + * @expectedExceptionMessage The directory "/" is not writable. + */ + public function testConstructWhenRepositoryIsNotWriteable() + { + if (!getenv('USER') || 'root' === getenv('USER')) { + $this->markTestSkipped('This test will fail if run under superuser'); + } + + new FlockStore('/'); + } + + public function testSaveSanitizeName() + { + $store = $this->getStore(); + + $key = new Key(''); + + $file = sprintf( + '%s/sf.-php-echo-hello-word-.%s.lock', + sys_get_temp_dir(), + strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_') + ); + // ensure the file does not exist before the store + @unlink($file); + + $store->save($key); + + $this->assertFileExists($file); + + $store->delete($key); + } +} diff --git a/vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php b/vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php new file mode 100644 index 00000000..f4ab571f --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Store\MemcachedStore; + +/** + * @author Jérémy Derussé + * + * @requires extension memcached + */ +class MemcachedStoreTest extends AbstractStoreTest +{ + use ExpiringStoreTestTrait; + + public static function setupBeforeClass() + { + $memcached = new \Memcached(); + $memcached->addServer(getenv('MEMCACHED_HOST'), 11211); + $memcached->get('foo'); + $code = $memcached->getResultCode(); + + if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) { + self::markTestSkipped('Unable to connect to the memcache host'); + } + } + + /** + * {@inheritdoc} + */ + protected function getClockDelay() + { + return 1000000; + } + + /** + * {@inheritdoc} + */ + public function getStore() + { + $memcached = new \Memcached(); + $memcached->addServer(getenv('MEMCACHED_HOST'), 11211); + + return new MemcachedStore($memcached); + } + + public function testAbortAfterExpiration() + { + $this->markTestSkipped('Memcached expects a TTL greater than 1 sec. Simulating a slow network is too hard'); + } +} diff --git a/vendor/symfony/lock/Tests/Store/PredisStoreTest.php b/vendor/symfony/lock/Tests/Store/PredisStoreTest.php new file mode 100644 index 00000000..621affec --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/PredisStoreTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +/** + * @author Jérémy Derussé + */ +class PredisStoreTest extends AbstractRedisStoreTest +{ + public static function setupBeforeClass() + { + $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); + try { + $redis->connect(); + } catch (\Exception $e) { + self::markTestSkipped($e->getMessage()); + } + } + + protected function getRedisConnection() + { + $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); + $redis->connect(); + + return $redis; + } +} diff --git a/vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php b/vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php new file mode 100644 index 00000000..180da461 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +/** + * @author Jérémy Derussé + * + * @requires extension redis + */ +class RedisArrayStoreTest extends AbstractRedisStoreTest +{ + public static function setupBeforeClass() + { + if (!class_exists('RedisArray')) { + self::markTestSkipped('The RedisArray class is required.'); + } + if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) { + $e = error_get_last(); + self::markTestSkipped($e['message']); + } + } + + protected function getRedisConnection() + { + $redis = new \RedisArray(array(getenv('REDIS_HOST'))); + + return $redis; + } +} diff --git a/vendor/symfony/lock/Tests/Store/RedisStoreTest.php b/vendor/symfony/lock/Tests/Store/RedisStoreTest.php new file mode 100644 index 00000000..6c7d2441 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/RedisStoreTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +/** + * @author Jérémy Derussé + * + * @requires extension redis + */ +class RedisStoreTest extends AbstractRedisStoreTest +{ + public static function setupBeforeClass() + { + if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) { + $e = error_get_last(); + self::markTestSkipped($e['message']); + } + } + + protected function getRedisConnection() + { + $redis = new \Redis(); + $redis->connect(getenv('REDIS_HOST')); + + return $redis; + } +} diff --git a/vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php b/vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php new file mode 100644 index 00000000..febd48f2 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Store\RedisStore; +use Symfony\Component\Lock\Store\RetryTillSaveStore; + +/** + * @author Jérémy Derussé + */ +class RetryTillSaveStoreTest extends AbstractStoreTest +{ + use BlockingStoreTestTrait; + + public function getStore() + { + $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); + try { + $redis->connect(); + } catch (\Exception $e) { + self::markTestSkipped($e->getMessage()); + } + + return new RetryTillSaveStore(new RedisStore($redis), 100, 100); + } +} diff --git a/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php b/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php new file mode 100644 index 00000000..bb37ec1f --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Store\SemaphoreStore; + +/** + * @author Jérémy Derussé + * + * @requires extension sysvsem + */ +class SemaphoreStoreTest extends AbstractStoreTest +{ + use BlockingStoreTestTrait; + + /** + * {@inheritdoc} + */ + protected function getStore() + { + if (\PHP_VERSION_ID < 50601) { + $this->markTestSkipped('Non blocking semaphore are supported by PHP version greater or equals than 5.6.1'); + } + + return new SemaphoreStore(); + } +} diff --git a/vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php b/vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php new file mode 100644 index 00000000..87e83a99 --- /dev/null +++ b/vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Strategy; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Lock\Strategy\ConsensusStrategy; + +/** + * @author Jérémy Derussé + */ +class ConsensusStrategyTest extends TestCase +{ + /** @var ConsensusStrategy */ + private $strategy; + + public function setup() + { + $this->strategy = new ConsensusStrategy(); + } + + public function provideMetResults() + { + // success, failure, total, isMet + yield array(3, 0, 3, true); + yield array(2, 1, 3, true); + yield array(2, 0, 3, true); + yield array(1, 2, 3, false); + yield array(1, 1, 3, false); + yield array(1, 0, 3, false); + yield array(0, 3, 3, false); + yield array(0, 2, 3, false); + yield array(0, 1, 3, false); + yield array(0, 0, 3, false); + + yield array(2, 0, 2, true); + yield array(1, 1, 2, false); + yield array(1, 0, 2, false); + yield array(0, 2, 2, false); + yield array(0, 1, 2, false); + yield array(0, 0, 2, false); + } + + public function provideIndeterminate() + { + // success, failure, total, canBeMet + yield array(3, 0, 3, true); + yield array(2, 1, 3, true); + yield array(2, 0, 3, true); + yield array(1, 2, 3, false); + yield array(1, 1, 3, true); + yield array(1, 0, 3, true); + yield array(0, 3, 3, false); + yield array(0, 2, 3, false); + yield array(0, 1, 3, true); + yield array(0, 0, 3, true); + + yield array(2, 0, 2, true); + yield array(1, 1, 2, false); + yield array(1, 0, 2, true); + yield array(0, 2, 2, false); + yield array(0, 1, 2, false); + yield array(0, 0, 2, true); + } + + /** + * @dataProvider provideMetResults + */ + public function testMet($success, $failure, $total, $isMet) + { + $this->assertSame($isMet, $this->strategy->isMet($success, $total)); + } + + /** + * @dataProvider provideIndeterminate + */ + public function testCanBeMet($success, $failure, $total, $isMet) + { + $this->assertSame($isMet, $this->strategy->canBeMet($failure, $total)); + } +} diff --git a/vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php b/vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php new file mode 100644 index 00000000..beff54a6 --- /dev/null +++ b/vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Strategy; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Lock\Strategy\UnanimousStrategy; + +/** + * @author Jérémy Derussé + */ +class UnanimousStrategyTest extends TestCase +{ + /** @var UnanimousStrategy */ + private $strategy; + + public function setup() + { + $this->strategy = new UnanimousStrategy(); + } + + public function provideMetResults() + { + // success, failure, total, isMet + yield array(3, 0, 3, true); + yield array(2, 1, 3, false); + yield array(2, 0, 3, false); + yield array(1, 2, 3, false); + yield array(1, 1, 3, false); + yield array(1, 0, 3, false); + yield array(0, 3, 3, false); + yield array(0, 2, 3, false); + yield array(0, 1, 3, false); + yield array(0, 0, 3, false); + + yield array(2, 0, 2, true); + yield array(1, 1, 2, false); + yield array(1, 0, 2, false); + yield array(0, 2, 2, false); + yield array(0, 1, 2, false); + yield array(0, 0, 2, false); + } + + public function provideIndeterminate() + { + // success, failure, total, canBeMet + yield array(3, 0, 3, true); + yield array(2, 1, 3, false); + yield array(2, 0, 3, true); + yield array(1, 2, 3, false); + yield array(1, 1, 3, false); + yield array(1, 0, 3, true); + yield array(0, 3, 3, false); + yield array(0, 2, 3, false); + yield array(0, 1, 3, false); + yield array(0, 0, 3, true); + + yield array(2, 0, 2, true); + yield array(1, 1, 2, false); + yield array(1, 0, 2, true); + yield array(0, 2, 2, false); + yield array(0, 1, 2, false); + yield array(0, 0, 2, true); + } + + /** + * @dataProvider provideMetResults + */ + public function testMet($success, $failure, $total, $isMet) + { + $this->assertSame($isMet, $this->strategy->isMet($success, $total)); + } + + /** + * @dataProvider provideIndeterminate + */ + public function testCanBeMet($success, $failure, $total, $isMet) + { + $this->assertSame($isMet, $this->strategy->canBeMet($failure, $total)); + } +} diff --git a/vendor/symfony/lock/composer.json b/vendor/symfony/lock/composer.json new file mode 100644 index 00000000..9a6e7687 --- /dev/null +++ b/vendor/symfony/lock/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/lock", + "type": "library", + "description": "Symfony Lock Component", + "keywords": ["locking", "redlock", "mutex", "semaphore", "flock", "cas"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Jérémy Derussé", + "email": "jeremy@derusse.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-php70": "~1.0", + "psr/log": "~1.0" + }, + "require-dev": { + "predis/predis": "~1.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Lock\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + } +} diff --git a/vendor/symfony/lock/phpunit.xml.dist b/vendor/symfony/lock/phpunit.xml.dist new file mode 100644 index 00000000..be3ca215 --- /dev/null +++ b/vendor/symfony/lock/phpunit.xml.dist @@ -0,0 +1,32 @@ + + + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Tests + ./vendor + + + + diff --git a/vendor/symfony/polyfill-php70/LICENSE b/vendor/symfony/polyfill-php70/LICENSE new file mode 100644 index 00000000..24fa32c2 --- /dev/null +++ b/vendor/symfony/polyfill-php70/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2018 Fabien Potencier + +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/vendor/symfony/polyfill-php70/Php70.php b/vendor/symfony/polyfill-php70/Php70.php new file mode 100644 index 00000000..39e66450 --- /dev/null +++ b/vendor/symfony/polyfill-php70/Php70.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php70; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class Php70 +{ + public static function intdiv($dividend, $divisor) + { + $dividend = self::intArg($dividend, __FUNCTION__, 1); + $divisor = self::intArg($divisor, __FUNCTION__, 2); + + if (0 === $divisor) { + throw new \DivisionByZeroError('Division by zero'); + } + if (-1 === $divisor && ~PHP_INT_MAX === $dividend) { + throw new \ArithmeticError('Division of PHP_INT_MIN by -1 is not an integer'); + } + + return ($dividend - ($dividend % $divisor)) / $divisor; + } + + public static function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) + { + $count = 0; + $result = (string) $subject; + if (0 === $limit = self::intArg($limit, __FUNCTION__, 3)) { + return $result; + } + + foreach ($patterns as $pattern => $callback) { + $result = preg_replace_callback($pattern, $callback, $result, $limit, $c); + $count += $c; + } + + return $result; + } + + public static function error_clear_last() + { + static $handler; + if (!$handler) { + $handler = function() { return false; }; + } + set_error_handler($handler); + @trigger_error(''); + restore_error_handler(); + } + + private static function intArg($value, $caller, $pos) + { + if (\is_int($value)) { + return $value; + } + if (!\is_numeric($value) || PHP_INT_MAX <= ($value += 0) || ~PHP_INT_MAX >= $value) { + throw new \TypeError(sprintf('%s() expects parameter %d to be integer, %s given', $caller, $pos, gettype($value))); + } + + return (int) $value; + } +} diff --git a/vendor/symfony/polyfill-php70/README.md b/vendor/symfony/polyfill-php70/README.md new file mode 100644 index 00000000..04988c6f --- /dev/null +++ b/vendor/symfony/polyfill-php70/README.md @@ -0,0 +1,28 @@ +Symfony Polyfill / Php70 +======================== + +This component provides features unavailable in releases prior to PHP 7.0: + +- [`intdiv`](http://php.net/intdiv) +- [`preg_replace_callback_array`](http://php.net/preg_replace_callback_array) +- [`error_clear_last`](http://php.net/error_clear_last) +- `random_bytes` and `random_int` (from [paragonie/random_compat](https://github.com/paragonie/random_compat)) +- [`*Error` throwable classes](http://php.net/Error) +- [`PHP_INT_MIN`](http://php.net/manual/en/reserved.constants.php#constant.php-int-min) +- `SessionUpdateTimestampHandlerInterface` + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +Compatibility notes +=================== + +To write portable code between PHP5 and PHP7, some care must be taken: +- `\*Error` exceptions must be caught before `\Exception`; +- after calling `error_clear_last()`, the result of `$e = error_get_last()` must be + verified using `isset($e['message'][0])` instead of `null !== $e`. + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php b/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php new file mode 100644 index 00000000..68191244 --- /dev/null +++ b/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php @@ -0,0 +1,5 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php70 as p; + +if (PHP_VERSION_ID < 70000) { + if (!defined('PHP_INT_MIN')) { + define('PHP_INT_MIN', ~PHP_INT_MAX); + } + if (!function_exists('intdiv')) { + function intdiv($dividend, $divisor) { return p\Php70::intdiv($dividend, $divisor); } + } + if (!function_exists('preg_replace_callback_array')) { + function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) { return p\Php70::preg_replace_callback_array($patterns, $subject, $limit, $count); } + } + if (!function_exists('error_clear_last')) { + function error_clear_last() { return p\Php70::error_clear_last(); } + } +} diff --git a/vendor/symfony/polyfill-php70/composer.json b/vendor/symfony/polyfill-php70/composer.json new file mode 100644 index 00000000..871045d2 --- /dev/null +++ b/vendor/symfony/polyfill-php70/composer.json @@ -0,0 +1,33 @@ +{ + "name": "symfony/polyfill-php70", + "type": "library", + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3", + "paragonie/random_compat": "~1.0|~2.0" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php70\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + } +}