Dep: update

주로 PHAN
This commit is contained in:
2021-08-06 22:39:09 +09:00
parent 5310c2e7f6
commit b306601c72
1098 changed files with 92137 additions and 33228 deletions
+3 -3
View File
@@ -37,8 +37,8 @@ namespace Composer\Autoload;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
@@ -60,7 +60,7 @@ class ClassLoader
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
+684
View File
@@ -0,0 +1,684 @@
<?php
namespace Composer;
use Composer\Semver\VersionParser;
class InstalledVersions
{
private static $installed = array (
'root' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '5310c2e7f6f872cbb923ed71b72ef01b8df4aaaf',
'name' => 'sammo-hid/sammo',
),
'versions' =>
array (
'brandonwamboldt/utilphp' =>
array (
'pretty_version' => '1.1.0',
'version' => '1.1.0.0',
'aliases' =>
array (
),
'reference' => '36c32efc4f0679c05163464a550f45c8d83fe683',
),
'catfan/medoo' =>
array (
'pretty_version' => 'v1.7.10',
'version' => '1.7.10.0',
'aliases' =>
array (
),
'reference' => '2d675f73e23f63bbaeb9a8aa33318659a3d3c32f',
),
'composer/semver' =>
array (
'pretty_version' => '3.2.5',
'version' => '3.2.5.0',
'aliases' =>
array (
),
'reference' => '31f3ea725711245195f62e54ffa402d8ef2fdba9',
),
'composer/xdebug-handler' =>
array (
'pretty_version' => '2.0.2',
'version' => '2.0.2.0',
'aliases' =>
array (
),
'reference' => '84674dd3a7575ba617f5a76d7e9e29a7d3891339',
),
'erusev/parsedown' =>
array (
'pretty_version' => '1.7.4',
'version' => '1.7.4.0',
'aliases' =>
array (
),
'reference' => 'cb17b6477dfff935958ba01325f2e8a2bfa6dab3',
),
'erusev/parsedown-extra' =>
array (
'pretty_version' => '0.8.1',
'version' => '0.8.1.0',
'aliases' =>
array (
),
'reference' => '91ac3ff98f0cea243bdccc688df43810f044dcef',
),
'ezyang/htmlpurifier' =>
array (
'pretty_version' => 'v4.13.0',
'version' => '4.13.0.0',
'aliases' =>
array (
),
'reference' => '08e27c97e4c6ed02f37c5b2b20488046c8d90d75',
),
'felixfbecker/advanced-json-rpc' =>
array (
'pretty_version' => 'v3.2.1',
'version' => '3.2.1.0',
'aliases' =>
array (
),
'reference' => 'b5f37dbff9a8ad360ca341f3240dc1c168b45447',
),
'firephp/firephp-core' =>
array (
'pretty_version' => 'v0.4.0',
'version' => '0.4.0.0',
'aliases' =>
array (
),
'reference' => 'fabad0f2503f9577fe8dd2cb1d1c7cd73ed2aacf',
),
'guzzlehttp/guzzle' =>
array (
'pretty_version' => '6.5.5',
'version' => '6.5.5.0',
'aliases' =>
array (
),
'reference' => '9d4290de1cfd701f38099ef7e183b64b4b7b0c5e',
),
'guzzlehttp/promises' =>
array (
'pretty_version' => '1.4.1',
'version' => '1.4.1.0',
'aliases' =>
array (
),
'reference' => '8e7d04f1f6450fef59366c399cfad4b9383aa30d',
),
'guzzlehttp/psr7' =>
array (
'pretty_version' => '1.8.2',
'version' => '1.8.2.0',
'aliases' =>
array (
),
'reference' => 'dc960a912984efb74d0a90222870c72c87f10c91',
),
'league/plates' =>
array (
'pretty_version' => 'v3.4.0',
'version' => '3.4.0.0',
'aliases' =>
array (
),
'reference' => '6d3ee31199b536a4e003b34a356ca20f6f75496a',
),
'microsoft/tolerant-php-parser' =>
array (
'pretty_version' => 'v0.1.1',
'version' => '0.1.1.0',
'aliases' =>
array (
),
'reference' => '6a965617cf484355048ac6d2d3de7b6ec93abb16',
),
'monolog/monolog' =>
array (
'pretty_version' => '1.26.1',
'version' => '1.26.1.0',
'aliases' =>
array (
),
'reference' => 'c6b00f05152ae2c9b04a448f99c7590beb6042f5',
),
'netresearch/jsonmapper' =>
array (
'pretty_version' => 'v4.0.0',
'version' => '4.0.0.0',
'aliases' =>
array (
),
'reference' => '8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d',
),
'nette/caching' =>
array (
'pretty_version' => 'v3.1.1',
'version' => '3.1.1.0',
'aliases' =>
array (
),
'reference' => '3e771c589dee414724be473c24ad16dae50c1960',
),
'nette/finder' =>
array (
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'aliases' =>
array (
),
'reference' => '4ad2c298eb8c687dd0e74ae84206a4186eeaed50',
),
'nette/utils' =>
array (
'pretty_version' => 'v3.2.2',
'version' => '3.2.2.0',
'aliases' =>
array (
),
'reference' => '967cfc4f9a1acd5f1058d76715a424c53343c20c',
),
'pguardiario/phpuri' =>
array (
'pretty_version' => '1.0',
'version' => '1.0.0.0',
'aliases' =>
array (
),
'reference' => 'ad0a5ec033fe616cfef55578b9c7f2458be8fbfc',
),
'phan/phan' =>
array (
'pretty_version' => '5.0.0',
'version' => '5.0.0.0',
'aliases' =>
array (
),
'reference' => 'f36b6b9a2f4143a25f35ce94d712ceb0527e9d90',
),
'php-extended/php-system' =>
array (
'pretty_version' => '1.4.0',
'version' => '1.4.0.0',
'aliases' =>
array (
),
'reference' => '9e6b3c2009ef56dc123efc43900e40cdf217ace0',
),
'php-extended/php-tail' =>
array (
'pretty_version' => '2.2.0',
'version' => '2.2.0.0',
'aliases' =>
array (
),
'reference' => '19fbd3a79ccc071954f28296b2c44754335304a0',
),
'phpdocumentor/reflection-common' =>
array (
'pretty_version' => '2.2.0',
'version' => '2.2.0.0',
'aliases' =>
array (
),
'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b',
),
'phpdocumentor/reflection-docblock' =>
array (
'pretty_version' => '5.2.2',
'version' => '5.2.2.0',
'aliases' =>
array (
),
'reference' => '069a785b2141f5bcf49f3e353548dc1cce6df556',
),
'phpdocumentor/type-resolver' =>
array (
'pretty_version' => '1.4.0',
'version' => '1.4.0.0',
'aliases' =>
array (
),
'reference' => '6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0',
),
'psr/container' =>
array (
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'aliases' =>
array (
),
'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf',
),
'psr/http-message' =>
array (
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'aliases' =>
array (
),
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
),
'psr/http-message-implementation' =>
array (
'provided' =>
array (
0 => '1.0',
),
),
'psr/log' =>
array (
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'aliases' =>
array (
),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
),
'psr/log-implementation' =>
array (
'provided' =>
array (
0 => '1.0.0',
1 => '1.0|2.0',
),
),
'ralouphie/getallheaders' =>
array (
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'aliases' =>
array (
),
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
),
'sabre/event' =>
array (
'pretty_version' => '5.1.2',
'version' => '5.1.2.0',
'aliases' =>
array (
),
'reference' => 'c120bec57c17b6251a496efc82b732418b49d50a',
),
'sammo-hid/sammo' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '5310c2e7f6f872cbb923ed71b72ef01b8df4aaaf',
),
'scssphp/scssphp' =>
array (
'pretty_version' => 'v1.6.0',
'version' => '1.6.0.0',
'aliases' =>
array (
),
'reference' => 'b83594e2323c5d6e80785df3f91b9d1d32aad530',
),
'sergeytsalkov/meekrodb' =>
array (
'pretty_version' => 'v2.4',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => 'e30c240d54bc81f58c58507a9ed768032eb494a5',
),
'symfony/console' =>
array (
'pretty_version' => 'v5.3.6',
'version' => '5.3.6.0',
'aliases' =>
array (
),
'reference' => '51b71afd6d2dc8f5063199357b9880cea8d8bfe2',
),
'symfony/deprecation-contracts' =>
array (
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => '5f38c8804a9e97d23e0c8d63341088cd8a22d627',
),
'symfony/lock' =>
array (
'pretty_version' => 'v4.4.27',
'version' => '4.4.27.0',
'aliases' =>
array (
),
'reference' => '6ca476d4ac992802f2a4043929f68f1818449486',
),
'symfony/polyfill-ctype' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce',
),
'symfony/polyfill-intl-grapheme' =>
array (
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'aliases' =>
array (
),
'reference' => '16880ba9c5ebe3642d1995ab866db29270b36535',
),
'symfony/polyfill-intl-idn' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '65bd267525e82759e7d8c4e8ceea44f398838e65',
),
'symfony/polyfill-intl-normalizer' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8',
),
'symfony/polyfill-mbstring' =>
array (
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'aliases' =>
array (
),
'reference' => '9174a3d80210dca8daa7f31fec659150bbeabfc6',
),
'symfony/polyfill-php72' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '9a142215a36a3888e30d0a9eeea9766764e96976',
),
'symfony/polyfill-php73' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => 'fba8933c384d6476ab14fb7b8526e5287ca7e010',
),
'symfony/polyfill-php80' =>
array (
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'aliases' =>
array (
),
'reference' => '1100343ed1a92e3a38f9ae122fc0eb21602547be',
),
'symfony/service-contracts' =>
array (
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => 'f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb',
),
'symfony/string' =>
array (
'pretty_version' => 'v5.3.3',
'version' => '5.3.3.0',
'aliases' =>
array (
),
'reference' => 'bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1',
),
'tysonandre/var_representation_polyfill' =>
array (
'pretty_version' => '0.0.2',
'version' => '0.0.2.0',
'aliases' =>
array (
),
'reference' => '3f17999ee1f257319ddc6721dd26ebbc5d175f33',
),
'vlucas/valitron' =>
array (
'pretty_version' => 'v1.4.10',
'version' => '1.4.10.0',
'aliases' =>
array (
),
'reference' => '5ebd5d7af82cc0a9d798e816a2ecad63f1b59ceb',
),
'webmozart/assert' =>
array (
'pretty_version' => '1.10.0',
'version' => '1.10.0.0',
'aliases' =>
array (
),
'reference' => '6964c76c7804814a842473e0c8fd15bab0f18e25',
),
'xemlock/htmlpurifier-html5' =>
array (
'pretty_version' => 'v0.1.11',
'version' => '0.1.11.0',
'aliases' =>
array (
),
'reference' => 'f0d563f9fd4a82a3d759043483f9a94c0d8c2255',
),
),
);
public static function getInstalledPackages()
{
return array_keys(self::$installed['versions']);
}
public static function isInstalled($packageName)
{
return isset(self::$installed['versions'][$packageName]);
}
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
public static function getVersionRanges($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
$ranges = array();
if (isset(self::$installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = self::$installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
public static function getVersion($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
if (!isset(self::$installed['versions'][$packageName]['version'])) {
return null;
}
return self::$installed['versions'][$packageName]['version'];
}
public static function getPrettyVersion($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return self::$installed['versions'][$packageName]['pretty_version'];
}
public static function getReference($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
if (!isset(self::$installed['versions'][$packageName]['reference'])) {
return null;
}
return self::$installed['versions'][$packageName]['reference'];
}
public static function getRootPackage()
{
return self::$installed['root'];
}
public static function getRawData()
{
return self::$installed;
}
public static function reload($data)
{
self::$installed = $data;
}
}
+32 -20
View File
@@ -6,8 +6,9 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'DB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'DBHelper' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'DBTransaction' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'FB' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/fb.php',
'FirePHP' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php',
@@ -47,37 +48,43 @@ return array(
'MeekroDB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBEval' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBException' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'Nette\\ArgumentOutOfRangeException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'MeekroDBWalk' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'Nette\\ArgumentOutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\Bridges\\CacheDI\\CacheExtension' => $vendorDir . '/nette/caching/src/Bridges/CacheDI/CacheExtension.php',
'Nette\\Bridges\\CacheLatte\\CacheMacro' => $vendorDir . '/nette/caching/src/Bridges/CacheLatte/CacheMacro.php',
'Nette\\Caching\\BulkReader' => $vendorDir . '/nette/caching/src/Caching/BulkReader.php',
'Nette\\Caching\\Cache' => $vendorDir . '/nette/caching/src/Caching/Cache.php',
'Nette\\Caching\\IBulkReader' => $vendorDir . '/nette/caching/src/Caching/IBulkReader.php',
'Nette\\Caching\\IStorage' => $vendorDir . '/nette/caching/src/Caching/IStorage.php',
'Nette\\Caching\\IBulkReader' => $vendorDir . '/nette/caching/src/compatibility.php',
'Nette\\Caching\\IStorage' => $vendorDir . '/nette/caching/src/compatibility.php',
'Nette\\Caching\\OutputHelper' => $vendorDir . '/nette/caching/src/Caching/OutputHelper.php',
'Nette\\Caching\\Storage' => $vendorDir . '/nette/caching/src/Caching/Storage.php',
'Nette\\Caching\\Storages\\DevNullStorage' => $vendorDir . '/nette/caching/src/Caching/Storages/DevNullStorage.php',
'Nette\\Caching\\Storages\\FileStorage' => $vendorDir . '/nette/caching/src/Caching/Storages/FileStorage.php',
'Nette\\Caching\\Storages\\IJournal' => $vendorDir . '/nette/caching/src/Caching/Storages/IJournal.php',
'Nette\\Caching\\Storages\\IJournal' => $vendorDir . '/nette/caching/src/compatibility.php',
'Nette\\Caching\\Storages\\Journal' => $vendorDir . '/nette/caching/src/Caching/Storages/Journal.php',
'Nette\\Caching\\Storages\\MemcachedStorage' => $vendorDir . '/nette/caching/src/Caching/Storages/MemcachedStorage.php',
'Nette\\Caching\\Storages\\MemoryStorage' => $vendorDir . '/nette/caching/src/Caching/Storages/MemoryStorage.php',
'Nette\\Caching\\Storages\\NewMemcachedStorage' => $vendorDir . '/nette/caching/src/Caching/Storages/NewMemcachedStorage.php',
'Nette\\Caching\\Storages\\SQLiteJournal' => $vendorDir . '/nette/caching/src/Caching/Storages/SQLiteJournal.php',
'Nette\\Caching\\Storages\\SQLiteStorage' => $vendorDir . '/nette/caching/src/Caching/Storages/SQLiteStorage.php',
'Nette\\DeprecatedException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\DirectoryNotFoundException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\FileNotFoundException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\IOException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\InvalidArgumentException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\InvalidStateException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\DeprecatedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\DirectoryNotFoundException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\FileNotFoundException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\HtmlStringable' => $vendorDir . '/nette/utils/src/HtmlStringable.php',
'Nette\\IOException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\InvalidArgumentException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\InvalidStateException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\Iterators\\CachingIterator' => $vendorDir . '/nette/utils/src/Iterators/CachingIterator.php',
'Nette\\Iterators\\Mapper' => $vendorDir . '/nette/utils/src/Iterators/Mapper.php',
'Nette\\Localization\\ITranslator' => $vendorDir . '/nette/utils/src/Utils/ITranslator.php',
'Nette\\MemberAccessException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\SmartObject' => $vendorDir . '/nette/utils/src/Utils/SmartObject.php',
'Nette\\StaticClass' => $vendorDir . '/nette/utils/src/Utils/StaticClass.php',
'Nette\\UnexpectedValueException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\Localization\\ITranslator' => $vendorDir . '/nette/utils/src/compatibility.php',
'Nette\\Localization\\Translator' => $vendorDir . '/nette/utils/src/Translator.php',
'Nette\\MemberAccessException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\SmartObject' => $vendorDir . '/nette/utils/src/SmartObject.php',
'Nette\\StaticClass' => $vendorDir . '/nette/utils/src/StaticClass.php',
'Nette\\UnexpectedValueException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\Utils\\ArrayHash' => $vendorDir . '/nette/utils/src/Utils/ArrayHash.php',
'Nette\\Utils\\ArrayList' => $vendorDir . '/nette/utils/src/Utils/ArrayList.php',
'Nette\\Utils\\Arrays' => $vendorDir . '/nette/utils/src/Utils/Arrays.php',
@@ -86,9 +93,10 @@ return array(
'Nette\\Utils\\DateTime' => $vendorDir . '/nette/utils/src/Utils/DateTime.php',
'Nette\\Utils\\FileSystem' => $vendorDir . '/nette/utils/src/Utils/FileSystem.php',
'Nette\\Utils\\Finder' => $vendorDir . '/nette/finder/src/Utils/Finder.php',
'Nette\\Utils\\Floats' => $vendorDir . '/nette/utils/src/Utils/Floats.php',
'Nette\\Utils\\Helpers' => $vendorDir . '/nette/utils/src/Utils/Helpers.php',
'Nette\\Utils\\Html' => $vendorDir . '/nette/utils/src/Utils/Html.php',
'Nette\\Utils\\IHtmlString' => $vendorDir . '/nette/utils/src/Utils/IHtmlString.php',
'Nette\\Utils\\IHtmlString' => $vendorDir . '/nette/utils/src/compatibility.php',
'Nette\\Utils\\Image' => $vendorDir . '/nette/utils/src/Utils/Image.php',
'Nette\\Utils\\ImageException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\Utils\\Json' => $vendorDir . '/nette/utils/src/Utils/Json.php',
@@ -102,6 +110,10 @@ return array(
'Nette\\Utils\\Strings' => $vendorDir . '/nette/utils/src/Utils/Strings.php',
'Nette\\Utils\\UnknownImageFileException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php',
'Nette\\Utils\\Validators' => $vendorDir . '/nette/utils/src/Utils/Validators.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'WhereClause' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php',
'kakao\\KakaoKey' => $baseDir . '/d_setting/KakaoKey.php',
'sammo\\RootDB' => $baseDir . '/d_setting/RootDB.php',
+12 -5
View File
@@ -6,17 +6,24 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
'2b9d0f43f9552984cfa82fee95491826' => $vendorDir . '/sabre/event/lib/coroutine.php',
'd81bab31d3feb45bfe2f283ea3c8fdf7' => $vendorDir . '/sabre/event/lib/Loop/functions.php',
'a1cce3d26cc15c00fcd0b3354bd72c88' => $vendorDir . '/sabre/event/lib/Promise/functions.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'6714be961f4a45ae8b9a99d5d55c5d07' => $vendorDir . '/tysonandre/var_representation_polyfill/src/var_representation.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'5b154887902198b16314243c6e0e3e19' => $vendorDir . '/pguardiario/phpuri/phpuri.php',
'870dc64919afa8b0f700701bb2c6a783' => $baseDir . '/f_config/config.php',
+6
View File
@@ -10,12 +10,18 @@ return array(
'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'),
'kakao\\' => array($baseDir . '/src/kakao'),
'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
'VarRepresentation\\' => array($vendorDir . '/tysonandre/var_representation_polyfill/src/VarRepresentation'),
'Valitron\\' => array($vendorDir . '/vlucas/valitron/src/Valitron'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
'Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'),
'Symfony\\Component\\Lock\\' => array($vendorDir . '/symfony/lock'),
'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
'ScssPhp\\ScssPhp\\' => array($vendorDir . '/scssphp/scssphp/src'),
+6 -1
View File
@@ -13,19 +13,24 @@ class ComposerAutoloaderInit67b09c83b85c3bc0027caefe5bba171a
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit67b09c83b85c3bc0027caefe5bba171a', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit67b09c83b85c3bc0027caefe5bba171a', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a::getInitializer($loader));
} else {
+74 -25
View File
@@ -7,17 +7,24 @@ namespace Composer\Autoload;
class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
'2b9d0f43f9552984cfa82fee95491826' => __DIR__ . '/..' . '/sabre/event/lib/coroutine.php',
'd81bab31d3feb45bfe2f283ea3c8fdf7' => __DIR__ . '/..' . '/sabre/event/lib/Loop/functions.php',
'a1cce3d26cc15c00fcd0b3354bd72c88' => __DIR__ . '/..' . '/sabre/event/lib/Promise/functions.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'6714be961f4a45ae8b9a99d5d55c5d07' => __DIR__ . '/..' . '/tysonandre/var_representation_polyfill/src/var_representation.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'5b154887902198b16314243c6e0e3e19' => __DIR__ . '/..' . '/pguardiario/phpuri/phpuri.php',
'870dc64919afa8b0f700701bb2c6a783' => __DIR__ . '/../..' . '/f_config/config.php',
@@ -42,15 +49,21 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
),
'V' =>
array (
'VarRepresentation\\' => 18,
'Valitron\\' => 9,
),
'S' =>
array (
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Php73\\' => 23,
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
'Symfony\\Polyfill\\Intl\\Grapheme\\' => 31,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Contracts\\Service\\' => 26,
'Symfony\\Component\\String\\' => 25,
'Symfony\\Component\\Lock\\' => 23,
'Symfony\\Component\\Console\\' => 26,
'ScssPhp\\ScssPhp\\' => 16,
@@ -111,10 +124,18 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
array (
0 => __DIR__ . '/..' . '/webmozart/assert/src',
),
'VarRepresentation\\' =>
array (
0 => __DIR__ . '/..' . '/tysonandre/var_representation_polyfill/src/VarRepresentation',
),
'Valitron\\' =>
array (
0 => __DIR__ . '/..' . '/vlucas/valitron/src/Valitron',
),
'Symfony\\Polyfill\\Php80\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Polyfill\\Php73\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php73',
@@ -127,6 +148,18 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Intl\\Normalizer\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
),
'Symfony\\Polyfill\\Intl\\Idn\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
),
'Symfony\\Polyfill\\Intl\\Grapheme\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme',
),
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
@@ -135,6 +168,10 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
array (
0 => __DIR__ . '/..' . '/symfony/service-contracts',
),
'Symfony\\Component\\String\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/string',
),
'Symfony\\Component\\Lock\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/lock',
@@ -253,8 +290,9 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
);
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'DB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'DBHelper' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'DBTransaction' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'FB' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/fb.php',
'FirePHP' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php',
@@ -294,37 +332,43 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
'MeekroDB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBEval' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'MeekroDBException' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'Nette\\ArgumentOutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'MeekroDBWalk' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'Nette\\ArgumentOutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\Bridges\\CacheDI\\CacheExtension' => __DIR__ . '/..' . '/nette/caching/src/Bridges/CacheDI/CacheExtension.php',
'Nette\\Bridges\\CacheLatte\\CacheMacro' => __DIR__ . '/..' . '/nette/caching/src/Bridges/CacheLatte/CacheMacro.php',
'Nette\\Caching\\BulkReader' => __DIR__ . '/..' . '/nette/caching/src/Caching/BulkReader.php',
'Nette\\Caching\\Cache' => __DIR__ . '/..' . '/nette/caching/src/Caching/Cache.php',
'Nette\\Caching\\IBulkReader' => __DIR__ . '/..' . '/nette/caching/src/Caching/IBulkReader.php',
'Nette\\Caching\\IStorage' => __DIR__ . '/..' . '/nette/caching/src/Caching/IStorage.php',
'Nette\\Caching\\IBulkReader' => __DIR__ . '/..' . '/nette/caching/src/compatibility.php',
'Nette\\Caching\\IStorage' => __DIR__ . '/..' . '/nette/caching/src/compatibility.php',
'Nette\\Caching\\OutputHelper' => __DIR__ . '/..' . '/nette/caching/src/Caching/OutputHelper.php',
'Nette\\Caching\\Storage' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storage.php',
'Nette\\Caching\\Storages\\DevNullStorage' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/DevNullStorage.php',
'Nette\\Caching\\Storages\\FileStorage' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/FileStorage.php',
'Nette\\Caching\\Storages\\IJournal' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/IJournal.php',
'Nette\\Caching\\Storages\\IJournal' => __DIR__ . '/..' . '/nette/caching/src/compatibility.php',
'Nette\\Caching\\Storages\\Journal' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/Journal.php',
'Nette\\Caching\\Storages\\MemcachedStorage' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/MemcachedStorage.php',
'Nette\\Caching\\Storages\\MemoryStorage' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/MemoryStorage.php',
'Nette\\Caching\\Storages\\NewMemcachedStorage' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/NewMemcachedStorage.php',
'Nette\\Caching\\Storages\\SQLiteJournal' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/SQLiteJournal.php',
'Nette\\Caching\\Storages\\SQLiteStorage' => __DIR__ . '/..' . '/nette/caching/src/Caching/Storages/SQLiteStorage.php',
'Nette\\DeprecatedException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\DirectoryNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\FileNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\IOException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\InvalidArgumentException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\InvalidStateException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\DeprecatedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\DirectoryNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\FileNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\HtmlStringable' => __DIR__ . '/..' . '/nette/utils/src/HtmlStringable.php',
'Nette\\IOException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\InvalidArgumentException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\InvalidStateException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\Iterators\\CachingIterator' => __DIR__ . '/..' . '/nette/utils/src/Iterators/CachingIterator.php',
'Nette\\Iterators\\Mapper' => __DIR__ . '/..' . '/nette/utils/src/Iterators/Mapper.php',
'Nette\\Localization\\ITranslator' => __DIR__ . '/..' . '/nette/utils/src/Utils/ITranslator.php',
'Nette\\MemberAccessException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\SmartObject' => __DIR__ . '/..' . '/nette/utils/src/Utils/SmartObject.php',
'Nette\\StaticClass' => __DIR__ . '/..' . '/nette/utils/src/Utils/StaticClass.php',
'Nette\\UnexpectedValueException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\Localization\\ITranslator' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php',
'Nette\\Localization\\Translator' => __DIR__ . '/..' . '/nette/utils/src/Translator.php',
'Nette\\MemberAccessException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\SmartObject' => __DIR__ . '/..' . '/nette/utils/src/SmartObject.php',
'Nette\\StaticClass' => __DIR__ . '/..' . '/nette/utils/src/StaticClass.php',
'Nette\\UnexpectedValueException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\Utils\\ArrayHash' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayHash.php',
'Nette\\Utils\\ArrayList' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayList.php',
'Nette\\Utils\\Arrays' => __DIR__ . '/..' . '/nette/utils/src/Utils/Arrays.php',
@@ -333,9 +377,10 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
'Nette\\Utils\\DateTime' => __DIR__ . '/..' . '/nette/utils/src/Utils/DateTime.php',
'Nette\\Utils\\FileSystem' => __DIR__ . '/..' . '/nette/utils/src/Utils/FileSystem.php',
'Nette\\Utils\\Finder' => __DIR__ . '/..' . '/nette/finder/src/Utils/Finder.php',
'Nette\\Utils\\Floats' => __DIR__ . '/..' . '/nette/utils/src/Utils/Floats.php',
'Nette\\Utils\\Helpers' => __DIR__ . '/..' . '/nette/utils/src/Utils/Helpers.php',
'Nette\\Utils\\Html' => __DIR__ . '/..' . '/nette/utils/src/Utils/Html.php',
'Nette\\Utils\\IHtmlString' => __DIR__ . '/..' . '/nette/utils/src/Utils/IHtmlString.php',
'Nette\\Utils\\IHtmlString' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php',
'Nette\\Utils\\Image' => __DIR__ . '/..' . '/nette/utils/src/Utils/Image.php',
'Nette\\Utils\\ImageException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\Utils\\Json' => __DIR__ . '/..' . '/nette/utils/src/Utils/Json.php',
@@ -349,6 +394,10 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a
'Nette\\Utils\\Strings' => __DIR__ . '/..' . '/nette/utils/src/Utils/Strings.php',
'Nette\\Utils\\UnknownImageFileException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php',
'Nette\\Utils\\Validators' => __DIR__ . '/..' . '/nette/utils/src/Utils/Validators.php',
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'WhereClause' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php',
'kakao\\KakaoKey' => __DIR__ . '/../..' . '/d_setting/KakaoKey.php',
'sammo\\RootDB' => __DIR__ . '/../..' . '/d_setting/RootDB.php',
+3257 -2348
View File
File diff suppressed because it is too large Load Diff
+489
View File
@@ -0,0 +1,489 @@
<?php return array (
'root' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '5310c2e7f6f872cbb923ed71b72ef01b8df4aaaf',
'name' => 'sammo-hid/sammo',
),
'versions' =>
array (
'brandonwamboldt/utilphp' =>
array (
'pretty_version' => '1.1.0',
'version' => '1.1.0.0',
'aliases' =>
array (
),
'reference' => '36c32efc4f0679c05163464a550f45c8d83fe683',
),
'catfan/medoo' =>
array (
'pretty_version' => 'v1.7.10',
'version' => '1.7.10.0',
'aliases' =>
array (
),
'reference' => '2d675f73e23f63bbaeb9a8aa33318659a3d3c32f',
),
'composer/semver' =>
array (
'pretty_version' => '3.2.5',
'version' => '3.2.5.0',
'aliases' =>
array (
),
'reference' => '31f3ea725711245195f62e54ffa402d8ef2fdba9',
),
'composer/xdebug-handler' =>
array (
'pretty_version' => '2.0.2',
'version' => '2.0.2.0',
'aliases' =>
array (
),
'reference' => '84674dd3a7575ba617f5a76d7e9e29a7d3891339',
),
'erusev/parsedown' =>
array (
'pretty_version' => '1.7.4',
'version' => '1.7.4.0',
'aliases' =>
array (
),
'reference' => 'cb17b6477dfff935958ba01325f2e8a2bfa6dab3',
),
'erusev/parsedown-extra' =>
array (
'pretty_version' => '0.8.1',
'version' => '0.8.1.0',
'aliases' =>
array (
),
'reference' => '91ac3ff98f0cea243bdccc688df43810f044dcef',
),
'ezyang/htmlpurifier' =>
array (
'pretty_version' => 'v4.13.0',
'version' => '4.13.0.0',
'aliases' =>
array (
),
'reference' => '08e27c97e4c6ed02f37c5b2b20488046c8d90d75',
),
'felixfbecker/advanced-json-rpc' =>
array (
'pretty_version' => 'v3.2.1',
'version' => '3.2.1.0',
'aliases' =>
array (
),
'reference' => 'b5f37dbff9a8ad360ca341f3240dc1c168b45447',
),
'firephp/firephp-core' =>
array (
'pretty_version' => 'v0.4.0',
'version' => '0.4.0.0',
'aliases' =>
array (
),
'reference' => 'fabad0f2503f9577fe8dd2cb1d1c7cd73ed2aacf',
),
'guzzlehttp/guzzle' =>
array (
'pretty_version' => '6.5.5',
'version' => '6.5.5.0',
'aliases' =>
array (
),
'reference' => '9d4290de1cfd701f38099ef7e183b64b4b7b0c5e',
),
'guzzlehttp/promises' =>
array (
'pretty_version' => '1.4.1',
'version' => '1.4.1.0',
'aliases' =>
array (
),
'reference' => '8e7d04f1f6450fef59366c399cfad4b9383aa30d',
),
'guzzlehttp/psr7' =>
array (
'pretty_version' => '1.8.2',
'version' => '1.8.2.0',
'aliases' =>
array (
),
'reference' => 'dc960a912984efb74d0a90222870c72c87f10c91',
),
'league/plates' =>
array (
'pretty_version' => 'v3.4.0',
'version' => '3.4.0.0',
'aliases' =>
array (
),
'reference' => '6d3ee31199b536a4e003b34a356ca20f6f75496a',
),
'microsoft/tolerant-php-parser' =>
array (
'pretty_version' => 'v0.1.1',
'version' => '0.1.1.0',
'aliases' =>
array (
),
'reference' => '6a965617cf484355048ac6d2d3de7b6ec93abb16',
),
'monolog/monolog' =>
array (
'pretty_version' => '1.26.1',
'version' => '1.26.1.0',
'aliases' =>
array (
),
'reference' => 'c6b00f05152ae2c9b04a448f99c7590beb6042f5',
),
'netresearch/jsonmapper' =>
array (
'pretty_version' => 'v4.0.0',
'version' => '4.0.0.0',
'aliases' =>
array (
),
'reference' => '8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d',
),
'nette/caching' =>
array (
'pretty_version' => 'v3.1.1',
'version' => '3.1.1.0',
'aliases' =>
array (
),
'reference' => '3e771c589dee414724be473c24ad16dae50c1960',
),
'nette/finder' =>
array (
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'aliases' =>
array (
),
'reference' => '4ad2c298eb8c687dd0e74ae84206a4186eeaed50',
),
'nette/utils' =>
array (
'pretty_version' => 'v3.2.2',
'version' => '3.2.2.0',
'aliases' =>
array (
),
'reference' => '967cfc4f9a1acd5f1058d76715a424c53343c20c',
),
'pguardiario/phpuri' =>
array (
'pretty_version' => '1.0',
'version' => '1.0.0.0',
'aliases' =>
array (
),
'reference' => 'ad0a5ec033fe616cfef55578b9c7f2458be8fbfc',
),
'phan/phan' =>
array (
'pretty_version' => '5.0.0',
'version' => '5.0.0.0',
'aliases' =>
array (
),
'reference' => 'f36b6b9a2f4143a25f35ce94d712ceb0527e9d90',
),
'php-extended/php-system' =>
array (
'pretty_version' => '1.4.0',
'version' => '1.4.0.0',
'aliases' =>
array (
),
'reference' => '9e6b3c2009ef56dc123efc43900e40cdf217ace0',
),
'php-extended/php-tail' =>
array (
'pretty_version' => '2.2.0',
'version' => '2.2.0.0',
'aliases' =>
array (
),
'reference' => '19fbd3a79ccc071954f28296b2c44754335304a0',
),
'phpdocumentor/reflection-common' =>
array (
'pretty_version' => '2.2.0',
'version' => '2.2.0.0',
'aliases' =>
array (
),
'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b',
),
'phpdocumentor/reflection-docblock' =>
array (
'pretty_version' => '5.2.2',
'version' => '5.2.2.0',
'aliases' =>
array (
),
'reference' => '069a785b2141f5bcf49f3e353548dc1cce6df556',
),
'phpdocumentor/type-resolver' =>
array (
'pretty_version' => '1.4.0',
'version' => '1.4.0.0',
'aliases' =>
array (
),
'reference' => '6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0',
),
'psr/container' =>
array (
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'aliases' =>
array (
),
'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf',
),
'psr/http-message' =>
array (
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'aliases' =>
array (
),
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
),
'psr/http-message-implementation' =>
array (
'provided' =>
array (
0 => '1.0',
),
),
'psr/log' =>
array (
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'aliases' =>
array (
),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
),
'psr/log-implementation' =>
array (
'provided' =>
array (
0 => '1.0.0',
1 => '1.0|2.0',
),
),
'ralouphie/getallheaders' =>
array (
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'aliases' =>
array (
),
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
),
'sabre/event' =>
array (
'pretty_version' => '5.1.2',
'version' => '5.1.2.0',
'aliases' =>
array (
),
'reference' => 'c120bec57c17b6251a496efc82b732418b49d50a',
),
'sammo-hid/sammo' =>
array (
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'aliases' =>
array (
),
'reference' => '5310c2e7f6f872cbb923ed71b72ef01b8df4aaaf',
),
'scssphp/scssphp' =>
array (
'pretty_version' => 'v1.6.0',
'version' => '1.6.0.0',
'aliases' =>
array (
),
'reference' => 'b83594e2323c5d6e80785df3f91b9d1d32aad530',
),
'sergeytsalkov/meekrodb' =>
array (
'pretty_version' => 'v2.4',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => 'e30c240d54bc81f58c58507a9ed768032eb494a5',
),
'symfony/console' =>
array (
'pretty_version' => 'v5.3.6',
'version' => '5.3.6.0',
'aliases' =>
array (
),
'reference' => '51b71afd6d2dc8f5063199357b9880cea8d8bfe2',
),
'symfony/deprecation-contracts' =>
array (
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => '5f38c8804a9e97d23e0c8d63341088cd8a22d627',
),
'symfony/lock' =>
array (
'pretty_version' => 'v4.4.27',
'version' => '4.4.27.0',
'aliases' =>
array (
),
'reference' => '6ca476d4ac992802f2a4043929f68f1818449486',
),
'symfony/polyfill-ctype' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce',
),
'symfony/polyfill-intl-grapheme' =>
array (
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'aliases' =>
array (
),
'reference' => '16880ba9c5ebe3642d1995ab866db29270b36535',
),
'symfony/polyfill-intl-idn' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '65bd267525e82759e7d8c4e8ceea44f398838e65',
),
'symfony/polyfill-intl-normalizer' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8',
),
'symfony/polyfill-mbstring' =>
array (
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'aliases' =>
array (
),
'reference' => '9174a3d80210dca8daa7f31fec659150bbeabfc6',
),
'symfony/polyfill-php72' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => '9a142215a36a3888e30d0a9eeea9766764e96976',
),
'symfony/polyfill-php73' =>
array (
'pretty_version' => 'v1.23.0',
'version' => '1.23.0.0',
'aliases' =>
array (
),
'reference' => 'fba8933c384d6476ab14fb7b8526e5287ca7e010',
),
'symfony/polyfill-php80' =>
array (
'pretty_version' => 'v1.23.1',
'version' => '1.23.1.0',
'aliases' =>
array (
),
'reference' => '1100343ed1a92e3a38f9ae122fc0eb21602547be',
),
'symfony/service-contracts' =>
array (
'pretty_version' => 'v2.4.0',
'version' => '2.4.0.0',
'aliases' =>
array (
),
'reference' => 'f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb',
),
'symfony/string' =>
array (
'pretty_version' => 'v5.3.3',
'version' => '5.3.3.0',
'aliases' =>
array (
),
'reference' => 'bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1',
),
'tysonandre/var_representation_polyfill' =>
array (
'pretty_version' => '0.0.2',
'version' => '0.0.2.0',
'aliases' =>
array (
),
'reference' => '3f17999ee1f257319ddc6721dd26ebbc5d175f33',
),
'vlucas/valitron' =>
array (
'pretty_version' => 'v1.4.10',
'version' => '1.4.10.0',
'aliases' =>
array (
),
'reference' => '5ebd5d7af82cc0a9d798e816a2ecad63f1b59ceb',
),
'webmozart/assert' =>
array (
'pretty_version' => '1.10.0',
'version' => '1.10.0.0',
'aliases' =>
array (
),
'reference' => '6964c76c7804814a842473e0c8fd15bab0f18e25',
),
'xemlock/htmlpurifier-html5' =>
array (
'pretty_version' => 'v0.1.11',
'version' => '0.1.11.0',
'aliases' =>
array (
),
'reference' => 'f0d563f9fd4a82a3d759043483f9a94c0d8c2255',
),
),
);
+26
View File
@@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 70205)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}
+94
View File
@@ -3,6 +3,85 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
### [3.2.5] 2021-05-24
* Fixed: issue comparing disjunctive MultiConstraints to conjunctive ones (#127)
* Fixed: added complete type information using phpstan annotations
### [3.2.4] 2020-11-13
* Fixed: code clean-up
### [3.2.3] 2020-11-12
* Fixed: constraints in the form of `X || Y, >=Y.1` and other such complex constructs were in some cases being optimized into a more restrictive constraint
### [3.2.2] 2020-10-14
* Fixed: internal code cleanups
### [3.2.1] 2020-09-27
* Fixed: accidental validation of broken constraints combining ^/~ and wildcards, and -dev suffix allowing weird cases
* Fixed: normalization of beta0 and such which was dropping the 0
### [3.2.0] 2020-09-09
* Added: support for `x || @dev`, not very useful but seen in the wild and failed to validate with 1.5.2/1.6.0
* Added: support for `foobar-dev` being equal to `dev-foobar`, dev-foobar is the official way to write it but we need to support the other for BC and convenience
### [3.1.0] 2020-09-08
* Added: support for constraints like `^2.x-dev` and `~2.x-dev`, not very useful but seen in the wild and failed to validate with 3.0.1
* Fixed: invalid aliases will no longer throw, unless explicitly validated by Composer in the root package
### [3.0.1] 2020-09-08
* Fixed: handling of some invalid -dev versions which were seen as valid
### [3.0.0] 2020-05-26
* Break: Renamed `EmptyConstraint`, replace it with `MatchAllConstraint`
* Break: Unlikely to affect anyone but strictly speaking a breaking change, `*.*` and such variants will not match all `dev-*` versions anymore, only `*` does
* Break: ConstraintInterface is now considered internal/private and not meant to be implemented by third parties anymore
* Added `Intervals` class to check if a constraint is a subsets of another one, and allow compacting complex MultiConstraints into simpler ones
* Added `CompilingMatcher` class to speed up constraint matching against simple Constraint instances
* Added `MatchAllConstraint` and `MatchNoneConstraint` which match everything and nothing
* Added more advanced optimization of contiguous constraints inside MultiConstraint
* Added tentative support for PHP 8
* Fixed ConstraintInterface::matches to be commutative in all cases
### [2.0.0] 2020-04-21
* Break: `dev-master`, `dev-trunk` and `dev-default` now normalize to `dev-master`, `dev-trunk` and `dev-default` instead of `9999999-dev` in 1.x
* Break: Removed the deprecated `AbstractConstraint`
* Added `getUpperBound` and `getLowerBound` to ConstraintInterface. They return `Composer\Semver\Constraint\Bound` instances
* Added `MultiConstraint::create` to create the most-optimal form of ConstraintInterface from an array of constraint strings
### [1.7.2] 2020-12-03
* Fixed: Allow installing on php 8
### [1.7.1] 2020-09-27
* Fixed: accidental validation of broken constraints combining ^/~ and wildcards, and -dev suffix allowing weird cases
* Fixed: normalization of beta0 and such which was dropping the 0
### [1.7.0] 2020-09-09
* Added: support for `x || @dev`, not very useful but seen in the wild and failed to validate with 1.5.2/1.6.0
* Added: support for `foobar-dev` being equal to `dev-foobar`, dev-foobar is the official way to write it but we need to support the other for BC and convenience
### [1.6.0] 2020-09-08
* Added: support for constraints like `^2.x-dev` and `~2.x-dev`, not very useful but seen in the wild and failed to validate with 1.5.2
* Fixed: invalid aliases will no longer throw, unless explicitly validated by Composer in the root package
### [1.5.2] 2020-09-08
* Fixed: handling of some invalid -dev versions which were seen as valid
* Fixed: some doctypes
### [1.5.1] 2020-01-13
* Fixed: Parsing of aliased version was not validating the alias to be a valid version
@@ -66,6 +145,21 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint`
* Changed: code style using php-cs-fixer.
[3.2.5]: https://github.com/composer/semver/compare/3.2.4...3.2.5
[3.2.4]: https://github.com/composer/semver/compare/3.2.3...3.2.4
[3.2.3]: https://github.com/composer/semver/compare/3.2.2...3.2.3
[3.2.2]: https://github.com/composer/semver/compare/3.2.1...3.2.2
[3.2.1]: https://github.com/composer/semver/compare/3.2.0...3.2.1
[3.2.0]: https://github.com/composer/semver/compare/3.1.0...3.2.0
[3.1.0]: https://github.com/composer/semver/compare/3.0.1...3.1.0
[3.0.1]: https://github.com/composer/semver/compare/3.0.0...3.0.1
[3.0.0]: https://github.com/composer/semver/compare/2.0.0...3.0.0
[2.0.0]: https://github.com/composer/semver/compare/1.5.1...2.0.0
[1.7.2]: https://github.com/composer/semver/compare/1.7.1...1.7.2
[1.7.1]: https://github.com/composer/semver/compare/1.7.0...1.7.1
[1.7.0]: https://github.com/composer/semver/compare/1.6.0...1.7.0
[1.6.0]: https://github.com/composer/semver/compare/1.5.2...1.6.0
[1.5.2]: https://github.com/composer/semver/compare/1.5.1...1.5.2
[1.5.1]: https://github.com/composer/semver/compare/1.5.0...1.5.1
[1.5.0]: https://github.com/composer/semver/compare/1.4.2...1.5.0
[1.4.2]: https://github.com/composer/semver/compare/1.4.1...1.4.2
+32 -4
View File
@@ -6,7 +6,7 @@ Semver library that offers utilities, version constraint parsing and validation.
Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.
[![Build Status](https://travis-ci.org/composer/semver.svg?branch=master)](https://travis-ci.org/composer/semver)
[![Continuous Integration](https://github.com/composer/semver/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/composer/semver/actions)
Installation
@@ -37,7 +37,7 @@ Basic usage
### Comparator
The `Composer\Semver\Comparator` class provides the following methods for comparing versions:
The [`Composer\Semver\Comparator`](https://github.com/composer/semver/blob/main/src/Comparator.php) class provides the following methods for comparing versions:
* greaterThan($v1, $v2)
* greaterThanOrEqualTo($v1, $v2)
@@ -46,7 +46,7 @@ The `Composer\Semver\Comparator` class provides the following methods for compar
* equalTo($v1, $v2)
* notEqualTo($v1, $v2)
Each function takes two version strings as arguments. For example:
Each function takes two version strings as arguments and returns a boolean. For example:
```php
use Composer\Semver\Comparator;
@@ -56,13 +56,41 @@ Comparator::greaterThan('1.25.0', '1.24.0'); // 1.25.0 > 1.24.0
### Semver
The `Composer\Semver\Semver` class provides the following methods:
The [`Composer\Semver\Semver`](https://github.com/composer/semver/blob/main/src/Semver.php) class provides the following methods:
* satisfies($version, $constraints)
* satisfiedBy(array $versions, $constraint)
* sort($versions)
* rsort($versions)
### Intervals
The [`Composer\Semver\Intervals`](https://github.com/composer/semver/blob/main/src/Intervals.php) static class provides
a few utilities to work with complex constraints or read version intervals from a constraint:
```php
use Composer\Semver\Intervals;
// Checks whether $candidate is a subset of $constraint
Intervals::isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint);
// Checks whether $a and $b have any intersection, equivalent to $a->matches($b)
Intervals::haveIntersections(ConstraintInterface $a, ConstraintInterface $b);
// Optimizes a complex multi constraint by merging all intervals down to the smallest
// possible multi constraint. The drawbacks are this is not very fast, and the resulting
// multi constraint will have no human readable prettyConstraint configured on it
Intervals::compactConstraint(ConstraintInterface $constraint);
// Creates an array of numeric intervals and branch constraints representing a given constraint
Intervals::get(ConstraintInterface $constraint);
// Clears the memoization cache when you are done processing constraints
Intervals::clear()
```
See the class docblocks for more details.
License
-------
+6 -4
View File
@@ -31,10 +31,11 @@
"issues": "https://github.com/composer/semver/issues"
},
"require": {
"php": "^5.3.2 || ^7.0"
"php": "^5.3.2 || ^7.0 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5"
"symfony/phpunit-bridge": "^4.2 || ^5",
"phpstan/phpstan": "^0.12.54"
},
"autoload": {
"psr-4": {
@@ -48,10 +49,11 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
"dev-main": "3.x-dev"
}
},
"scripts": {
"test": "phpunit"
"test": "SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 vendor/bin/simple-phpunit",
"phpstan": "phpstan analyse"
}
}
+3 -1
View File
@@ -101,11 +101,13 @@ class Comparator
* @param string $version2
*
* @return bool
*
* @phpstan-param Constraint::STR_OP_* $operator
*/
public static function compare($version1, $operator, $version2)
{
$constraint = new Constraint($operator, $version2);
return $constraint->matches(new Constraint('==', $version1));
return $constraint->matchSpecific(new Constraint('==', $version1), true);
}
}
+71
View File
@@ -0,0 +1,71 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\Constraint;
use Composer\Semver\Constraint\ConstraintInterface;
/**
* Helper class to evaluate constraint by compiling and reusing the code to evaluate
*/
class CompilingMatcher
{
/**
* @var array
* @phpstan-var array<string, callable>
*/
private static $compiledCheckerCache = array();
/** @var bool */
private static $enabled;
/**
* @phpstan-var array<Constraint::OP_*, Constraint::STR_OP_*>
*/
private static $transOpInt = array(
Constraint::OP_EQ => Constraint::STR_OP_EQ,
Constraint::OP_LT => Constraint::STR_OP_LT,
Constraint::OP_LE => Constraint::STR_OP_LE,
Constraint::OP_GT => Constraint::STR_OP_GT,
Constraint::OP_GE => Constraint::STR_OP_GE,
Constraint::OP_NE => Constraint::STR_OP_NE,
);
/**
* Evaluates the expression: $constraint match $operator $version
*
* @param ConstraintInterface $constraint
* @param int $operator
* @phpstan-param Constraint::OP_* $operator
* @param string $version
*
* @return mixed
*/
public static function match(ConstraintInterface $constraint, $operator, $version)
{
if (self::$enabled === null) {
self::$enabled = !\in_array('eval', explode(',', (string) ini_get('disable_functions')), true);
}
if (!self::$enabled) {
return $constraint->matches(new Constraint(self::$transOpInt[$operator], $version));
}
$cacheKey = $operator.$constraint;
if (!isset(self::$compiledCheckerCache[$cacheKey])) {
$code = $constraint->compile($operator);
self::$compiledCheckerCache[$cacheKey] = $function = eval('return function($v, $b){return '.$code.';};');
} else {
$function = self::$compiledCheckerCache[$cacheKey];
}
return $function($version, strpos($version, 'dev-') === 0);
}
}
@@ -1,63 +0,0 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
trigger_error('The ' . __NAMESPACE__ . '\AbstractConstraint abstract class is deprecated, there is no replacement for it, it will be removed in the next major version.', E_USER_DEPRECATED);
/**
* Base constraint class.
*/
abstract class AbstractConstraint implements ConstraintInterface
{
/** @var string */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if ($provider instanceof $this) {
// see note at bottom of this class declaration
return $this->matchSpecific($provider);
}
// turn matching around to find a match
return $provider->matches($this);
}
/**
* @param string $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return $this->__toString();
}
// implementations must implement a method of this format:
// not declared abstract here because type hinting violates parameter coherence (TODO right word?)
// public function matchSpecific(<SpecificConstraintType> $provider);
}
+122
View File
@@ -0,0 +1,122 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
class Bound
{
/**
* @var string
*/
private $version;
/**
* @var bool
*/
private $isInclusive;
/**
* @param string $version
* @param bool $isInclusive
*/
public function __construct($version, $isInclusive)
{
$this->version = $version;
$this->isInclusive = $isInclusive;
}
/**
* @return string
*/
public function getVersion()
{
return $this->version;
}
/**
* @return bool
*/
public function isInclusive()
{
return $this->isInclusive;
}
/**
* @return bool
*/
public function isZero()
{
return $this->getVersion() === '0.0.0.0-dev' && $this->isInclusive();
}
/**
* @return bool
*/
public function isPositiveInfinity()
{
return $this->getVersion() === PHP_INT_MAX.'.0.0.0' && !$this->isInclusive();
}
/**
* Compares a bound to another with a given operator.
*
* @param Bound $other
* @param string $operator
*
* @return bool
*/
public function compareTo(Bound $other, $operator)
{
if (!\in_array($operator, array('<', '>'), true)) {
throw new \InvalidArgumentException('Does not support any other operator other than > or <.');
}
// If they are the same it doesn't matter
if ($this == $other) {
return false;
}
$compareResult = version_compare($this->getVersion(), $other->getVersion());
// Not the same version means we don't need to check if the bounds are inclusive or not
if (0 !== $compareResult) {
return (('>' === $operator) ? 1 : -1) === $compareResult;
}
// Question we're answering here is "am I higher than $other?"
return '>' === $operator ? $other->isInclusive() : !$other->isInclusive();
}
public function __toString()
{
return sprintf(
'%s [%s]',
$this->getVersion(),
$this->isInclusive() ? 'inclusive' : 'exclusive'
);
}
/**
* @return self
*/
public static function zero()
{
return new Bound('0.0.0.0-dev', true);
}
/**
* @return self
*/
public static function positiveInfinity()
{
return new Bound(PHP_INT_MAX.'.0.0.0', false);
}
}
+277 -57
View File
@@ -24,10 +24,21 @@ class Constraint implements ConstraintInterface
const OP_GE = 4;
const OP_NE = 5;
/* operator string values */
const STR_OP_EQ = '==';
const STR_OP_EQ_ALT = '=';
const STR_OP_LT = '<';
const STR_OP_LE = '<=';
const STR_OP_GT = '>';
const STR_OP_GE = '>=';
const STR_OP_NE = '!=';
const STR_OP_NE_ALT = '<>';
/**
* Operator to integer translation table.
*
* @var array
* @phpstan-var array<self::STR_OP_*, self::OP_*>
*/
private static $transOpStr = array(
'=' => self::OP_EQ,
@@ -44,6 +55,7 @@ class Constraint implements ConstraintInterface
* Integer to operator translation table.
*
* @var array
* @phpstan-var array<self::OP_*, self::STR_OP_*>
*/
private static $transOpInt = array(
self::OP_EQ => '==',
@@ -54,59 +66,23 @@ class Constraint implements ConstraintInterface
self::OP_NE => '!=',
);
/** @var string */
/**
* @var int
* @phpstan-var self::OP_*
*/
protected $operator;
/** @var string */
protected $version;
/** @var string */
/** @var string|null */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if ($provider instanceof $this) {
return $this->matchSpecific($provider);
}
/** @var Bound */
protected $lowerBound;
// turn matching around to find a match
return $provider->matches($this);
}
/**
* @param string $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return $this->__toString();
}
/**
* Get all supported comparison operators.
*
* @return array
*/
public static function getSupportedOperators()
{
return array_keys(self::$transOpStr);
}
/** @var Bound */
protected $upperBound;
/**
* Sets operator and version to compare with.
@@ -115,6 +91,8 @@ class Constraint implements ConstraintInterface
* @param string $version
*
* @throws \InvalidArgumentException if invalid operator is given.
*
* @phpstan-param self::STR_OP_* $operator
*/
public function __construct($operator, $version)
{
@@ -130,15 +108,94 @@ class Constraint implements ConstraintInterface
$this->version = $version;
}
/**
* @return string
*/
public function getVersion()
{
return $this->version;
}
/**
* @return string
*
* @phpstan-return self::STR_OP_*
*/
public function getOperator()
{
return self::$transOpInt[$this->operator];
}
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if ($provider instanceof self) {
return $this->matchSpecific($provider);
}
// turn matching around to find a match
return $provider->matches($this);
}
/**
* {@inheritDoc}
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* {@inheritDoc}
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return $this->__toString();
}
/**
* Get all supported comparison operators.
*
* @return array
*
* @phpstan-return list<self::STR_OP_*>
*/
public static function getSupportedOperators()
{
return array_keys(self::$transOpStr);
}
/**
* @param string $operator
* @return int
*
* @phpstan-param self::STR_OP_* $operator
* @phpstan-return self::OP_*
*/
public static function getOperatorConstant($operator)
{
return self::$transOpStr[$operator];
}
/**
* @param string $a
* @param string $b
* @param string $operator
* @param bool $compareBranches
* @param bool $compareBranches
*
* @throws \InvalidArgumentException if invalid operator is given.
*
* @return bool
*
* @phpstan-param self::STR_OP_* $operator
*/
public function versionCompare($a, $b, $operator, $compareBranches = false)
{
@@ -150,8 +207,12 @@ class Constraint implements ConstraintInterface
));
}
$aIsBranch = 'dev-' === substr($a, 0, 4);
$bIsBranch = 'dev-' === substr($b, 0, 4);
$aIsBranch = strpos($a, 'dev-') === 0;
$bIsBranch = strpos($b, 'dev-') === 0;
if ($operator === '!=' && ($aIsBranch || $bIsBranch)) {
return $a !== $b;
}
if ($aIsBranch && $bIsBranch) {
return $operator === '==' && $a === $b;
@@ -162,12 +223,91 @@ class Constraint implements ConstraintInterface
return false;
}
return version_compare($a, $b, $operator);
return \version_compare($a, $b, $operator);
}
/**
* {@inheritDoc}
*/
public function compile($otherOperator)
{
if (strpos($this->version, 'dev-') === 0) {
if (self::OP_EQ === $this->operator) {
if (self::OP_EQ === $otherOperator) {
return sprintf('$b && $v === %s', \var_export($this->version, true));
}
if (self::OP_NE === $otherOperator) {
return sprintf('!$b || $v !== %s', \var_export($this->version, true));
}
return 'false';
}
if (self::OP_NE === $this->operator) {
if (self::OP_EQ === $otherOperator) {
return sprintf('!$b || $v !== %s', \var_export($this->version, true));
}
if (self::OP_NE === $otherOperator) {
return 'true';
}
return '!$b';
}
return 'false';
}
if (self::OP_EQ === $this->operator) {
if (self::OP_EQ === $otherOperator) {
return sprintf('\version_compare($v, %s, \'==\')', \var_export($this->version, true));
}
if (self::OP_NE === $otherOperator) {
return sprintf('$b || \version_compare($v, %s, \'!=\')', \var_export($this->version, true));
}
return sprintf('!$b && \version_compare(%s, $v, \'%s\')', \var_export($this->version, true), self::$transOpInt[$otherOperator]);
}
if (self::OP_NE === $this->operator) {
if (self::OP_EQ === $otherOperator) {
return sprintf('$b || (!$b && \version_compare($v, %s, \'!=\'))', \var_export($this->version, true));
}
if (self::OP_NE === $otherOperator) {
return 'true';
}
return '!$b';
}
if (self::OP_LT === $this->operator || self::OP_LE === $this->operator) {
if (self::OP_LT === $otherOperator || self::OP_LE === $otherOperator) {
return '!$b';
}
} else { // $this->operator must be self::OP_GT || self::OP_GE here
if (self::OP_GT === $otherOperator || self::OP_GE === $otherOperator) {
return '!$b';
}
}
if (self::OP_NE === $otherOperator) {
return 'true';
}
$codeComparison = sprintf('\version_compare($v, %s, \'%s\')', \var_export($this->version, true), self::$transOpInt[$this->operator]);
if ($this->operator === self::OP_LE) {
if ($otherOperator === self::OP_GT) {
return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, true)) . $codeComparison;
}
} elseif ($this->operator === self::OP_GE) {
if ($otherOperator === self::OP_LT) {
return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, true)) . $codeComparison;
}
}
return sprintf('!$b && %s', $codeComparison);
}
/**
* @param Constraint $provider
* @param bool $compareBranches
* @param bool $compareBranches
*
* @return bool
*/
@@ -184,22 +324,37 @@ class Constraint implements ConstraintInterface
// '!=' operator is match when other operator is not '==' operator or version is not match
// these kinds of comparisons always have a solution
if ($isNonEqualOp || $isProviderNonEqualOp) {
return (!$isEqualOp && !$isProviderEqualOp)
|| $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
if ($isNonEqualOp && !$isProviderNonEqualOp && !$isProviderEqualOp && strpos($provider->version, 'dev-') === 0) {
return false;
}
if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && strpos($this->version, 'dev-') === 0) {
return false;
}
if (!$isEqualOp && !$isProviderEqualOp) {
return true;
}
return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
}
// an example for the condition is <= 2.0 & < 1.0
// these kinds of comparisons always have a solution
if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
return true;
return !(strpos($this->version, 'dev-') === 0 || strpos($provider->version, 'dev-') === 0);
}
if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
$version1 = $isEqualOp ? $this->version : $provider->version;
$version2 = $isEqualOp ? $provider->version : $this->version;
$operator = $isEqualOp ? $provider->operator : $this->operator;
if ($this->versionCompare($version1, $version2, self::$transOpInt[$operator], $compareBranches)) {
// special case, e.g. require >= 1.0 and provide < 1.0
// 1.0 >= 1.0 but 1.0 is outside of the provided interval
return !($provider->version === $this->version
&& self::$transOpInt[$provider->operator] === $providerNoEqualOp
&& self::$transOpInt[$this->operator] !== $noEqualOp);
return !(self::$transOpInt[$provider->operator] === $providerNoEqualOp
&& self::$transOpInt[$this->operator] !== $noEqualOp
&& \version_compare($provider->version, $this->version, '=='));
}
return false;
@@ -212,4 +367,69 @@ class Constraint implements ConstraintInterface
{
return self::$transOpInt[$this->operator] . ' ' . $this->version;
}
/**
* {@inheritDoc}
*/
public function getLowerBound()
{
$this->extractBounds();
return $this->lowerBound;
}
/**
* {@inheritDoc}
*/
public function getUpperBound()
{
$this->extractBounds();
return $this->upperBound;
}
/**
* @return void
*/
private function extractBounds()
{
if (null !== $this->lowerBound) {
return;
}
// Branches
if (strpos($this->version, 'dev-') === 0) {
$this->lowerBound = Bound::zero();
$this->upperBound = Bound::positiveInfinity();
return;
}
switch ($this->operator) {
case self::OP_EQ:
$this->lowerBound = new Bound($this->version, true);
$this->upperBound = new Bound($this->version, true);
break;
case self::OP_LT:
$this->lowerBound = Bound::zero();
$this->upperBound = new Bound($this->version, false);
break;
case self::OP_LE:
$this->lowerBound = Bound::zero();
$this->upperBound = new Bound($this->version, true);
break;
case self::OP_GT:
$this->lowerBound = new Bound($this->version, false);
$this->upperBound = Bound::positiveInfinity();
break;
case self::OP_GE:
$this->lowerBound = new Bound($this->version, true);
$this->upperBound = Bound::positiveInfinity();
break;
case self::OP_NE:
$this->lowerBound = Bound::zero();
$this->upperBound = Bound::positiveInfinity();
break;
}
}
}
@@ -11,20 +11,63 @@
namespace Composer\Semver\Constraint;
/**
* DO NOT IMPLEMENT this interface. It is only meant for usage as a type hint
* in libraries relying on composer/semver but creating your own constraint class
* that implements this interface is not a supported use case and will cause the
* composer/semver components to return unexpected results.
*/
interface ConstraintInterface
{
/**
* Checks whether the given constraint intersects in any way with this constraint
*
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider);
/**
* Provides a compiled version of the constraint for the given operator
* The compiled version must be a PHP expression.
* Executor of compile version must provide 2 variables:
* - $v = the string version to compare with
* - $b = whether or not the version is a non-comparable branch (starts with "dev-")
*
* @see Constraint::OP_* for the list of available operators.
* @example return '!$b && version_compare($v, '1.0', '>')';
*
* @param int $otherOperator one Constraint::OP_*
*
* @return string
*
* @phpstan-param Constraint::OP_* $otherOperator
*/
public function compile($otherOperator);
/**
* @return Bound
*/
public function getUpperBound();
/**
* @return Bound
*/
public function getLowerBound();
/**
* @return string
*/
public function getPrettyString();
/**
* @param string|null $prettyString
*
* @return void
*/
public function setPrettyString($prettyString);
/**
* @return string
*/
@@ -13,10 +13,12 @@ namespace Composer\Semver\Constraint;
/**
* Defines the absence of a constraint.
*
* This constraint matches everything.
*/
class EmptyConstraint implements ConstraintInterface
class MatchAllConstraint implements ConstraintInterface
{
/** @var string */
/** @var string|null */
protected $prettyString;
/**
@@ -30,7 +32,15 @@ class EmptyConstraint implements ConstraintInterface
}
/**
* @param $prettyString
* {@inheritDoc}
*/
public function compile($otherOperator)
{
return 'true';
}
/**
* {@inheritDoc}
*/
public function setPrettyString($prettyString)
{
@@ -38,7 +48,7 @@ class EmptyConstraint implements ConstraintInterface
}
/**
* @return string
* {@inheritDoc}
*/
public function getPrettyString()
{
@@ -50,10 +60,26 @@ class EmptyConstraint implements ConstraintInterface
}
/**
* @return string
* {@inheritDoc}
*/
public function __toString()
{
return '[]';
return '*';
}
/**
* {@inheritDoc}
*/
public function getUpperBound()
{
return Bound::positiveInfinity();
}
/**
* {@inheritDoc}
*/
public function getLowerBound()
{
return Bound::zero();
}
}
@@ -0,0 +1,83 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Blackhole of constraints, nothing escapes it
*/
class MatchNoneConstraint implements ConstraintInterface
{
/** @var string|null */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
return false;
}
/**
* {@inheritDoc}
*/
public function compile($otherOperator)
{
return 'false';
}
/**
* {@inheritDoc}
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* {@inheritDoc}
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return (string) $this;
}
/**
* {@inheritDoc}
*/
public function __toString()
{
return '[]';
}
/**
* {@inheritDoc}
*/
public function getUpperBound()
{
return new Bound('0.0.0.0-dev', false);
}
/**
* {@inheritDoc}
*/
public function getLowerBound()
{
return new Bound('0.0.0.0-dev', false);
}
}
+214 -9
View File
@@ -16,21 +16,43 @@ namespace Composer\Semver\Constraint;
*/
class MultiConstraint implements ConstraintInterface
{
/** @var ConstraintInterface[] */
/**
* @var ConstraintInterface[]
* @phpstan-var non-empty-array<ConstraintInterface>
*/
protected $constraints;
/** @var string */
/** @var string|null */
protected $prettyString;
/** @var string|null */
protected $string;
/** @var bool */
protected $conjunctive;
/** @var Bound|null */
protected $lowerBound;
/** @var Bound|null */
protected $upperBound;
/**
* @param ConstraintInterface[] $constraints A set of constraints
* @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
* @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
*
* @throws \InvalidArgumentException If less than 2 constraints are passed
*/
public function __construct(array $constraints, $conjunctive = true)
{
if (\count($constraints) < 2) {
throw new \InvalidArgumentException(
'Must provide at least two constraints for a MultiConstraint. Use '.
'the regular Constraint class for one constraint only or MatchAllConstraint for none. You may use '.
'MultiConstraint::create() which optimizes and handles those cases automatically.'
);
}
$this->constraints = $constraints;
$this->conjunctive = $conjunctive;
}
@@ -59,6 +81,34 @@ class MultiConstraint implements ConstraintInterface
return !$this->conjunctive;
}
/**
* {@inheritDoc}
*/
public function compile($otherOperator)
{
$parts = array();
foreach ($this->constraints as $constraint) {
$code = $constraint->compile($otherOperator);
if ($code === 'true') {
if (!$this->conjunctive) {
return 'true';
}
} elseif ($code === 'false') {
if ($this->conjunctive) {
return 'false';
}
} else {
$parts[] = '('.$code.')';
}
}
if (!$parts) {
return $this->conjunctive ? 'true' : 'false';
}
return $this->conjunctive ? implode('&&', $parts) : implode('||', $parts);
}
/**
* @param ConstraintInterface $provider
*
@@ -68,7 +118,7 @@ class MultiConstraint implements ConstraintInterface
{
if (false === $this->conjunctive) {
foreach ($this->constraints as $constraint) {
if ($constraint->matches($provider)) {
if ($provider->matches($constraint)) {
return true;
}
}
@@ -76,8 +126,15 @@ class MultiConstraint implements ConstraintInterface
return false;
}
// when matching a conjunctive and a disjunctive multi constraint we have to iterate over the disjunctive one
// otherwise we'd return true if different parts of the disjunctive constraint match the conjunctive one
// which would lead to incorrect results, e.g. [>1 and <2] would match [<1 or >2] although they do not intersect
if ($provider instanceof MultiConstraint && $provider->isDisjunctive()) {
return $provider->matches($this);
}
foreach ($this->constraints as $constraint) {
if (!$constraint->matches($provider)) {
if (!$provider->matches($constraint)) {
return false;
}
}
@@ -86,7 +143,7 @@ class MultiConstraint implements ConstraintInterface
}
/**
* @param string $prettyString
* {@inheritDoc}
*/
public function setPrettyString($prettyString)
{
@@ -94,7 +151,7 @@ class MultiConstraint implements ConstraintInterface
}
/**
* @return string
* {@inheritDoc}
*/
public function getPrettyString()
{
@@ -106,15 +163,163 @@ class MultiConstraint implements ConstraintInterface
}
/**
* @return string
* {@inheritDoc}
*/
public function __toString()
{
if ($this->string !== null) {
return $this->string;
}
$constraints = array();
foreach ($this->constraints as $constraint) {
$constraints[] = (string) $constraint;
}
return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
return $this->string = '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
}
/**
* {@inheritDoc}
*/
public function getLowerBound()
{
$this->extractBounds();
if (null === $this->lowerBound) {
throw new \LogicException('extractBounds should have populated the lowerBound property');
}
return $this->lowerBound;
}
/**
* {@inheritDoc}
*/
public function getUpperBound()
{
$this->extractBounds();
if (null === $this->upperBound) {
throw new \LogicException('extractBounds should have populated the upperBound property');
}
return $this->upperBound;
}
/**
* Tries to optimize the constraints as much as possible, meaning
* reducing/collapsing congruent constraints etc.
* Does not necessarily return a MultiConstraint instance if
* things can be reduced to a simple constraint
*
* @param ConstraintInterface[] $constraints A set of constraints
* @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
*
* @return ConstraintInterface
*/
public static function create(array $constraints, $conjunctive = true)
{
if (0 === \count($constraints)) {
return new MatchAllConstraint();
}
if (1 === \count($constraints)) {
return $constraints[0];
}
$optimized = self::optimizeConstraints($constraints, $conjunctive);
if ($optimized !== null) {
list($constraints, $conjunctive) = $optimized;
if (\count($constraints) === 1) {
return $constraints[0];
}
}
return new self($constraints, $conjunctive);
}
/**
* @param ConstraintInterface[] $constraints
* @param bool $conjunctive
* @return ?array
*
* @phpstan-return array{0: list<ConstraintInterface>, 1: bool}|null
*/
private static function optimizeConstraints(array $constraints, $conjunctive)
{
// parse the two OR groups and if they are contiguous we collapse
// them into one constraint
// [>= 1 < 2] || [>= 2 < 3] || [>= 3 < 4] => [>= 1 < 4]
if (!$conjunctive) {
$left = $constraints[0];
$mergedConstraints = array();
$optimized = false;
for ($i = 1, $l = \count($constraints); $i < $l; $i++) {
$right = $constraints[$i];
if (
$left instanceof self
&& $left->conjunctive
&& $right instanceof self
&& $right->conjunctive
&& \count($left->constraints) === 2
&& \count($right->constraints) === 2
&& ($left0 = (string) $left->constraints[0])
&& $left0[0] === '>' && $left0[1] === '='
&& ($left1 = (string) $left->constraints[1])
&& $left1[0] === '<'
&& ($right0 = (string) $right->constraints[0])
&& $right0[0] === '>' && $right0[1] === '='
&& ($right1 = (string) $right->constraints[1])
&& $right1[0] === '<'
&& substr($left1, 2) === substr($right0, 3)
) {
$optimized = true;
$left = new MultiConstraint(
array(
$left->constraints[0],
$right->constraints[1],
),
true);
} else {
$mergedConstraints[] = $left;
$left = $right;
}
}
if ($optimized) {
$mergedConstraints[] = $left;
return array($mergedConstraints, false);
}
}
// TODO: Here's the place to put more optimizations
return null;
}
/**
* @return void
*/
private function extractBounds()
{
if (null !== $this->lowerBound) {
return;
}
foreach ($this->constraints as $constraint) {
if (null === $this->lowerBound || null === $this->upperBound) {
$this->lowerBound = $constraint->getLowerBound();
$this->upperBound = $constraint->getUpperBound();
continue;
}
if ($constraint->getLowerBound()->compareTo($this->lowerBound, $this->isConjunctive() ? '>' : '<')) {
$this->lowerBound = $constraint->getLowerBound();
}
if ($constraint->getUpperBound()->compareTo($this->upperBound, $this->isConjunctive() ? '<' : '>')) {
$this->upperBound = $constraint->getUpperBound();
}
}
}
}
+98
View File
@@ -0,0 +1,98 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\Constraint;
class Interval
{
/** @var Constraint */
private $start;
/** @var Constraint */
private $end;
public function __construct(Constraint $start, Constraint $end)
{
$this->start = $start;
$this->end = $end;
}
/**
* @return Constraint
*/
public function getStart()
{
return $this->start;
}
/**
* @return Constraint
*/
public function getEnd()
{
return $this->end;
}
/**
* @return Constraint
*/
public static function fromZero()
{
static $zero;
if (null === $zero) {
$zero = new Constraint('>=', '0.0.0.0-dev');
}
return $zero;
}
/**
* @return Constraint
*/
public static function untilPositiveInfinity()
{
static $positiveInfinity;
if (null === $positiveInfinity) {
$positiveInfinity = new Constraint('<', PHP_INT_MAX.'.0.0.0');
}
return $positiveInfinity;
}
/**
* @return self
*/
public static function any()
{
return new self(self::fromZero(), self::untilPositiveInfinity());
}
/**
* @return array{'names': string[], 'exclude': bool}
*/
public static function anyDev()
{
// any == exclude nothing
return array('names' => array(), 'exclude' => true);
}
/**
* @return array{'names': string[], 'exclude': bool}
*/
public static function noDev()
{
// nothing == no names included
return array('names' => array(), 'exclude' => false);
}
}
+478
View File
@@ -0,0 +1,478 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\Constraint;
use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Semver\Constraint\MatchAllConstraint;
use Composer\Semver\Constraint\MatchNoneConstraint;
use Composer\Semver\Constraint\MultiConstraint;
/**
* Helper class generating intervals from constraints
*
* This contains utilities for:
*
* - compacting an existing constraint which can be used to combine several into one
* by creating a MultiConstraint out of the many constraints you have.
*
* - checking whether one subset is a subset of another.
*
* Note: You should call clear to free memoization memory usage when you are done using this class
*/
class Intervals
{
/**
* @phpstan-var array<string, array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}}>
*/
private static $intervalsCache = array();
/**
* @phpstan-var array<string, int>
*/
private static $opSortOrder = array(
'>=' => -3,
'<' => -2,
'>' => 2,
'<=' => 3,
);
/**
* Clears the memoization cache once you are done
*
* @return void
*/
public static function clear()
{
self::$intervalsCache = array();
}
/**
* Checks whether $candidate is a subset of $constraint
*
* @return bool
*/
public static function isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint)
{
if ($constraint instanceof MatchAllConstraint) {
return true;
}
if ($candidate instanceof MatchNoneConstraint || $constraint instanceof MatchNoneConstraint) {
return false;
}
$intersectionIntervals = self::get(new MultiConstraint(array($candidate, $constraint), true));
$candidateIntervals = self::get($candidate);
if (\count($intersectionIntervals['numeric']) !== \count($candidateIntervals['numeric'])) {
return false;
}
foreach ($intersectionIntervals['numeric'] as $index => $interval) {
if (!isset($candidateIntervals['numeric'][$index])) {
return false;
}
if ((string) $candidateIntervals['numeric'][$index]->getStart() !== (string) $interval->getStart()) {
return false;
}
if ((string) $candidateIntervals['numeric'][$index]->getEnd() !== (string) $interval->getEnd()) {
return false;
}
}
if ($intersectionIntervals['branches']['exclude'] !== $candidateIntervals['branches']['exclude']) {
return false;
}
if (\count($intersectionIntervals['branches']['names']) !== \count($candidateIntervals['branches']['names'])) {
return false;
}
foreach ($intersectionIntervals['branches']['names'] as $index => $name) {
if ($name !== $candidateIntervals['branches']['names'][$index]) {
return false;
}
}
return true;
}
/**
* Checks whether $a and $b have any intersection, equivalent to $a->matches($b)
*
* @return bool
*/
public static function haveIntersections(ConstraintInterface $a, ConstraintInterface $b)
{
if ($a instanceof MatchAllConstraint || $b instanceof MatchAllConstraint) {
return true;
}
if ($a instanceof MatchNoneConstraint || $b instanceof MatchNoneConstraint) {
return false;
}
$intersectionIntervals = self::generateIntervals(new MultiConstraint(array($a, $b), true), true);
return \count($intersectionIntervals['numeric']) > 0 || $intersectionIntervals['branches']['exclude'] || \count($intersectionIntervals['branches']['names']) > 0;
}
/**
* Attempts to optimize a MultiConstraint
*
* When merging MultiConstraints together they can get very large, this will
* compact it by looking at the real intervals covered by all the constraints
* and then creates a new constraint containing only the smallest amount of rules
* to match the same intervals.
*
* @return ConstraintInterface
*/
public static function compactConstraint(ConstraintInterface $constraint)
{
if (!$constraint instanceof MultiConstraint) {
return $constraint;
}
$intervals = self::generateIntervals($constraint);
$constraints = array();
$hasNumericMatchAll = false;
if (\count($intervals['numeric']) === 1 && (string) $intervals['numeric'][0]->getStart() === (string) Interval::fromZero() && (string) $intervals['numeric'][0]->getEnd() === (string) Interval::untilPositiveInfinity()) {
$constraints[] = $intervals['numeric'][0]->getStart();
$hasNumericMatchAll = true;
} else {
$unEqualConstraints = array();
for ($i = 0, $count = \count($intervals['numeric']); $i < $count; $i++) {
$interval = $intervals['numeric'][$i];
// if current interval ends with < N and next interval begins with > N we can swap this out for != N
// but this needs to happen as a conjunctive expression together with the start of the current interval
// and end of next interval, so [>=M, <N] || [>N, <P] => [>=M, !=N, <P] but M/P can be skipped if
// they are zero/+inf
if ($interval->getEnd()->getOperator() === '<' && $i+1 < $count) {
$nextInterval = $intervals['numeric'][$i+1];
if ($interval->getEnd()->getVersion() === $nextInterval->getStart()->getVersion() && $nextInterval->getStart()->getOperator() === '>') {
// only add a start if we didn't already do so, can be skipped if we're looking at second
// interval in [>=M, <N] || [>N, <P] || [>P, <Q] where unEqualConstraints currently contains
// [>=M, !=N] already and we only want to add !=P right now
if (\count($unEqualConstraints) === 0 && (string) $interval->getStart() !== (string) Interval::fromZero()) {
$unEqualConstraints[] = $interval->getStart();
}
$unEqualConstraints[] = new Constraint('!=', $interval->getEnd()->getVersion());
continue;
}
}
if (\count($unEqualConstraints) > 0) {
// this is where the end of the following interval of a != constraint is added as explained above
if ((string) $interval->getEnd() !== (string) Interval::untilPositiveInfinity()) {
$unEqualConstraints[] = $interval->getEnd();
}
// count is 1 if entire constraint is just one != expression
if (\count($unEqualConstraints) > 1) {
$constraints[] = new MultiConstraint($unEqualConstraints, true);
} else {
$constraints[] = $unEqualConstraints[0];
}
$unEqualConstraints = array();
continue;
}
// convert back >= x - <= x intervals to == x
if ($interval->getStart()->getVersion() === $interval->getEnd()->getVersion() && $interval->getStart()->getOperator() === '>=' && $interval->getEnd()->getOperator() === '<=') {
$constraints[] = new Constraint('==', $interval->getStart()->getVersion());
continue;
}
if ((string) $interval->getStart() === (string) Interval::fromZero()) {
$constraints[] = $interval->getEnd();
} elseif ((string) $interval->getEnd() === (string) Interval::untilPositiveInfinity()) {
$constraints[] = $interval->getStart();
} else {
$constraints[] = new MultiConstraint(array($interval->getStart(), $interval->getEnd()), true);
}
}
}
$devConstraints = array();
if (0 === \count($intervals['branches']['names'])) {
if ($intervals['branches']['exclude']) {
if ($hasNumericMatchAll) {
return new MatchAllConstraint;
}
// otherwise constraint should contain a != operator and already cover this
}
} else {
foreach ($intervals['branches']['names'] as $branchName) {
if ($intervals['branches']['exclude']) {
$devConstraints[] = new Constraint('!=', $branchName);
} else {
$devConstraints[] = new Constraint('==', $branchName);
}
}
// excluded branches, e.g. != dev-foo are conjunctive with the interval, so
// > 2.0 != dev-foo must return a conjunctive constraint
if ($intervals['branches']['exclude']) {
if (\count($constraints) > 1) {
return new MultiConstraint(array_merge(
array(new MultiConstraint($constraints, false)),
$devConstraints
), true);
}
if (\count($constraints) === 1 && (string)$constraints[0] === (string)Interval::fromZero()) {
if (\count($devConstraints) > 1) {
return new MultiConstraint($devConstraints, true);
}
return $devConstraints[0];
}
return new MultiConstraint(array_merge($constraints, $devConstraints), true);
}
// otherwise devConstraints contains a list of == operators for branches which are disjunctive with the
// rest of the constraint
$constraints = array_merge($constraints, $devConstraints);
}
if (\count($constraints) > 1) {
return new MultiConstraint($constraints, false);
}
if (\count($constraints) === 1) {
return $constraints[0];
}
return new MatchNoneConstraint;
}
/**
* Creates an array of numeric intervals and branch constraints representing a given constraint
*
* if the returned numeric array is empty it means the constraint matches nothing in the numeric range (0 - +inf)
* if the returned branches array is empty it means no dev-* versions are matched
* if a constraint matches all possible dev-* versions, branches will contain Interval::anyDev()
*
* @return array
* @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}}
*/
public static function get(ConstraintInterface $constraint)
{
$key = (string) $constraint;
if (!isset(self::$intervalsCache[$key])) {
self::$intervalsCache[$key] = self::generateIntervals($constraint);
}
return self::$intervalsCache[$key];
}
/**
* @param bool $stopOnFirstValidInterval
*
* @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}}
*/
private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = false)
{
if ($constraint instanceof MatchAllConstraint) {
return array('numeric' => array(new Interval(Interval::fromZero(), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev());
}
if ($constraint instanceof MatchNoneConstraint) {
return array('numeric' => array(), 'branches' => array('names' => array(), 'exclude' => false));
}
if ($constraint instanceof Constraint) {
return self::generateSingleConstraintIntervals($constraint);
}
if (!$constraint instanceof MultiConstraint) {
throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got '.\get_class($constraint).'.');
}
$constraints = $constraint->getConstraints();
$numericGroups = array();
$constraintBranches = array();
foreach ($constraints as $c) {
$res = self::get($c);
$numericGroups[] = $res['numeric'];
$constraintBranches[] = $res['branches'];
}
if ($constraint->isDisjunctive()) {
$branches = Interval::noDev();
foreach ($constraintBranches as $b) {
if ($b['exclude']) {
if ($branches['exclude']) {
// disjunctive constraint, so only exclude what's excluded in all constraints
// !=a,!=b || !=b,!=c => !=b
$branches['names'] = array_intersect($branches['names'], $b['names']);
} else {
// disjunctive constraint so exclude all names which are not explicitly included in the alternative
// (==b || ==c) || !=a,!=b => !=a
$branches['exclude'] = true;
$branches['names'] = array_diff($b['names'], $branches['names']);
}
} else {
if ($branches['exclude']) {
// disjunctive constraint so exclude all names which are not explicitly included in the alternative
// !=a,!=b || (==b || ==c) => !=a
$branches['names'] = array_diff($branches['names'], $b['names']);
} else {
// disjunctive constraint, so just add all the other branches
// (==a || ==b) || ==c => ==a || ==b || ==c
$branches['names'] = array_merge($branches['names'], $b['names']);
}
}
}
} else {
$branches = Interval::anyDev();
foreach ($constraintBranches as $b) {
if ($b['exclude']) {
if ($branches['exclude']) {
// conjunctive, so just add all branch names to be excluded
// !=a && !=b => !=a,!=b
$branches['names'] = array_merge($branches['names'], $b['names']);
} else {
// conjunctive, so only keep included names which are not excluded
// (==a||==c) && !=a,!=b => ==c
$branches['names'] = array_diff($branches['names'], $b['names']);
}
} else {
if ($branches['exclude']) {
// conjunctive, so only keep included names which are not excluded
// !=a,!=b && (==a||==c) => ==c
$branches['names'] = array_diff($b['names'], $branches['names']);
$branches['exclude'] = false;
} else {
// conjunctive, so only keep names that are included in both
// (==a||==b) && (==a||==c) => ==a
$branches['names'] = array_intersect($branches['names'], $b['names']);
}
}
}
}
$branches['names'] = array_unique($branches['names']);
if (\count($numericGroups) === 1) {
return array('numeric' => $numericGroups[0], 'branches' => $branches);
}
$borders = array();
foreach ($numericGroups as $group) {
foreach ($group as $interval) {
$borders[] = array('version' => $interval->getStart()->getVersion(), 'operator' => $interval->getStart()->getOperator(), 'side' => 'start');
$borders[] = array('version' => $interval->getEnd()->getVersion(), 'operator' => $interval->getEnd()->getOperator(), 'side' => 'end');
}
}
$opSortOrder = self::$opSortOrder;
usort($borders, function ($a, $b) use ($opSortOrder) {
$order = version_compare($a['version'], $b['version']);
if ($order === 0) {
return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']];
}
return $order;
});
$activeIntervals = 0;
$intervals = array();
$index = 0;
$activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1;
$start = null;
foreach ($borders as $border) {
if ($border['side'] === 'start') {
$activeIntervals++;
} else {
$activeIntervals--;
}
if (!$start && $activeIntervals >= $activationThreshold) {
$start = new Constraint($border['operator'], $border['version']);
} elseif ($start && $activeIntervals < $activationThreshold) {
// filter out invalid intervals like > x - <= x, or >= x - < x
if (
version_compare($start->getVersion(), $border['version'], '=')
&& (
($start->getOperator() === '>' && $border['operator'] === '<=')
|| ($start->getOperator() === '>=' && $border['operator'] === '<')
)
) {
unset($intervals[$index]);
} else {
$intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version']));
$index++;
if ($stopOnFirstValidInterval) {
break;
}
}
$start = null;
}
}
return array('numeric' => $intervals, 'branches' => $branches);
}
/**
* @phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}}}
*/
private static function generateSingleConstraintIntervals(Constraint $constraint)
{
$op = $constraint->getOperator();
// handle branch constraints first
if (strpos($constraint->getVersion(), 'dev-') === 0) {
$intervals = array();
$branches = array('names' => array(), 'exclude' => false);
// != dev-foo means any numeric version may match, we treat >/< like != they are not really defined for branches
if ($op === '!=') {
$intervals[] = new Interval(Interval::fromZero(), Interval::untilPositiveInfinity());
$branches = array('names' => array($constraint->getVersion()), 'exclude' => true);
} elseif ($op === '==') {
$branches['names'][] = $constraint->getVersion();
}
return array(
'numeric' => $intervals,
'branches' => $branches,
);
}
if ($op[0] === '>') { // > & >=
return array('numeric' => array(new Interval($constraint, Interval::untilPositiveInfinity())), 'branches' => Interval::noDev());
}
if ($op[0] === '<') { // < & <=
return array('numeric' => array(new Interval(Interval::fromZero(), $constraint)), 'branches' => Interval::noDev());
}
if ($op === '!=') {
// convert !=x to intervals of 0 - <x && >x - +inf + dev*
return array('numeric' => array(
new Interval(Interval::fromZero(), new Constraint('<', $constraint->getVersion())),
new Interval(new Constraint('>', $constraint->getVersion()), Interval::untilPositiveInfinity()),
), 'branches' => Interval::anyDev());
}
// convert ==x to an interval of >=x - <=x
return array('numeric' => array(
new Interval(new Constraint('>=', $constraint->getVersion()), new Constraint('<=', $constraint->getVersion())),
), 'branches' => Interval::noDev());
}
}
+13 -11
View File
@@ -45,10 +45,10 @@ class Semver
/**
* Return all versions that satisfy given constraints.
*
* @param array $versions
* @param string $constraints
* @param string[] $versions
* @param string $constraints
*
* @return array
* @return string[]
*/
public static function satisfiedBy(array $versions, $constraints)
{
@@ -62,9 +62,9 @@ class Semver
/**
* Sort given array of versions.
*
* @param array $versions
* @param string[] $versions
*
* @return array
* @return string[]
*/
public static function sort(array $versions)
{
@@ -74,9 +74,9 @@ class Semver
/**
* Sort given array of versions in reverse.
*
* @param array $versions
* @param string[] $versions
*
* @return array
* @return string[]
*/
public static function rsort(array $versions)
{
@@ -84,10 +84,10 @@ class Semver
}
/**
* @param array $versions
* @param int $direction
* @param string[] $versions
* @param int $direction
*
* @return array
* @return string[]
*/
private static function usort(array $versions, $direction)
{
@@ -101,7 +101,9 @@ class Semver
// Normalize outside of usort() scope for minor performance increase.
// Creates an array of arrays: [[normalized, key], ...]
foreach ($versions as $key => $version) {
$normalized[] = array($versionParser->normalize($version), $key);
$normalizedVersion = $versionParser->normalize($version);
$normalizedVersion = $versionParser->normalizeDefaultBranch($normalizedVersion);
$normalized[] = array($normalizedVersion, $key);
}
usort($normalized, function (array $left, array $right) use ($direction) {
+108 -70
View File
@@ -12,7 +12,7 @@
namespace Composer\Semver;
use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Semver\Constraint\EmptyConstraint;
use Composer\Semver\Constraint\MatchAllConstraint;
use Composer\Semver\Constraint\MultiConstraint;
use Composer\Semver\Constraint\Constraint;
@@ -38,8 +38,8 @@ class VersionParser
*/
private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
/** @var array */
private static $stabilities = array('stable', 'RC', 'beta', 'alpha', 'dev');
/** @var string */
private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev';
/**
* Returns the stability of a version.
@@ -50,7 +50,7 @@ class VersionParser
*/
public static function parseStability($version)
{
$version = preg_replace('{#.+$}i', '', $version);
$version = (string) preg_replace('{#.+$}', '', $version);
if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
return 'dev';
@@ -102,21 +102,24 @@ class VersionParser
public function normalize($version, $fullVersion = null)
{
$version = trim($version);
$origVersion = $version;
if (null === $fullVersion) {
$fullVersion = $version;
}
// strip off aliasing
if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
// verify that the alias is a version without constraint
$this->normalize($match[2]);
$version = $match[1];
}
// match master-like branches
if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
return '9999999-dev';
// strip off stability flag
if (preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) {
$version = substr($version, 0, strlen($version) - strlen($match[0]));
}
// normalize master/trunk/default branches to dev-name for BC with 1.x as these used to be valid constraints
if (\in_array($version, array('master', 'trunk', 'default'), true)) {
$version = 'dev-' . $version;
}
// if requirement is branch-like, use full name
@@ -148,7 +151,7 @@ class VersionParser
if ('stable' === $matches[$index]) {
return $version;
}
$version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? ltrim($matches[$index + 1], '.-') : '');
$version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? ltrim($matches[$index + 1], '.-') : '');
}
if (!empty($matches[$index + 2])) {
@@ -161,19 +164,25 @@ class VersionParser
// match dev branches
if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
try {
return $this->normalizeBranch($match[1]);
$normalized = $this->normalizeBranch($match[1]);
// a branch ending with -dev is only valid if it is numeric
// if it gets prefixed with dev- it means the branch name should
// have had a dev- prefix already when passed to normalize
if (strpos($normalized, 'dev-') === false) {
return $normalized;
}
} catch (\Exception $e) {
}
}
$extraMessage = '';
if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) {
if (preg_match('{ +as +' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))?$}', $fullVersion)) {
$extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
} elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) {
} elseif (preg_match('{^' . preg_quote($version) . '(?:@(?:'.self::$stabilitiesRegex.'))? +as +}', $fullVersion)) {
$extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
}
throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage);
throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage);
}
/**
@@ -203,10 +212,6 @@ class VersionParser
{
$name = trim($name);
if (in_array($name, array('master', 'trunk', 'default'))) {
return $this->normalize($name);
}
if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
$version = '';
for ($i = 1; $i < 5; ++$i) {
@@ -219,6 +224,22 @@ class VersionParser
return 'dev-' . $name;
}
/**
* Normalizes a default branch name (i.e. master on git) to 9999999-dev.
*
* @param string $name
*
* @return string
*/
public function normalizeDefaultBranch($name)
{
if ($name === 'dev-master' || $name === 'dev-default' || $name === 'dev-trunk') {
return '9999999-dev';
}
return $name;
}
/**
* Parses a constraint string into MultiConstraint and/or Constraint objects.
*
@@ -230,20 +251,18 @@ class VersionParser
{
$prettyConstraint = $constraints;
if (preg_match('{^([^,\s]*?)@(' . implode('|', self::$stabilities) . ')$}i', $constraints, $match)) {
$constraints = empty($match[1]) ? '*' : $match[1];
}
if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraints, $match)) {
$constraints = $match[1];
}
$orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
if (false === $orConstraints) {
throw new \RuntimeException('Failed to preg_split string: '.$constraints);
}
$orGroups = array();
foreach ($orConstraints as $constraints) {
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
if (count($andConstraints) > 1) {
if (false === $andConstraints) {
throw new \RuntimeException('Failed to preg_split string: '.$constraints);
}
if (\count($andConstraints) > 1) {
$constraintObjects = array();
foreach ($andConstraints as $constraint) {
foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
@@ -254,7 +273,7 @@ class VersionParser
$constraintObjects = $this->parseConstraint($andConstraints[0]);
}
if (1 === count($constraintObjects)) {
if (1 === \count($constraintObjects)) {
$constraint = $constraintObjects[0];
} else {
$constraint = new MultiConstraint($constraintObjects);
@@ -263,28 +282,7 @@ class VersionParser
$orGroups[] = $constraint;
}
if (1 === count($orGroups)) {
$constraint = $orGroups[0];
} elseif (2 === count($orGroups)
// parse the two OR groups and if they are contiguous we collapse
// them into one constraint
&& $orGroups[0] instanceof MultiConstraint
&& $orGroups[1] instanceof MultiConstraint
&& 2 === count($orGroups[0]->getConstraints())
&& 2 === count($orGroups[1]->getConstraints())
&& ($a = (string) $orGroups[0])
&& strpos($a, '[>=') === 0 && (false !== ($posA = strpos($a, '<', 4)))
&& ($b = (string) $orGroups[1])
&& strpos($b, '[>=') === 0 && (false !== ($posB = strpos($b, '<', 4)))
&& substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
) {
$constraint = new MultiConstraint(array(
new Constraint('>=', substr($a, 4, $posA - 5)),
new Constraint('<', substr($b, $posB + 2, -1)),
));
} else {
$constraint = new MultiConstraint($orGroups, false);
}
$constraint = MultiConstraint::create($orGroups, false);
$constraint->setPrettyString($prettyConstraint);
@@ -297,21 +295,38 @@ class VersionParser
* @throws \UnexpectedValueException
*
* @return array
*
* @phpstan-return non-empty-array<ConstraintInterface>
*/
private function parseConstraint($constraint)
{
if (preg_match('{^([^,\s]+?)@(' . implode('|', self::$stabilities) . ')$}i', $constraint, $match)) {
// strip off aliasing
if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $constraint, $match)) {
$constraint = $match[1];
}
// strip @stability flags, and keep it for later use
if (preg_match('{^([^,\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) {
$constraint = '' !== $match[1] ? $match[1] : '*';
if ($match[2] !== 'stable') {
$stabilityModifier = $match[2];
}
}
if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) {
return array(new EmptyConstraint());
// get rid of #refs as those are used by composer only
if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraint, $match)) {
$constraint = $match[1];
}
$versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?' . self::$modifierRegex . '(?:\+[^\s]+)?';
if (preg_match('{^(v)?[xX*](\.[xX*])*$}i', $constraint, $match)) {
if (!empty($match[1]) || !empty($match[2])) {
return array(new Constraint('>=', '0.0.0.0-dev'));
}
return array(new MatchAllConstraint());
}
$versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?(?:' . self::$modifierRegex . '|\.([xX*][.-]?dev))(?:\+[^\s]+)?';
// Tilde Range
//
@@ -337,9 +352,14 @@ class VersionParser
$position = 1;
}
// when matching 2.x-dev or 3.0.x-dev we have to shift the second or third number, despite no second/third number matching above
if (!empty($matches[8])) {
$position++;
}
// Calculate the stability suffix
$stabilitySuffix = '';
if (empty($matches[5]) && empty($matches[7])) {
if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
$stabilitySuffix .= '-dev';
}
@@ -375,7 +395,7 @@ class VersionParser
// Calculate the stability suffix
$stabilitySuffix = '';
if (empty($matches[5]) && empty($matches[7])) {
if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
$stabilitySuffix .= '-dev';
}
@@ -428,7 +448,7 @@ class VersionParser
if (preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
// Calculate the stability suffix
$lowStabilitySuffix = '';
if (empty($matches[6]) && empty($matches[8])) {
if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) {
$lowStabilitySuffix = '-dev';
}
@@ -439,12 +459,16 @@ class VersionParser
return ($x === 0 || $x === '0') ? false : empty($x);
};
if ((!$empty($matches[11]) && !$empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) {
if ((!$empty($matches[12]) && !$empty($matches[13])) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) {
$highVersion = $this->normalize($matches['to']);
$upperBound = new Constraint('<=', $highVersion);
} else {
$highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]);
$highVersion = $this->manipulateVersionString($highMatch, $empty($matches[11]) ? 1 : 2, 1) . '-dev';
$highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]);
// validate to version
$this->normalize($matches['to']);
$highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev';
$upperBound = new Constraint('<', $highVersion);
}
@@ -457,11 +481,23 @@ class VersionParser
// Basic Comparators
if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
try {
$version = $this->normalize($matches[2]);
try {
$version = $this->normalize($matches[2]);
} catch (\UnexpectedValueException $e) {
// recover from an invalid constraint like foobar-dev which should be dev-foobar
// except if the constraint uses a known operator, in which case it must be a parse error
if (substr($matches[2], -4) === '-dev' && preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) {
$version = $this->normalize('dev-'.substr($matches[2], 0, -4));
} else {
throw $e;
}
}
if (!empty($stabilityModifier) && self::parseStability($version) === 'stable') {
$op = $matches[1] ?: '=';
if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') {
$version .= '-' . $stabilityModifier;
} elseif ('<' === $matches[1] || '>=' === $matches[1]) {
} elseif ('<' === $op || '>=' === $op) {
if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
if (strpos($matches[2], 'dev-') !== 0) {
$version .= '-dev';
@@ -487,14 +523,16 @@ class VersionParser
*
* Support function for {@link parseConstraint()}
*
* @param array $matches Array with version parts in array indexes 1,2,3,4
* @param int $position 1,2,3,4 - which segment of the version to increment/decrement
* @param int $increment
* @param string $pad The string to pad version parts after $position
* @param array $matches Array with version parts in array indexes 1,2,3,4
* @param int $position 1,2,3,4 - which segment of the version to increment/decrement
* @param int $increment
* @param string $pad The string to pad version parts after $position
*
* @return string The new version
* @return string|null The new version
*
* @phpstan-param string[] $matches
*/
private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
private function manipulateVersionString(array $matches, $position, $increment = 0, $pad = '0')
{
for ($i = 4; $i > 0; --$i) {
if ($i > $position) {
+43 -1
View File
@@ -1,5 +1,39 @@
## [Unreleased]
## [2.0.2] - 2021-07-31
* Added: support for `xdebug_info('mode')` in Xdebug 3.1.
* Added: support for Psr\Log versions 2 and 3.
* Fixed: remove ini directives from non-cli HOST/PATH sections.
## [2.0.1] - 2021-05-05
* Fixed: don't restart if the cwd is a UNC path and cmd.exe will be invoked.
## [2.0.0] - 2021-04-09
* Break: this is a major release, see [UPGRADE.md](UPGRADE.md) for more information.
* Break: removed optional `$colorOption` constructor param and passthru fallback.
* Break: renamed `requiresRestart` param from `$isLoaded` to `$default`.
* Break: changed `restart` param `$command` from a string to an array.
* Added: support for Xdebug3 to only restart if Xdebug is not running with `xdebug.mode=off`.
* Added: `isXdebugActive()` method to determine if Xdebug is still running in the restart.
* Added: feature to bypass the shell in PHP-7.4+ by giving `proc_open` an array of arguments.
* Added: Process utility class to the API.
## [1.4.6] - 2021-03-25
* Fixed: fail restart if `proc_open` has been disabled in `disable_functions`.
* Fixed: enable Windows CTRL event handling in the restarted process.
## [1.4.5] - 2020-11-13
* Fixed: use `proc_open` when available for correct FD forwarding to the restarted process.
## [1.4.4] - 2020-10-24
* Fixed: exception if 'pcntl_signal' is disabled.
## [1.4.3] - 2020-08-19
* Fixed: restore SIGINT to default handler in restarted process if no other handler exists.
## [1.4.2] - 2020-06-04
* Fixed: ignore SIGINTs to let the restarted process handle them.
## [1.4.1] - 2020-03-01
* Fixed: restart fails if an ini file is empty.
@@ -57,7 +91,15 @@
* Break: the following class was renamed:
- `Composer\XdebugHandler` -> `Composer\XdebugHandler\XdebugHandler`
[Unreleased]: https://github.com/composer/xdebug-handler/compare/1.4.1...HEAD
[Unreleased]: https://github.com/composer/xdebug-handler/compare/2.0.2...HEAD
[2.0.2]: https://github.com/composer/xdebug-handler/compare/2.0.1...2.0.2
[2.0.1]: https://github.com/composer/xdebug-handler/compare/2.0.0...2.0.1
[2.0.0]: https://github.com/composer/xdebug-handler/compare/1.4.6...2.0.0
[1.4.6]: https://github.com/composer/xdebug-handler/compare/1.4.5...1.4.6
[1.4.5]: https://github.com/composer/xdebug-handler/compare/1.4.4...1.4.5
[1.4.4]: https://github.com/composer/xdebug-handler/compare/1.4.3...1.4.4
[1.4.3]: https://github.com/composer/xdebug-handler/compare/1.4.2...1.4.3
[1.4.2]: https://github.com/composer/xdebug-handler/compare/1.4.1...1.4.2
[1.4.1]: https://github.com/composer/xdebug-handler/compare/1.4.0...1.4.1
[1.4.0]: https://github.com/composer/xdebug-handler/compare/1.3.3...1.4.0
[1.3.3]: https://github.com/composer/xdebug-handler/compare/1.3.2...1.3.3
+23 -20
View File
@@ -1,16 +1,19 @@
# composer/xdebug-handler
[![packagist](https://img.shields.io/packagist/v/composer/xdebug-handler.svg)](https://packagist.org/packages/composer/xdebug-handler)
[![linux build](https://img.shields.io/travis/composer/xdebug-handler/master.svg?label=linux+build)](https://travis-ci.org/composer/xdebug-handler)
[![windows build](https://img.shields.io/appveyor/ci/Seldaek/xdebug-handler/master.svg?label=windows+build)](https://ci.appveyor.com/project/Seldaek/xdebug-handler)
[![Continuous Integration](https://github.com/composer/xdebug-handler/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/composer/xdebug-handler/actions)
![license](https://img.shields.io/github/license/composer/xdebug-handler.svg)
![php](https://img.shields.io/packagist/php-v/composer/xdebug-handler.svg?colorB=8892BF&label=php)
Restart a CLI process without loading the Xdebug extension.
Restart a CLI process without loading the Xdebug extension, unless `xdebug.mode=off`.
Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.
### Version 2
Support added for Xdebug3. See [UPGRADE](UPGRADE.md) for more information.
## Installation
Install the latest version with:
@@ -32,21 +35,11 @@ $xdebug->check();
unset($xdebug);
```
The constructor takes two parameters:
#### _$envPrefix_
This is used to create distinct environment variables and is upper-cased and prepended to default base values. The above example enables the use of:
The constructor takes a single parameter, `$envPrefix`, which is upper-cased and prepended to default base values to create two distinct environment variables. The above example enables the use of:
- `MYAPP_ALLOW_XDEBUG=1` to override automatic restart and allow Xdebug
- `MYAPP_ORIGINAL_INIS` to obtain ini file locations in a restarted process
#### _$colorOption_
This optional value is added to the restart command-line and is needed to force color output in a piped child process. Only long-options are supported, for example `--ansi` or `--colors=always` etc.
If the original command-line contains an argument that pattern matches this value (for example `--no-ansi`, `--colors=never`) then _$colorOption_ is ignored.
If the pattern match ends with `=auto` (for example `--colors=auto`), the argument is replaced by _$colorOption_. Otherwise it is added at either the end of the command-line, or preceding the first double-dash `--` delimiter.
## Advanced Usage
* [How it works](#how-it-works)
@@ -63,12 +56,18 @@ A temporary ini file is created from the loaded (and scanned) ini files, with an
* `MYAPP_ALLOW_XDEBUG` is set with internal data to flag and use in the restart.
* The command-line and environment are [configured](#process-configuration) for the restart.
* The application is restarted in a new process using `passthru`.
* The application is restarted in a new process.
* The restart settings are stored in the environment.
* `MYAPP_ALLOW_XDEBUG` is unset.
* The application runs and exits.
* The main process exits with the exit code from the restarted process.
#### Signal handling
From PHP 7.1 with the pcntl extension loaded, asynchronous signal handling is automatically enabled. `SIGINT` is set to `SIG_IGN` in the parent
process and restored to `SIG_DFL` in the restarted process (if no other handler has been set).
From PHP 7.4 on Windows, `CTRL+C` and `CTRL+BREAK` handling is ignored in the parent process and automatically enabled in the restarted process.
### Limitations
There are a few things to be aware of when running inside a restarted process.
@@ -124,6 +123,9 @@ $version = XdebugHandler::getSkippedVersion();
# $version: '2.6.0' (for example), or an empty string
```
#### _isXdebugActive()_
Returns true if Xdebug is loaded and is running in an active mode (if it supports modes). Returns false if Xdebug is not loaded, or it is running with `xdebug.mode=off`.
### Setter methods
These methods implement a fluent interface and must be called before the main `check()` method.
@@ -232,15 +234,16 @@ The following environment settings can be used to troubleshoot unexpected behavi
### Extending the library
The API is defined by classes and their accessible elements that are not annotated as @internal. The main class has two protected methods that can be overridden to provide additional functionality:
#### _requiresRestart($isLoaded)_
By default the process will restart if Xdebug is loaded. Extending this method allows an application to decide, by returning a boolean (or equivalent) value. It is only called if `MYAPP_ALLOW_XDEBUG` is empty, so it will not be called in the restarted process (where this variable contains internal data), or if the restart has been overridden.
#### _requiresRestart($default)_
By default the process will restart if Xdebug is loaded and not running with `xdebug.mode=off`. Extending this method allows an application to decide, by returning a boolean (or equivalent) value.
It is only called if `MYAPP_ALLOW_XDEBUG` is empty, so it will not be called in the restarted process (where this variable contains internal data), or if the restart has been overridden.
Note that the [setMainScript()](#setmainscriptscript) and [setPersistent()](#setpersistent) setters can be used here, if required.
#### _restart($command)_
An application can extend this to modify the temporary ini file, its location given in the `tmpIni` property. New settings can be safely appended to the end of the data, which is `PHP_EOL` terminated.
Note that the `$command` parameter is the escaped command-line string that will be used for the new process and must be treated accordingly.
The `$command` parameter is an array of unescaped command-line arguments that will be used for the new process.
Remember to finish with `parent::restart($command)`.
@@ -259,7 +262,7 @@ class MyRestarter extends XdebugHandler
{
private $required;
protected function requiresRestart($isLoaded)
protected function requiresRestart($default)
{
if (Command::isHelp()) {
# No need to disable Xdebug for this
@@ -267,7 +270,7 @@ class MyRestarter extends XdebugHandler
}
$this->required = (bool) ini_get('phar.readonly');
return $isLoaded || $this->required;
return $this->required || $default;
}
protected function restart($command)
+30
View File
@@ -0,0 +1,30 @@
## Upgrading from 1.x
The default behaviour has changed from always restarting if Xdebug is loaded, to only restarting if
Xdebug is _active_. This has been introduced to support Xdebug3
[modes](https://xdebug.org/docs/all_settings#mode). Xdebug is considered active if it is loaded, and
for Xdebug3, if it is running in a mode other than `xdebug.mode=off`.
* Break: removed optional `$colorOption` constructor param and passthru fallback.
Just use `new XdebugHandler('myapp')` to instantiate the class and color support will be
detectable in the restarted process.
* Added: `isXdebugActive()` method to determine if Xdebug is still running in the restart.
Returns true if Xdebug is loaded and is running in an active mode (if it supports modes).
Returns false if Xdebug is not loaded, or it is running with `xdebug.mode=off`.
### Extending classes
* Break: renamed `requiresRestart` param from `$isLoaded` to `$default`.
This reflects the new default behaviour which is to restart only if Xdebug is active.
* Break: changed `restart` param `$command` from a string to an array.
Only important if you modified the string. `$command` is now an array of unescaped arguments.
* Added: Process utility class to the API.
This class was previously annotated as @internal and has been refactored due to recent changes.
+5 -3
View File
@@ -19,10 +19,11 @@
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
"psr/log": "^1 || ^2 || ^3"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
"symfony/phpunit-bridge": "^4.2 || ^5",
"phpstan/phpstan": "^0.12.55"
},
"autoload": {
"psr-4": {
@@ -35,6 +36,7 @@
}
},
"scripts": {
"test": "phpunit"
"test": "vendor/bin/simple-phpunit",
"phpstan": "vendor/bin/phpstan analyse"
}
}
+15 -4
View File
@@ -49,8 +49,8 @@ class PhpConfig
public function usePersistent()
{
if ($data = $this->getDataAndReset()) {
Process::setEnv('PHPRC', $data['tmpIni']);
Process::setEnv('PHP_INI_SCAN_DIR', '');
$this->updateEnv('PHPRC', $data['tmpIni']);
$this->updateEnv('PHP_INI_SCAN_DIR', '');
}
return array();
@@ -64,10 +64,21 @@ class PhpConfig
private function getDataAndReset()
{
if ($data = XdebugHandler::getRestartSettings()) {
Process::setEnv('PHPRC', $data['phprc']);
Process::setEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
$this->updateEnv('PHPRC', $data['phprc']);
$this->updateEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
}
return $data;
}
/**
* Updates a restart settings value in the environment
*
* @param string $name
* @param string|false $value
*/
private function updateEnv($name, $value)
{
Process::setEnv($name, false !== $value ? $value : null);
}
}
+12 -79
View File
@@ -12,59 +12,12 @@
namespace Composer\XdebugHandler;
/**
* Provides utility functions to prepare a child process command-line and set
* environment variables in that process.
* Process utility functions
*
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
* @internal
*/
class Process
{
/**
* Returns an array of parameters, including a color option if required
*
* A color option is needed because child process output is piped.
*
* @param array $args The script parameters
* @param string $colorOption The long option to force color output
*
* @return array
*/
public static function addColorOption(array $args, $colorOption)
{
if (!$colorOption
|| in_array($colorOption, $args)
|| !preg_match('/^--([a-z]+$)|(^--[a-z]+=)/', $colorOption, $matches)) {
return $args;
}
if (isset($matches[2])) {
// Handle --color(s)= options
if (false !== ($index = array_search($matches[2].'auto', $args))) {
$args[$index] = $colorOption;
return $args;
} elseif (preg_grep('/^'.$matches[2].'/', $args)) {
return $args;
}
} elseif (in_array('--no-'.$matches[1], $args)) {
return $args;
}
// Check for NO_COLOR variable (https://no-color.org/)
if (false !== getenv('NO_COLOR')) {
return $args;
}
if (false !== ($index = array_search('--', $args))) {
// Position option before double-dash delimiter
array_splice($args, $index, 0, $colorOption);
} else {
$args[] = $colorOption;
}
return $args;
}
/**
* Escapes a string to be used as a shell argument.
*
@@ -109,53 +62,33 @@ class Process
}
/**
* Returns true if the output stream supports colors
* Escapes an array of arguments that make up a shell command
*
* This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
* terminals via named pipes, so we can only check the environment.
* @param array $args Argument list, with the module name first
*
* @param mixed $output A valid CLI output stream
*
* @return bool
* @return string The escaped command line
*/
public static function supportsColor($output)
public static function escapeShellCommand(array $args)
{
if ('Hyper' === getenv('TERM_PROGRAM')) {
return true;
$cmd = self::escape(array_shift($args), true, true);
foreach ($args as $arg) {
$cmd .= ' '.self::escape($arg);
}
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
return (function_exists('sapi_windows_vt100_support')
&& sapi_windows_vt100_support($output))
|| false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM');
}
if (function_exists('stream_isatty')) {
return stream_isatty($output);
}
if (function_exists('posix_isatty')) {
return posix_isatty($output);
}
$stat = fstat($output);
// Check if formatted mode is S_IFCHR
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
return $cmd;
}
/**
* Makes putenv environment changes available in $_SERVER and $_ENV
*
* @param string $name
* @param string|false $value A false value unsets the variable
* @param string|null $value A null value unsets the variable
*
* @return bool Whether the environment variable was set
*/
public static function setEnv($name, $value = false)
public static function setEnv($name, $value = null)
{
$unset = false === $value;
$unset = null === $value;
if (!putenv($unset ? $name : $name.'='.$value)) {
return false;
+9 -3
View File
@@ -33,6 +33,7 @@ class Status
private $envAllowXdebug;
private $loaded;
private $logger;
private $modeOff;
private $time;
/**
@@ -91,7 +92,12 @@ class Status
private function reportCheck($loaded)
{
$this->loaded = $loaded;
list($version, $mode) = explode('|', $loaded);
if ($version) {
$this->loaded = '('.$version.')'.($mode ? ' mode='.$mode : '');
}
$this->modeOff = $mode === 'off';
$this->output('Checking '.$this->envAllowXdebug);
}
@@ -112,7 +118,7 @@ class Status
if ($this->loaded) {
$text = sprintf('No restart (%s)', $this->getEnvAllow());
if (!getenv($this->envAllowXdebug)) {
$text .= ' Allowed by application';
$text .= ' Allowed by '.($this->modeOff ? 'mode' : 'application');
}
$this->output($text);
}
@@ -157,7 +163,7 @@ class Status
*/
private function getLoadedMessage()
{
$loaded = $this->loaded ? sprintf('loaded (%s)', $this->loaded) : 'not loaded';
$loaded = $this->loaded ? sprintf('loaded %s', $this->loaded) : 'not loaded';
return 'The Xdebug extension is '.$loaded;
}
}
+126 -42
View File
@@ -30,13 +30,14 @@ class XdebugHandler
private static $inRestart;
private static $name;
private static $skipped;
private static $xdebugActive;
private $cli;
private $colorOption;
private $debug;
private $envAllowXdebug;
private $envOriginalInis;
private $loaded;
private $mode;
private $persistent;
private $script;
/** @var Status|null */
@@ -50,12 +51,11 @@ class XdebugHandler
* would result in MYAPP_ALLOW_XDEBUG and MYAPP_ORIGINAL_INIS.
*
* @param string $envPrefix Value used in environment variables
* @param string $colorOption Command-line long option to force color output
* @throws \RuntimeException If a parameter is invalid
* @throws \RuntimeException If the parameter is invalid
*/
public function __construct($envPrefix, $colorOption = '')
public function __construct($envPrefix)
{
if (!is_string($envPrefix) || empty($envPrefix) || !is_string($colorOption)) {
if (!is_string($envPrefix) || empty($envPrefix)) {
throw new \RuntimeException('Invalid constructor parameter');
}
@@ -63,13 +63,23 @@ class XdebugHandler
$this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
$this->envOriginalInis = self::$name.self::SUFFIX_INIS;
$this->colorOption = $colorOption;
if (extension_loaded('xdebug')) {
$ext = new \ReflectionExtension('xdebug');
$this->loaded = $ext->getVersion() ?: 'unknown';
$this->loaded = phpversion('xdebug') ?: 'unknown';
if (version_compare($this->loaded, '3.1', '>=')) {
/** @phpstan-ignore-next-line */
$modes = xdebug_info('mode');
$this->mode = empty($modes) ? 'off' : implode(',', $modes);
} elseif (false !== ($mode = ini_get('xdebug.mode'))) {
$this->mode = getenv('XDEBUG_MODE') ?: ($mode ?: 'off');
if (preg_match('/^,+$/', str_replace(' ', '', $this->mode))) {
$this->mode = 'off';
}
}
}
self::$xdebugActive = $this->loaded && $this->mode !== 'off';
if ($this->cli = PHP_SAPI === 'cli') {
$this->debug = getenv(self::DEBUG);
}
@@ -123,23 +133,22 @@ class XdebugHandler
*/
public function check()
{
$this->notify(Status::CHECK, $this->loaded);
$this->notify(Status::CHECK, $this->loaded.'|'.$this->mode);
$envArgs = explode('|', (string) getenv($this->envAllowXdebug));
if (empty($envArgs[0]) && $this->requiresRestart((bool) $this->loaded)) {
if (empty($envArgs[0]) && $this->requiresRestart(self::$xdebugActive)) {
// Restart required
$this->notify(Status::RESTART);
if ($this->prepareRestart()) {
$command = $this->getCommand();
$this->notify(Status::RESTARTING, $command);
$this->restart($command);
}
return;
}
if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
// Restarting, so unset environment variable and use saved values
// Restarted, so unset environment variable and use saved values
$this->notify(Status::RESTARTED);
Process::setEnv($this->envAllowXdebug);
@@ -150,6 +159,8 @@ class XdebugHandler
self::$skipped = $envArgs[1];
}
$this->tryEnableSignals();
// Put restart settings in the environment
$this->setEnvRestartSettings($envArgs);
return;
@@ -204,7 +215,7 @@ class XdebugHandler
if (count($envArgs) !== 6
|| (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
return;
return null;
}
return array(
@@ -228,21 +239,39 @@ class XdebugHandler
}
/**
* Returns true if Xdebug is loaded, or as directed by an extending class
* Returns whether Xdebug is loaded and active
*
* @param bool $isLoaded Whether Xdebug is loaded
* true: if Xdebug is loaded and is running in an active mode.
* false: if Xdebug is not loaded, or it is running with xdebug.mode=off.
*
* @return bool
*/
protected function requiresRestart($isLoaded)
public static function isXdebugActive()
{
return $isLoaded;
return self::$xdebugActive;
}
/**
* Allows an extending class to decide if there should be a restart
*
* The default is to restart if Xdebug is loaded and its mode is not "off".
* Do not typehint for 1.x compatibility.
*
* @param bool $default The default behaviour
*
* @return bool Whether the process should restart
*/
protected function requiresRestart($default)
{
return $default;
}
/**
* Allows an extending class to access the tmpIni
*
* @param string $command
* Do not typehint for 1.x compatibility
*
* @param array $command
*/
protected function restart($command)
{
@@ -252,12 +281,35 @@ class XdebugHandler
/**
* Executes the restarted command then deletes the tmp ini
*
* @param string $command
* @param array $command
*/
private function doRestart($command)
private function doRestart(array $command)
{
passthru($command, $exitCode);
$this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
$this->tryEnableSignals();
$this->notify(Status::RESTARTING, implode(' ', $command));
if (PHP_VERSION_ID >= 70400) {
$cmd = $command;
} else {
$cmd = Process::escapeShellCommand($command);
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
// Outer quotes required on cmd string below PHP 8
$cmd = '"'.$cmd.'"';
}
}
$process = proc_open($cmd, array(), $pipes);
if (is_resource($process)) {
$exitCode = proc_close($process);
}
if (!isset($exitCode)) {
// Unlikely that php or the default shell cannot be invoked
$this->notify(Status::ERROR, 'Unable to restart process');
$exitCode = -1;
} else {
$this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
}
if ($this->debug === '2') {
$this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
@@ -329,7 +381,8 @@ class XdebugHandler
}
$content = '';
$regex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
$sectionRegex = '/^\s*\[(?:PATH|HOST)\s*=/mi';
$xdebugRegex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
foreach ($iniFiles as $file) {
// Check for inaccessible ini files
@@ -337,7 +390,11 @@ class XdebugHandler
$error = 'Unable to read ini: '.$file;
return false;
}
$content .= preg_replace($regex, ';$1', $data).PHP_EOL;
// Check and remove directives after HOST and PATH sections
if (preg_match($sectionRegex, $data, $matches, PREG_OFFSET_CAPTURE)) {
$data = substr($data, 0, $matches[0][1]);
}
$content .= preg_replace($xdebugRegex, ';$1', $data).PHP_EOL;
}
// Merge loaded settings into our ini content, if it is valid
@@ -353,9 +410,9 @@ class XdebugHandler
}
/**
* Returns the restart command line
* Returns the command line arguments for the restart
*
* @return string
* @return array
*/
private function getCommand()
{
@@ -367,18 +424,7 @@ class XdebugHandler
array_push($php, '-n', '-c', $this->tmpIni);
}
if (defined('STDOUT') && Process::supportsColor(STDOUT)) {
$args = Process::addColorOption($args, $this->colorOption);
}
$args = array_merge($php, array($this->script), $args);
$cmd = Process::escape(array_shift($args), true, true);
foreach ($args as $arg) {
$cmd .= ' '.Process::escape($arg);
}
return $cmd;
return array_merge($php, array($this->script), $args);
}
/**
@@ -490,7 +536,7 @@ class XdebugHandler
/**
* Adds restart settings to the environment
*
* @param string $envArgs
* @param string[] $envArgs
*/
private function setEnvRestartSettings($envArgs)
{
@@ -542,11 +588,12 @@ class XdebugHandler
* Returns true if there are no known configuration issues
*
* @param string $info Set by method
* @return bool
*/
private function checkConfiguration(&$info)
{
if (false !== strpos(ini_get('disable_functions'), 'passthru')) {
$info = 'passthru function is disabled';
if (!function_exists('proc_open')) {
$info = 'proc_open function is disabled';
return false;
}
@@ -560,6 +607,43 @@ class XdebugHandler
}
}
$workingDir = getcwd();
if (0 === strpos($workingDir, '\\\\')) {
if (defined('PHP_WINDOWS_VERSION_BUILD') && PHP_VERSION_ID < 70400) {
$info = 'cmd.exe does not support UNC paths: '.$workingDir;
return false;
}
}
return true;
}
/**
* Enables async signals and control interrupts in the restarted process
*
* Available on Unix PHP 7.1+ with the pcntl extension and Windows PHP 7.4+.
*/
private function tryEnableSignals()
{
if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) {
pcntl_async_signals(true);
$message = 'Async signals enabled';
if (!self::$inRestart) {
// Restarting, so ignore SIGINT in parent
pcntl_signal(SIGINT, SIG_IGN);
} elseif (is_int(pcntl_signal_get_handler(SIGINT))) {
// Restarted, no handler set so force default action
pcntl_signal(SIGINT, SIG_DFL);
}
}
if (!self::$inRestart && function_exists('sapi_windows_set_ctrl_handler')) {
// Restarting, so set a handler to ignore CTRL events in the parent.
// This ensures that CTRL+C events will be available in the child
// process without having to enable them there, which is unreliable.
sapi_windows_set_ctrl_handler(function ($evt) {});
}
}
}