1
0
Fork 0

Merge pull request #10334 from Seldaek/phpstan

PHPStan level 8 with baseline
pull/10318/head
Jordi Boggiano 2021-12-07 13:07:01 +01:00 committed by GitHub
commit 62dfd0af23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
104 changed files with 9803 additions and 506 deletions

View File

@ -51,7 +51,7 @@ jobs:
- name: "Install PHPStan" - name: "Install PHPStan"
# Locked to phpunit 7.5 here as newer ones have void return types which break inheritance # Locked to phpunit 7.5 here as newer ones have void return types which break inheritance
run: "bin/composer require --dev phpstan/phpstan:^1.0 phpstan/phpstan-phpunit:^1.0 phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }}" run: "bin/composer require --dev phpstan/phpstan:^1.0 phpstan/phpstan-phpunit:^1.0 phpstan/phpstan-deprecation-rules:^1 phpstan/phpstan-strict-rules:^1 phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }}"
- name: "Run PHPStan" - name: "Run PHPStan"
run: "vendor/bin/phpstan analyse --configuration=phpstan/config.neon" run: "vendor/bin/phpstan analyse --configuration=phpstan/config.neon"

View File

@ -36,7 +36,8 @@
"symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", "symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"react/promise": "^1.2 || ^2.7" "react/promise": "^1.2 || ^2.7",
"composer/pcre": "^1.0"
}, },
"require-dev": { "require-dev": {
"symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0", "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0",
@ -82,7 +83,7 @@
"phpstan-setup": [ "phpstan-setup": [
"@composer config platform --unset", "@composer config platform --unset",
"@composer update", "@composer update",
"@composer require --dev phpstan/phpstan:^1.0 phpstan/phpstan-phpunit:^1.0 phpunit/phpunit:^7.5.20 --with-all-dependencies", "@composer require --dev phpstan/phpstan:^1.0 phpstan/phpstan-phpunit:^1.0 phpstan/phpstan-deprecation-rules:^1 phpstan/phpstan-strict-rules:^1 phpunit/phpunit:^7.5.20 --with-all-dependencies",
"git checkout composer.json composer.lock" "git checkout composer.json composer.lock"
], ],
"phpstan": "@php vendor/bin/phpstan analyse --configuration=phpstan/config.neon" "phpstan": "@php vendor/bin/phpstan analyse --configuration=phpstan/config.neon"

73
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "136c1a25e4f757a3dccb43aa967507f4", "content-hash": "659a81a68363780c2e9fb35a1116808c",
"packages": [ "packages": [
{ {
"name": "composer/ca-bundle", "name": "composer/ca-bundle",
@ -151,6 +151,77 @@
], ],
"time": "2021-04-07T13:37:33+00:00" "time": "2021-04-07T13:37:33+00:00"
}, },
{
"name": "composer/pcre",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "3d322d715c43a1ac36c7fe215fa59336265500f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/3d322d715c43a1ac36c7fe215fa59336265500f2",
"reference": "3d322d715c43a1ac36c7fe215fa59336265500f2",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^1",
"phpstan/phpstan-strict-rules": "^1.1",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Pcre\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
"keywords": [
"PCRE",
"preg",
"regex",
"regular expression"
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/1.0.0"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2021-12-06T15:17:27+00:00"
},
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "3.2.6", "version": "3.2.6",

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,19 @@
includes: includes:
- ../vendor/phpstan/phpstan-phpunit/extension.neon - ../vendor/phpstan/phpstan-phpunit/extension.neon
- ../vendor/phpstan/phpstan-deprecation-rules/rules.neon
- ../vendor/phpstan/phpstan-strict-rules/rules.neon
- ./baseline.neon - ./baseline.neon
parameters: parameters:
level: 6 level: 8
excludePaths: excludePaths:
- '../tests/Composer/Test/Fixtures/*' - '../tests/Composer/Test/Fixtures/*'
- '../tests/Composer/Test/Autoload/Fixtures/*' - '../tests/Composer/Test/Autoload/Fixtures/*'
- '../tests/Composer/Test/Plugin/Fixtures/*' - '../tests/Composer/Test/Plugin/Fixtures/*'
- '../tests/Composer/Test/PolyfillTestCase.php' - '../tests/Composer/Test/PolyfillTestCase.php'
# TODO Remove in 2.3
- '../src/Composer/Console/HtmlOutputFormatter.php'
reportUnmatchedIgnoredErrors: false reportUnmatchedIgnoredErrors: false
@ -43,6 +47,10 @@ parameters:
- '~Method Composer\\Test\\[^:]+::(setUp(BeforeClass)?|tearDown(AfterClass)?|test[^(]+)\(\) has no return type specified.~' - '~Method Composer\\Test\\[^:]+::(setUp(BeforeClass)?|tearDown(AfterClass)?|test[^(]+)\(\) has no return type specified.~'
- '~Method Composer\\Test\\[^:]+::(data\w+|provide\w+|\w+?Provider)\(\) has no return type specified.~' - '~Method Composer\\Test\\[^:]+::(data\w+|provide\w+|\w+?Provider)\(\) has no return type specified.~'
# PHPUnit assertions as instance methods
- '~Dynamic call to static method PHPUnit\\Framework\\Assert::\w+\(\)~'
- '~Dynamic call to static method PHPUnit\\Framework\\TestCase::(once|at|exactly|will|exactly|returnValue|returnCallback|any|atLeastOnce|throwException|onConsecutiveCalls|never|returnValueMap)\(\)~'
bootstrapFiles: bootstrapFiles:
- ../tests/bootstrap.php - ../tests/bootstrap.php

View File

@ -22,6 +22,7 @@ use Composer\IO\IOInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Pcre\Preg;
use Composer\Repository\InstalledRepositoryInterface; use Composer\Repository\InstalledRepositoryInterface;
use Composer\Semver\Constraint\Bound; use Composer\Semver\Constraint\Bound;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
@ -375,7 +376,7 @@ EOF;
if (!$suffix) { if (!$suffix) {
if (!$config->get('autoloader-suffix') && Filesystem::isReadable($vendorPath.'/autoload.php')) { if (!$config->get('autoloader-suffix') && Filesystem::isReadable($vendorPath.'/autoload.php')) {
$content = file_get_contents($vendorPath.'/autoload.php'); $content = file_get_contents($vendorPath.'/autoload.php');
if (preg_match('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) { if (Preg::isMatch('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) {
$suffix = $match[1]; $suffix = $match[1];
} }
} }
@ -447,7 +448,7 @@ EOF;
$pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path).",\n"; $pathCode = $this->getPathCode($filesystem, $basePath, $vendorPath, $path).",\n";
if (!isset($classMap[$class])) { if (!isset($classMap[$class])) {
$classMap[$class] = $pathCode; $classMap[$class] = $pathCode;
} elseif ($this->io && $classMap[$class] !== $pathCode && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class].' '.$path, '\\', '/'))) { } elseif ($this->io && $classMap[$class] !== $pathCode && !Preg::isMatch('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class].' '.$path, '\\', '/'))) {
$ambiguousClasses[$class][] = $path; $ambiguousClasses[$class][] = $path;
} }
} }
@ -475,7 +476,7 @@ EOF;
$dirMatch = preg_quote(strtr(realpath($dir), '\\', '/')); $dirMatch = preg_quote(strtr(realpath($dir), '\\', '/'));
foreach ($excluded as $index => $pattern) { foreach ($excluded as $index => $pattern) {
// extract the constant string prefix of the pattern here, until we reach a non-escaped regex special character // extract the constant string prefix of the pattern here, until we reach a non-escaped regex special character
$pattern = preg_replace('{^(([^.+*?\[^\]$(){}=!<>|:\\\\#-]+|\\\\[.+*?\[^\]$(){}=!<>|:#-])*).*}', '$1', $pattern); $pattern = Preg::replace('{^(([^.+*?\[^\]$(){}=!<>|:\\\\#-]+|\\\\[.+*?\[^\]$(){}=!<>|:#-])*).*}', '$1', $pattern);
// if the pattern is not a subset or superset of $dir, it is unrelated and we skip it // if the pattern is not a subset or superset of $dir, it is unrelated and we skip it
if (0 !== strpos($pattern, $dirMatch) && 0 !== strpos($dirMatch, $pattern)) { if (0 !== strpos($pattern, $dirMatch) && 0 !== strpos($dirMatch, $pattern)) {
unset($excluded[$index]); unset($excluded[$index]);
@ -757,7 +758,7 @@ EOF;
foreach ($packageMap as $item) { foreach ($packageMap as $item) {
$package = $item[0]; $package = $item[0];
foreach (array_merge($package->getReplaces(), $package->getProvides()) as $link) { foreach (array_merge($package->getReplaces(), $package->getProvides()) as $link) {
if (preg_match('{^ext-(.+)$}iD', $link->getTarget(), $match)) { if (Preg::isMatch('{^ext-(.+)$}iD', $link->getTarget(), $match)) {
$extensionProviders[$match[1]][] = $link->getConstraint(); $extensionProviders[$match[1]][] = $link->getConstraint();
} }
} }
@ -782,7 +783,7 @@ EOF;
} }
} }
if ($checkPlatform === true && preg_match('{^ext-(.+)$}iD', $link->getTarget(), $match)) { if ($checkPlatform === true && Preg::isMatch('{^ext-(.+)$}iD', $link->getTarget(), $match)) {
// skip extension checks if they have a valid provider/replacer // skip extension checks if they have a valid provider/replacer
if (isset($extensionProviders[$match[1]])) { if (isset($extensionProviders[$match[1]])) {
foreach ($extensionProviders[$match[1]] as $provided) { foreach ($extensionProviders[$match[1]] as $provided) {
@ -1204,7 +1205,7 @@ HEADER;
$absoluteAppBaseDirPharCode => $appBaseDirPharCode, $absoluteAppBaseDirPharCode => $appBaseDirPharCode,
) )
); );
$value = ltrim(preg_replace('/^ */m', ' $0$0', $value)); $value = ltrim(Preg::replace('/^ */m', ' $0$0', $value));
$file .= sprintf(" public static $%s = %s;\n\n", $prop, $value); $file .= sprintf(" public static $%s = %s;\n\n", $prop, $value);
if ('files' !== $prop) { if ('files' !== $prop) {
@ -1255,7 +1256,7 @@ INITIALIZER;
// remove target-dir from file paths of the root package // remove target-dir from file paths of the root package
if ($package === $rootPackage) { if ($package === $rootPackage) {
$targetDir = str_replace('\\<dirsep\\>', '[\\\\/]', preg_quote(str_replace(array('/', '\\'), '<dirsep>', $package->getTargetDir()))); $targetDir = str_replace('\\<dirsep\\>', '[\\\\/]', preg_quote(str_replace(array('/', '\\'), '<dirsep>', $package->getTargetDir())));
$path = ltrim(preg_replace('{^'.$targetDir.'}', '', ltrim($path, '\\/')), '\\/'); $path = ltrim(Preg::replace('{^'.$targetDir.'}', '', ltrim($path, '\\/')), '\\/');
} else { } else {
// add target-dir from file paths that don't have it // add target-dir from file paths that don't have it
$path = $package->getTargetDir() . '/' . $path; $path = $package->getTargetDir() . '/' . $path;
@ -1264,14 +1265,14 @@ INITIALIZER;
if ($type === 'exclude-from-classmap') { if ($type === 'exclude-from-classmap') {
// first escape user input // first escape user input
$path = preg_replace('{/+}', '/', preg_quote(trim(strtr($path, '\\', '/'), '/'))); $path = Preg::replace('{/+}', '/', preg_quote(trim(strtr($path, '\\', '/'), '/')));
// add support for wildcards * and ** // add support for wildcards * and **
$path = strtr($path, array('\\*\\*' => '.+?', '\\*' => '[^/]+?')); $path = strtr($path, array('\\*\\*' => '.+?', '\\*' => '[^/]+?'));
// add support for up-level relative paths // add support for up-level relative paths
$updir = null; $updir = null;
$path = preg_replace_callback( $path = Preg::replaceCallback(
'{^((?:(?:\\\\\\.){1,2}+/)+)}', '{^((?:(?:\\\\\\.){1,2}+/)+)}',
function ($matches) use (&$updir) { function ($matches) use (&$updir) {
if (isset($matches[1])) { if (isset($matches[1])) {

View File

@ -18,6 +18,7 @@
namespace Composer\Autoload; namespace Composer\Autoload;
use Composer\Pcre\Preg;
use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\Finder;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
@ -92,7 +93,7 @@ class ClassMapGenerator
$filePath = $cwd . '/' . $filePath; $filePath = $cwd . '/' . $filePath;
$filePath = $filesystem->normalizePath($filePath); $filePath = $filesystem->normalizePath($filePath);
} else { } else {
$filePath = preg_replace('{[\\\\/]{2,}}', '/', $filePath); $filePath = Preg::replace('{[\\\\/]{2,}}', '/', $filePath);
} }
$realPath = realpath($filePath); $realPath = realpath($filePath);
@ -104,11 +105,11 @@ class ClassMapGenerator
} }
// check the realpath of the file against the excluded paths as the path might be a symlink and the excluded path is realpath'd so symlink are resolved // check the realpath of the file against the excluded paths as the path might be a symlink and the excluded path is realpath'd so symlink are resolved
if ($excluded && preg_match($excluded, strtr($realPath, '\\', '/'))) { if ($excluded && Preg::isMatch($excluded, strtr($realPath, '\\', '/'))) {
continue; continue;
} }
// check non-realpath of file for directories symlink in project dir // check non-realpath of file for directories symlink in project dir
if ($excluded && preg_match($excluded, strtr($filePath, '\\', '/'))) { if ($excluded && Preg::isMatch($excluded, strtr($filePath, '\\', '/'))) {
continue; continue;
} }
@ -133,7 +134,7 @@ class ClassMapGenerator
if (!isset($map[$class])) { if (!isset($map[$class])) {
$map[$class] = $filePath; $map[$class] = $filePath;
} elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) { } elseif ($io && $map[$class] !== $filePath && !Preg::isMatch('{/(test|fixture|example|stub)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) {
$io->writeError( $io->writeError(
'<warning>Warning: Ambiguous class resolution, "'.$class.'"'. '<warning>Warning: Ambiguous class resolution, "'.$class.'"'.
' was found in both "'.$map[$class].'" and "'.$filePath.'", the first will be used.</warning>' ' was found in both "'.$map[$class].'" and "'.$filePath.'", the first will be used.</warning>'
@ -196,7 +197,7 @@ class ClassMapGenerator
if (empty($validClasses)) { if (empty($validClasses)) {
foreach ($rejectedClasses as $class) { foreach ($rejectedClasses as $class) {
if ($io) { if ($io) {
$io->writeError("<warning>Class $class located in ".preg_replace('{^'.preg_quote(getcwd()).'}', '.', $filePath, 1)." does not comply with $namespaceType autoloading standard. Skipping.</warning>"); $io->writeError("<warning>Class $class located in ".Preg::replace('{^'.preg_quote(getcwd()).'}', '.', $filePath, 1)." does not comply with $namespaceType autoloading standard. Skipping.</warning>");
} }
} }
@ -239,7 +240,7 @@ class ClassMapGenerator
} }
// return early if there is no chance of matching anything in this file // return early if there is no chance of matching anything in this file
preg_match_all('{\b(?:class|interface'.$extraTypes.')\s}i', $contents, $matches); Preg::matchAll('{\b(?:class|interface'.$extraTypes.')\s}i', $contents, $matches);
if (!$matches) { if (!$matches) {
return array(); return array();
} }
@ -248,7 +249,7 @@ class ClassMapGenerator
$contents = $p->clean(); $contents = $p->clean();
unset($p); unset($p);
preg_match_all('{ Preg::matchAll('{
(?: (?:
\b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+) \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
| \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;] | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]

View File

@ -12,6 +12,8 @@
namespace Composer\Autoload; namespace Composer\Autoload;
use Composer\Pcre\Preg;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
* @internal * @internal
@ -125,7 +127,7 @@ class PhpFileCleaner
$type = self::$typeConfig[$char]; $type = self::$typeConfig[$char];
if ( if (
\substr($this->contents, $this->index, $type['length']) === $type['name'] \substr($this->contents, $this->index, $type['length']) === $type['name']
&& \preg_match($type['pattern'], $this->contents, $match, 0, $this->index - 1) && Preg::isMatch($type['pattern'], $this->contents, $match, 0, $this->index - 1)
) { ) {
$clean .= $match[0]; $clean .= $match[0];
@ -269,10 +271,6 @@ class PhpFileCleaner
*/ */
private function match($regex, array &$match = null) private function match($regex, array &$match = null)
{ {
if (\preg_match($regex, $this->contents, $match, 0, $this->index)) { return Preg::isMatch($regex, $this->contents, $match, 0, $this->index);
return true;
}
return false;
} }
} }

View File

@ -13,6 +13,7 @@
namespace Composer; namespace Composer;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Platform; use Composer\Util\Platform;
use Composer\Util\Silencer; use Composer\Util\Silencer;
@ -85,7 +86,7 @@ class Cache
*/ */
public static function isUsable($path) public static function isUsable($path)
{ {
return !preg_match('{(^|[\\\\/])(\$null|nul|NUL|/dev/null)([\\\\/]|$)}', $path); return !Preg::isMatch('{(^|[\\\\/])(\$null|nul|NUL|/dev/null)([\\\\/]|$)}', $path);
} }
/** /**
@ -124,7 +125,7 @@ class Cache
public function read($file) public function read($file)
{ {
if ($this->isEnabled()) { if ($this->isEnabled()) {
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file); $file = Preg::replace('{[^'.$this->allowlist.']}i', '-', $file);
if (file_exists($this->root . $file)) { if (file_exists($this->root . $file)) {
$this->io->writeError('Reading '.$this->root . $file.' from cache', true, IOInterface::DEBUG); $this->io->writeError('Reading '.$this->root . $file.' from cache', true, IOInterface::DEBUG);
@ -144,7 +145,7 @@ class Cache
public function write($file, $contents) public function write($file, $contents)
{ {
if ($this->isEnabled() && !$this->readOnly) { if ($this->isEnabled() && !$this->readOnly) {
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file); $file = Preg::replace('{[^'.$this->allowlist.']}i', '-', $file);
$this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG); $this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG);
@ -153,7 +154,7 @@ class Cache
return file_put_contents($tempFileName, $contents) !== false && rename($tempFileName, $this->root . $file); return file_put_contents($tempFileName, $contents) !== false && rename($tempFileName, $this->root . $file);
} catch (\ErrorException $e) { } catch (\ErrorException $e) {
$this->io->writeError('<warning>Failed to write into cache: '.$e->getMessage().'</warning>', true, IOInterface::DEBUG); $this->io->writeError('<warning>Failed to write into cache: '.$e->getMessage().'</warning>', true, IOInterface::DEBUG);
if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) { if (Preg::isMatch('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) {
// Remove partial file. // Remove partial file.
unlink($tempFileName); unlink($tempFileName);
@ -188,7 +189,7 @@ class Cache
public function copyFrom($file, $source) public function copyFrom($file, $source)
{ {
if ($this->isEnabled() && !$this->readOnly) { if ($this->isEnabled() && !$this->readOnly) {
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file); $file = Preg::replace('{[^'.$this->allowlist.']}i', '-', $file);
$this->filesystem->ensureDirectoryExists(dirname($this->root . $file)); $this->filesystem->ensureDirectoryExists(dirname($this->root . $file));
if (!file_exists($source)) { if (!file_exists($source)) {
@ -214,7 +215,7 @@ class Cache
public function copyTo($file, $target) public function copyTo($file, $target)
{ {
if ($this->isEnabled()) { if ($this->isEnabled()) {
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file); $file = Preg::replace('{[^'.$this->allowlist.']}i', '-', $file);
if (file_exists($this->root . $file)) { if (file_exists($this->root . $file)) {
try { try {
touch($this->root . $file, filemtime($this->root . $file), time()); touch($this->root . $file, filemtime($this->root . $file), time());
@ -262,7 +263,7 @@ class Cache
public function remove($file) public function remove($file)
{ {
if ($this->isEnabled()) { if ($this->isEnabled()) {
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file); $file = Preg::replace('{[^'.$this->allowlist.']}i', '-', $file);
if (file_exists($this->root . $file)) { if (file_exists($this->root . $file)) {
return $this->filesystem->unlink($this->root . $file); return $this->filesystem->unlink($this->root . $file);
} }
@ -329,7 +330,7 @@ class Cache
public function sha1($file) public function sha1($file)
{ {
if ($this->isEnabled()) { if ($this->isEnabled()) {
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file); $file = Preg::replace('{[^'.$this->allowlist.']}i', '-', $file);
if (file_exists($this->root . $file)) { if (file_exists($this->root . $file)) {
return sha1_file($this->root . $file); return sha1_file($this->root . $file);
} }
@ -346,7 +347,7 @@ class Cache
public function sha256($file) public function sha256($file)
{ {
if ($this->isEnabled()) { if ($this->isEnabled()) {
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file); $file = Preg::replace('{[^'.$this->allowlist.']}i', '-', $file);
if (file_exists($this->root . $file)) { if (file_exists($this->root . $file)) {
return hash_file('sha256', $this->root . $file); return hash_file('sha256', $this->root . $file);
} }

View File

@ -12,6 +12,7 @@
namespace Composer\Command; namespace Composer\Command;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Platform; use Composer\Util\Platform;
use Composer\Util\Silencer; use Composer\Util\Silencer;
@ -261,7 +262,7 @@ EOT
$properties = array('name', 'type', 'description', 'homepage', 'version', 'minimum-stability', 'prefer-stable', 'keywords', 'license', 'extra'); $properties = array('name', 'type', 'description', 'homepage', 'version', 'minimum-stability', 'prefer-stable', 'keywords', 'license', 'extra');
$rawData = $this->configFile->read(); $rawData = $this->configFile->read();
$data = $this->config->all(); $data = $this->config->all();
if (preg_match('/^repos?(?:itories)?(?:\.(.+))?/', $settingKey, $matches)) { if (Preg::isMatch('/^repos?(?:itories)?(?:\.(.+))?/', $settingKey, $matches)) {
if (!isset($matches[1]) || $matches[1] === '') { if (!isset($matches[1]) || $matches[1] === '') {
$value = isset($data['repositories']) ? $data['repositories'] : array(); $value = isset($data['repositories']) ? $data['repositories'] : array();
} else { } else {
@ -390,7 +391,7 @@ EOT
'cache-files-ttl' => array('is_numeric', 'intval'), 'cache-files-ttl' => array('is_numeric', 'intval'),
'cache-files-maxsize' => array( 'cache-files-maxsize' => array(
function ($val) { function ($val) {
return preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $val) > 0; return Preg::isMatch('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $val);
}, },
function ($val) { function ($val) {
return $val; return $val;
@ -535,7 +536,7 @@ EOT
return 0; return 0;
} }
// handle preferred-install per-package config // handle preferred-install per-package config
if (preg_match('/^preferred-install\.(.+)/', $settingKey, $matches)) { if (Preg::isMatch('/^preferred-install\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
$this->configSource->removeConfigSetting($settingKey); $this->configSource->removeConfigSetting($settingKey);
@ -626,7 +627,7 @@ EOT
} }
// handle repositories // handle repositories
if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) { if (Preg::isMatch('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
$this->configSource->removeRepository($matches[1]); $this->configSource->removeRepository($matches[1]);
@ -662,7 +663,7 @@ EOT
} }
// handle extra // handle extra
if (preg_match('/^extra\.(.+)/', $settingKey, $matches)) { if (Preg::isMatch('/^extra\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
$this->configSource->removeProperty($settingKey); $this->configSource->removeProperty($settingKey);
@ -689,7 +690,7 @@ EOT
} }
// handle suggest // handle suggest
if (preg_match('/^suggest\.(.+)/', $settingKey, $matches)) { if (Preg::isMatch('/^suggest\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
$this->configSource->removeProperty($settingKey); $this->configSource->removeProperty($settingKey);
@ -709,7 +710,7 @@ EOT
} }
// handle platform // handle platform
if (preg_match('/^platform\.(.+)/', $settingKey, $matches)) { if (Preg::isMatch('/^platform\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
$this->configSource->removeConfigSetting($settingKey); $this->configSource->removeConfigSetting($settingKey);
@ -729,7 +730,7 @@ EOT
} }
// handle auth // handle auth
if (preg_match('/^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|http-basic|bearer)\.(.+)/', $settingKey, $matches)) { if (Preg::isMatch('/^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|http-basic|bearer)\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
$this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]); $this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]);
$this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]); $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
@ -764,7 +765,7 @@ EOT
} }
// handle script // handle script
if (preg_match('/^scripts\.(.+)/', $settingKey, $matches)) { if (Preg::isMatch('/^scripts\.(.+)/', $settingKey, $matches)) {
if ($input->getOption('unset')) { if ($input->getOption('unset')) {
$this->configSource->removeProperty($settingKey); $this->configSource->removeProperty($settingKey);
@ -857,7 +858,7 @@ EOT
$rawVal = isset($rawContents[$key]) ? $rawContents[$key] : null; $rawVal = isset($rawContents[$key]) ? $rawContents[$key] : null;
if (is_array($value) && (!is_numeric(key($value)) || ($key === 'repositories' && null === $k))) { if (is_array($value) && (!is_numeric(key($value)) || ($key === 'repositories' && null === $k))) {
$k .= preg_replace('{^config\.}', '', $key . '.'); $k .= Preg::replace('{^config\.}', '', $key . '.');
$this->listConfiguration($value, $rawVal, $output, $k, $showSource); $this->listConfiguration($value, $rawVal, $output, $k, $showSource);
$k = $origK; $k = $origK;

View File

@ -25,6 +25,7 @@ use Composer\Package\BasePackage;
use Composer\DependencyResolver\Operation\InstallOperation; use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\Package\Version\VersionSelector; use Composer\Package\Version\VersionSelector;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Pcre\Preg;
use Composer\Repository\RepositoryFactory; use Composer\Repository\RepositoryFactory;
use Composer\Repository\CompositeRepository; use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
@ -390,7 +391,7 @@ EOT
if (null === $stability) { if (null === $stability) {
if (null === $packageVersion) { if (null === $packageVersion) {
$stability = 'stable'; $stability = 'stable';
} elseif (preg_match('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $packageVersion, $match)) { } elseif (Preg::isMatch('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $packageVersion, $match)) {
$stability = $match[1]; $stability = $match[1];
} else { } else {
$stability = VersionParser::parseStability($packageVersion); $stability = VersionParser::parseStability($packageVersion);

View File

@ -16,6 +16,7 @@ use Composer\Composer;
use Composer\Factory; use Composer\Factory;
use Composer\Config; use Composer\Config;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Pcre\Preg;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
@ -579,7 +580,7 @@ EOT
ob_start(); ob_start();
phpinfo(INFO_GENERAL); phpinfo(INFO_GENERAL);
$phpinfo = ob_get_clean(); $phpinfo = ob_get_clean();
if (preg_match('{Configure Command(?: *</td><td class="v">| *=> *)(.*?)(?:</td>|$)}m', $phpinfo, $match)) { if (Preg::isMatch('{Configure Command(?: *</td><td class="v">| *=> *)(.*?)(?:</td>|$)}m', $phpinfo, $match)) {
$configure = $match[1]; $configure = $match[1];
if (false !== strpos($configure, '--enable-sigchild')) { if (false !== strpos($configure, '--enable-sigchild')) {

View File

@ -16,6 +16,7 @@ use Composer\Json\JsonFile;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\CompletePackageInterface; use Composer\Package\CompletePackageInterface;
use Composer\Pcre\Preg;
use Composer\Repository\CompositeRepository; use Composer\Repository\CompositeRepository;
use Composer\Semver\Constraint\MatchAllConstraint; use Composer\Semver\Constraint\MatchAllConstraint;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -144,7 +145,7 @@ class FundCommand extends BaseCommand
continue; continue;
} }
$url = $fundingOption['url']; $url = $fundingOption['url'];
if (!empty($fundingOption['type']) && $fundingOption['type'] === 'github' && preg_match('{^https://github.com/([^/]+)$}', $url, $match)) { if (!empty($fundingOption['type']) && $fundingOption['type'] === 'github' && Preg::isMatch('{^https://github.com/([^/]+)$}', $url, $match)) {
$url = 'https://github.com/sponsors/'.$match[1]; $url = 'https://github.com/sponsors/'.$match[1];
} }
$fundings[$vendor][$url][] = $packageName; $fundings[$vendor][$url][] = $packageName;

View File

@ -13,6 +13,7 @@
namespace Composer\Command; namespace Composer\Command;
use Composer\Factory; use Composer\Factory;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Platform; use Composer\Util\Platform;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -71,7 +72,7 @@ EOT
} }
// extract real command name // extract real command name
$tokens = preg_split('{\s+}', $input->__toString()); $tokens = Preg::split('{\s+}', $input->__toString());
$args = array(); $args = array();
foreach ($tokens as $token) { foreach ($tokens as $token) {
if ($token && $token[0] !== '-') { if ($token && $token[0] !== '-') {
@ -112,7 +113,7 @@ EOT
$this->getIO()->writeError('<info>Changed current directory to '.$home.'</info>'); $this->getIO()->writeError('<info>Changed current directory to '.$home.'</info>');
// create new input without "global" command prefix // create new input without "global" command prefix
$input = new StringInput(preg_replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1)); $input = new StringInput(Preg::replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1));
$this->getApplication()->resetComposer(); $this->getApplication()->resetComposer();
return $this->getApplication()->run($input, $output); return $this->getApplication()->run($input, $output);

View File

@ -23,6 +23,7 @@ use Composer\Package\Package;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Package\Version\VersionSelector; use Composer\Package\Version\VersionSelector;
use Composer\Pcre\Preg;
use Composer\Repository\CompositeRepository; use Composer\Repository\CompositeRepository;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryFactory; use Composer\Repository\RepositoryFactory;
@ -104,7 +105,7 @@ EOT
$allowlist = array('name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license', 'autoload'); $allowlist = array('name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license', 'autoload');
$options = array_filter(array_intersect_key($input->getOptions(), array_flip($allowlist))); $options = array_filter(array_intersect_key($input->getOptions(), array_flip($allowlist)));
if (isset($options['name']) && !preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $options['name'])) { if (isset($options['name']) && !Preg::isMatch('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $options['name'])) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
'The package name '.$options['name'].' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+' 'The package name '.$options['name'].' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
); );
@ -283,7 +284,7 @@ EOT
if (!$name = $input->getOption('name')) { if (!$name = $input->getOption('name')) {
$name = basename($cwd); $name = basename($cwd);
$name = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name); $name = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
$name = strtolower($name); $name = strtolower($name);
if (!empty($_SERVER['COMPOSER_DEFAULT_VENDOR'])) { if (!empty($_SERVER['COMPOSER_DEFAULT_VENDOR'])) {
$name = $_SERVER['COMPOSER_DEFAULT_VENDOR'] . '/' . $name; $name = $_SERVER['COMPOSER_DEFAULT_VENDOR'] . '/' . $name;
@ -309,7 +310,7 @@ EOT
return $name; return $name;
} }
if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $value)) { if (!Preg::isMatch('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $value)) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
'The package name '.$value.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+' 'The package name '.$value.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
); );
@ -452,7 +453,7 @@ EOT
$value = $value ?: $autoload; $value = $value ?: $autoload;
if (!preg_match('{^[^/][A-Za-z0-9\-_/]+/$}', $value)) { if (!Preg::isMatch('{^[^/][A-Za-z0-9\-_/]+/$}', $value)) {
throw new \InvalidArgumentException(sprintf( throw new \InvalidArgumentException(sprintf(
'The src folder name "%s" is invalid. Please add a relative path with tailing forward slash. [A-Za-z0-9_-/]+/', 'The src folder name "%s" is invalid. Please add a relative path with tailing forward slash. [A-Za-z0-9_-/]+/',
$value $value
@ -474,7 +475,7 @@ EOT
*/ */
public function parseAuthorString($author) public function parseAuthorString($author)
{ {
if (preg_match('/^(?P<name>[- .,\p{L}\p{N}\p{Mn}\'"()]+) <(?P<email>.+?)>$/u', $author, $match)) { if (Preg::isMatch('/^(?P<name>[- .,\p{L}\p{N}\p{Mn}\'"()]+) <(?P<email>.+?)>$/u', $author, $match)) {
if ($this->isValidEmail($match['email'])) { if ($this->isValidEmail($match['email'])) {
return array( return array(
'name' => trim($match['name']), 'name' => trim($match['name']),
@ -617,7 +618,7 @@ EOT
return $package['name']; return $package['name'];
} }
if (preg_match('{^\s*(?P<name>[\S/]+)(?:\s+(?P<version>\S+))?\s*$}', $selection, $packageMatches)) { if (Preg::isMatch('{^\s*(?P<name>[\S/]+)(?:\s+(?P<version>\S+))?\s*$}', $selection, $packageMatches)) {
if (isset($packageMatches['version'])) { if (isset($packageMatches['version'])) {
// parsing `acme/example ~2.3` // parsing `acme/example ~2.3`
@ -707,7 +708,7 @@ EOT
$namespace = array_map( $namespace = array_map(
function ($part) { function ($part) {
$part = preg_replace('/[^a-z0-9]/i', ' ', $part); $part = Preg::replace('/[^a-z0-9]/i', ' ', $part);
$part = ucwords($part); $part = ucwords($part);
return str_replace(' ', '', $part); return str_replace(' ', '', $part);
@ -741,9 +742,9 @@ EOT
if ($cmd->isSuccessful()) { if ($cmd->isSuccessful()) {
$this->gitConfig = array(); $this->gitConfig = array();
preg_match_all('{^([^=]+)=(.*)$}m', $cmd->getOutput(), $matches, PREG_SET_ORDER); Preg::matchAll('{^([^=]+)=(.*)$}m', $cmd->getOutput(), $matches);
foreach ($matches as $match) { foreach ($matches[1] as $key => $match) {
$this->gitConfig[$match[1]] = $match[2]; $this->gitConfig[$match] = $matches[2][$key];
} }
return $this->gitConfig; return $this->gitConfig;
@ -778,7 +779,7 @@ EOT
$lines = file($ignoreFile, FILE_IGNORE_NEW_LINES); $lines = file($ignoreFile, FILE_IGNORE_NEW_LINES);
foreach ($lines as $line) { foreach ($lines as $line) {
if (preg_match($pattern, $line)) { if (Preg::isMatch($pattern, $line)) {
return true; return true;
} }
} }

View File

@ -18,6 +18,7 @@ use Composer\DependencyResolver\Transaction;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory; use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Pcre\Preg;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -82,7 +83,7 @@ EOT
$patternRegexp = BasePackage::packageNameToRegexp($pattern); $patternRegexp = BasePackage::packageNameToRegexp($pattern);
$matched = false; $matched = false;
foreach ($localRepo->getCanonicalPackages() as $package) { foreach ($localRepo->getCanonicalPackages() as $package) {
if (preg_match($patternRegexp, $package->getName())) { if (Preg::isMatch($patternRegexp, $package->getName())) {
$matched = true; $matched = true;
$packagesToReinstall[] = $package; $packagesToReinstall[] = $package;
$packageNamesToReinstall[] = $package->getName(); $packageNamesToReinstall[] = $package->getName();

View File

@ -16,6 +16,7 @@ use Composer\Config\JsonConfigSource;
use Composer\DependencyResolver\Request; use Composer\DependencyResolver\Request;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory; use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Installer; use Composer\Installer;
use Composer\Pcre\Preg;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
@ -178,7 +179,7 @@ EOT
} }
} }
} }
} elseif (isset($composer[$type]) && $matches = preg_grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$type]))) { } elseif (isset($composer[$type]) && $matches = Preg::grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$type]))) {
foreach ($matches as $matchedPackage) { foreach ($matches as $matchedPackage) {
if ($dryRun) { if ($dryRun) {
$toRemove[$type][] = $matchedPackage; $toRemove[$type][] = $matchedPackage;
@ -186,7 +187,7 @@ EOT
$json->removeLink($type, $matchedPackage); $json->removeLink($type, $matchedPackage);
} }
} }
} elseif (isset($composer[$altType]) && $matches = preg_grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$altType]))) { } elseif (isset($composer[$altType]) && $matches = Preg::grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$altType]))) {
foreach ($matches as $matchedPackage) { foreach ($matches as $matchedPackage) {
$io->writeError('<warning>' . $matchedPackage . ' could not be found in ' . $type . ' but it is present in ' . $altType . '</warning>'); $io->writeError('<warning>' . $matchedPackage . ' could not be found in ' . $type . ' but it is present in ' . $altType . '</warning>');
if ($io->isInteractive()) { if ($io->isInteractive()) {

View File

@ -15,6 +15,7 @@ namespace Composer\Command;
use Composer\Composer; use Composer\Composer;
use Composer\Factory; use Composer\Factory;
use Composer\Config; use Composer\Config;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Platform; use Composer\Util\Platform;
use Composer\SelfUpdate\Keys; use Composer\SelfUpdate\Keys;
@ -157,9 +158,9 @@ EOT
} }
$latestVersion = $latest['version']; $latestVersion = $latest['version'];
$updateVersion = $input->getArgument('version') ?: $latestVersion; $updateVersion = $input->getArgument('version') ?: $latestVersion;
$currentMajorVersion = preg_replace('{^(\d+).*}', '$1', Composer::getVersion()); $currentMajorVersion = Preg::replace('{^(\d+).*}', '$1', Composer::getVersion());
$updateMajorVersion = preg_replace('{^(\d+).*}', '$1', $updateVersion); $updateMajorVersion = Preg::replace('{^(\d+).*}', '$1', $updateVersion);
$previewMajorVersion = preg_replace('{^(\d+).*}', '$1', $latestPreview['version']); $previewMajorVersion = Preg::replace('{^(\d+).*}', '$1', $latestPreview['version']);
if ($versionsUtil->getChannel() === 'stable' && !$input->getArgument('version')) { if ($versionsUtil->getChannel() === 'stable' && !$input->getArgument('version')) {
// if requesting stable channel and no specific version, avoid automatically upgrading to the next major // if requesting stable channel and no specific version, avoid automatically upgrading to the next major
@ -185,7 +186,7 @@ EOT
$io->writeError('<warning>Warning: You forced the install of '.$latestVersion.' via --'.$requestedChannel.', but '.$latestStable['version'].' is the latest stable version. Updating to it via composer self-update --stable is recommended.</warning>'); $io->writeError('<warning>Warning: You forced the install of '.$latestVersion.' via --'.$requestedChannel.', but '.$latestStable['version'].' is the latest stable version. Updating to it via composer self-update --stable is recommended.</warning>');
} }
if (preg_match('{^[0-9a-f]{40}$}', $updateVersion) && $updateVersion !== $latestVersion) { if (Preg::isMatch('{^[0-9a-f]{40}$}', $updateVersion) && $updateVersion !== $latestVersion) {
$io->writeError('<error>You can not update to a specific SHA-1 as those phars are not available for download</error>'); $io->writeError('<error>You can not update to a specific SHA-1 as those phars are not available for download</error>');
return 1; return 1;
@ -218,11 +219,11 @@ EOT
'%s/%s-%s%s', '%s/%s-%s%s',
$rollbackDir, $rollbackDir,
strtr(Composer::RELEASE_DATE, ' :', '_-'), strtr(Composer::RELEASE_DATE, ' :', '_-'),
preg_replace('{^([0-9a-f]{7})[0-9a-f]{33}$}', '$1', Composer::VERSION), Preg::replace('{^([0-9a-f]{7})[0-9a-f]{33}$}', '$1', Composer::VERSION),
self::OLD_INSTALL_EXT self::OLD_INSTALL_EXT
); );
$updatingToTag = !preg_match('{^[0-9a-f]{40}$}', $updateVersion); $updatingToTag = !Preg::isMatch('{^[0-9a-f]{40}$}', $updateVersion);
$io->write(sprintf("Upgrading to version <info>%s</info> (%s channel).", $updateVersion, $channelString)); $io->write(sprintf("Upgrading to version <info>%s</info> (%s channel).", $updateVersion, $channelString));
$remoteFilename = $baseUrl . ($updatingToTag ? "/download/{$updateVersion}/composer.phar" : '/composer.phar'); $remoteFilename = $baseUrl . ($updatingToTag ? "/download/{$updateVersion}/composer.phar" : '/composer.phar');
@ -351,7 +352,7 @@ TAGSPUBKEY
$io->write('Open <info>https://composer.github.io/pubkeys.html</info> to find the latest keys'); $io->write('Open <info>https://composer.github.io/pubkeys.html</info> to find the latest keys');
$validator = function ($value) { $validator = function ($value) {
if (!preg_match('{^-----BEGIN PUBLIC KEY-----$}', trim($value))) { if (!Preg::isMatch('{^-----BEGIN PUBLIC KEY-----$}', trim($value))) {
throw new \UnexpectedValueException('Invalid input'); throw new \UnexpectedValueException('Invalid input');
} }
@ -359,7 +360,7 @@ TAGSPUBKEY
}; };
$devKey = ''; $devKey = '';
while (!preg_match('{(-----BEGIN PUBLIC KEY-----.+?-----END PUBLIC KEY-----)}s', $devKey, $match)) { while (!Preg::isMatch('{(-----BEGIN PUBLIC KEY-----.+?-----END PUBLIC KEY-----)}s', $devKey, $match)) {
$devKey = $io->askAndValidate('Enter Dev / Snapshot Public Key (including lines with -----): ', $validator); $devKey = $io->askAndValidate('Enter Dev / Snapshot Public Key (including lines with -----): ', $validator);
while ($line = $io->ask('')) { while ($line = $io->ask('')) {
$devKey .= trim($line)."\n"; $devKey .= trim($line)."\n";
@ -372,7 +373,7 @@ TAGSPUBKEY
$io->write('Stored key with fingerprint: ' . Keys::fingerprint($keyPath)); $io->write('Stored key with fingerprint: ' . Keys::fingerprint($keyPath));
$tagsKey = ''; $tagsKey = '';
while (!preg_match('{(-----BEGIN PUBLIC KEY-----.+?-----END PUBLIC KEY-----)}s', $tagsKey, $match)) { while (!Preg::isMatch('{(-----BEGIN PUBLIC KEY-----.+?-----END PUBLIC KEY-----)}s', $tagsKey, $match)) {
$tagsKey = $io->askAndValidate('Enter Tags Public Key (including lines with -----): ', $validator); $tagsKey = $io->askAndValidate('Enter Tags Public Key (including lines with -----): ', $validator);
while ($line = $io->ask('')) { while ($line = $io->ask('')) {
$tagsKey .= trim($line)."\n"; $tagsKey .= trim($line)."\n";

View File

@ -24,6 +24,7 @@ use Composer\Package\Package;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Package\Version\VersionSelector; use Composer\Package\Version\VersionSelector;
use Composer\Pcre\Preg;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
use Composer\Repository\InstalledArrayRepository; use Composer\Repository\InstalledArrayRepository;
@ -364,7 +365,7 @@ EOT
while ($package instanceof AliasPackage) { while ($package instanceof AliasPackage) {
$package = $package->getAliasOf(); $package = $package->getAliasOf();
} }
if (!$packageFilterRegex || preg_match($packageFilterRegex, $package->getName())) { if (!$packageFilterRegex || Preg::isMatch($packageFilterRegex, $package->getName())) {
if (!$packageListFilter || in_array($package->getName(), $packageListFilter, true)) { if (!$packageListFilter || in_array($package->getName(), $packageListFilter, true)) {
$packages[$type][$package->getName()] = $package; $packages[$type][$package->getName()] = $package;
} }

View File

@ -18,6 +18,7 @@ use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\Installer; use Composer\Installer;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\Loader\RootPackageLoader; use Composer\Package\Loader\RootPackageLoader;
use Composer\Pcre\Preg;
use Composer\Plugin\CommandEvent; use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
@ -136,7 +137,7 @@ EOT
// extract --with shorthands from the allowlist // extract --with shorthands from the allowlist
if ($packages) { if ($packages) {
$allowlistPackagesWithRequirements = array_filter($packages, function ($pkg) { $allowlistPackagesWithRequirements = array_filter($packages, function ($pkg) {
return preg_match('{\S+[ =:]\S+}', $pkg) > 0; return Preg::isMatch('{\S+[ =:]\S+}', $pkg);
}); });
foreach ($this->formatRequirements($allowlistPackagesWithRequirements) as $package => $constraint) { foreach ($this->formatRequirements($allowlistPackagesWithRequirements) as $package => $constraint) {
$reqs[$package] = $constraint; $reqs[$package] = $constraint;
@ -144,7 +145,7 @@ EOT
// replace the foo/bar:req by foo/bar in the allowlist // replace the foo/bar:req by foo/bar in the allowlist
foreach ($allowlistPackagesWithRequirements as $package) { foreach ($allowlistPackagesWithRequirements as $package) {
$packageName = preg_replace('{^([^ =:]+)[ =:].*$}', '$1', $package); $packageName = Preg::replace('{^([^ =:]+)[ =:].*$}', '$1', $package);
$index = array_search($package, $packages); $index = array_search($package, $packages);
$packages[$index] = $packageName; $packages[$index] = $packageName;
} }

View File

@ -14,6 +14,7 @@ namespace Composer;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\CaBundle\CaBundle; use Composer\CaBundle\CaBundle;
use Composer\Pcre\Preg;
use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\Finder;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
use Seld\PharUtils\Timestamps; use Seld\PharUtils\Timestamps;
@ -161,11 +162,11 @@ class Compiler
foreach ($finder as $file) { foreach ($finder as $file) {
if (in_array(realpath($file), $extraFiles, true)) { if (in_array(realpath($file), $extraFiles, true)) {
unset($extraFiles[array_search(realpath($file), $extraFiles, true)]); unset($extraFiles[array_search(realpath($file), $extraFiles, true)]);
} elseif (!preg_match('{([/\\\\]LICENSE|\.php)$}', $file)) { } elseif (!Preg::isMatch('{([/\\\\]LICENSE|\.php)$}', $file)) {
$unexpectedFiles[] = (string) $file; $unexpectedFiles[] = (string) $file;
} }
if (preg_match('{\.php[\d.]*$}', $file)) { if (Preg::isMatch('{\.php[\d.]*$}', $file)) {
$this->addFile($phar, $file); $this->addFile($phar, $file);
} else { } else {
$this->addFile($phar, $file, false); $this->addFile($phar, $file, false);
@ -241,7 +242,7 @@ class Compiler
'@release_date@' => $this->versionDate->format('Y-m-d H:i:s'), '@release_date@' => $this->versionDate->format('Y-m-d H:i:s'),
) )
); );
$content = preg_replace('{SOURCE_VERSION = \'[^\']+\';}', 'SOURCE_VERSION = \'\';', $content); $content = Preg::replace('{SOURCE_VERSION = \'[^\']+\';}', 'SOURCE_VERSION = \'\';', $content);
} }
$phar->addFromString($path, $content); $phar->addFromString($path, $content);
@ -253,7 +254,7 @@ class Compiler
private function addComposerBin(\Phar $phar) private function addComposerBin(\Phar $phar)
{ {
$content = file_get_contents(__DIR__.'/../../bin/composer'); $content = file_get_contents(__DIR__.'/../../bin/composer');
$content = preg_replace('{^#!/usr/bin/env php\s*}', '', $content); $content = Preg::replace('{^#!/usr/bin/env php\s*}', '', $content);
$phar->addFromString('bin/composer', $content); $phar->addFromString('bin/composer', $content);
} }
@ -277,11 +278,11 @@ class Compiler
$output .= str_repeat("\n", substr_count($token[1], "\n")); $output .= str_repeat("\n", substr_count($token[1], "\n"));
} elseif (T_WHITESPACE === $token[0]) { } elseif (T_WHITESPACE === $token[0]) {
// reduce wide spaces // reduce wide spaces
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]); $whitespace = Preg::replace('{[ \t]+}', ' ', $token[1]);
// normalize newlines to \n // normalize newlines to \n
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace); $whitespace = Preg::replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
// trim leading spaces // trim leading spaces
$whitespace = preg_replace('{\n +}', "\n", $whitespace); $whitespace = Preg::replace('{\n +}', "\n", $whitespace);
$output .= $whitespace; $output .= $whitespace;
} else { } else {
$output .= $token[1]; $output .= $token[1];
@ -329,7 +330,7 @@ Phar::mapPhar('composer.phar');
EOF; EOF;
// add warning once the phar is older than 60 days // add warning once the phar is older than 60 days
if (preg_match('{^[a-f0-9]+$}', $this->version)) { if (Preg::isMatch('{^[a-f0-9]+$}', $this->version)) {
$warningTime = ((int) $this->versionDate->format('U')) + 60 * 86400; $warningTime = ((int) $this->versionDate->format('U')) + 60 * 86400;
$stub .= "define('COMPOSER_DEV_WARNING_TIME', $warningTime);\n"; $stub .= "define('COMPOSER_DEV_WARNING_TIME', $warningTime);\n";
} }

View File

@ -14,6 +14,7 @@ namespace Composer;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Package\Locker; use Composer\Package\Locker;
use Composer\Pcre\Preg;
use Composer\Util\Loop; use Composer\Util\Loop;
use Composer\Repository\RepositoryManager; use Composer\Repository\RepositoryManager;
use Composer\Installer\InstallationManager; use Composer\Installer\InstallationManager;
@ -78,7 +79,7 @@ class Composer
} }
// we have a branch alias and version is a commit id, this must be a snapshot build // we have a branch alias and version is a commit id, this must be a snapshot build
if (self::BRANCH_ALIAS_VERSION !== '' && preg_match('{^[a-f0-9]{40}$}', self::VERSION)) { if (self::BRANCH_ALIAS_VERSION !== '' && Preg::isMatch('{^[a-f0-9]{40}$}', self::VERSION)) {
return self::BRANCH_ALIAS_VERSION.'+'.self::VERSION; return self::BRANCH_ALIAS_VERSION.'+'.self::VERSION;
} }

View File

@ -15,6 +15,7 @@ namespace Composer;
use Composer\Config\ConfigSourceInterface; use Composer\Config\ConfigSourceInterface;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Composer\Util\Platform; use Composer\Util\Platform;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
@ -225,7 +226,7 @@ class Config
} }
// auto-deactivate the default packagist.org repo if it gets redefined // auto-deactivate the default packagist.org repo if it gets redefined
if (isset($repository['type'], $repository['url']) && $repository['type'] === 'composer' && preg_match('{^https?://(?:[a-z0-9-.]+\.)?packagist.org(/|$)}', $repository['url'])) { if (isset($repository['type'], $repository['url']) && $repository['type'] === 'composer' && Preg::isMatch('{^https?://(?:[a-z0-9-.]+\.)?packagist.org(/|$)}', $repository['url'])) {
$this->disableRepoByName('packagist.org'); $this->disableRepoByName('packagist.org');
} }
@ -328,7 +329,7 @@ class Config
// numbers with kb/mb/gb support, without env var support // numbers with kb/mb/gb support, without env var support
case 'cache-files-maxsize': case 'cache-files-maxsize':
if (!preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $this->config[$key], $matches)) { if (!Preg::isMatch('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $this->config[$key], $matches)) {
throw new \RuntimeException( throw new \RuntimeException(
"Could not parse the value of '$key': {$this->config[$key]}" "Could not parse the value of '$key': {$this->config[$key]}"
); );
@ -361,7 +362,7 @@ class Config
return (int) $this->config['cache-ttl']; return (int) $this->config['cache-ttl'];
case 'home': case 'home':
$val = preg_replace('#^(\$HOME|~)(/|$)#', rtrim(Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE'), '/\\') . '/', $this->config[$key]); $val = Preg::replace('#^(\$HOME|~)(/|$)#', rtrim(Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE'), '/\\') . '/', $this->config[$key]);
return rtrim($this->process($val, $flags), '/\\'); return rtrim($this->process($val, $flags), '/\\');
@ -507,7 +508,7 @@ class Config
return $value; return $value;
} }
return preg_replace_callback('#\{\$(.+)\}#', function ($match) use ($config, $flags) { return Preg::replaceCallback('#\{\$(.+)\}#', function ($match) use ($config, $flags) {
return $config->get($match[1], $flags); return $config->get($match[1], $flags);
}, $value); }, $value);
} }
@ -522,7 +523,7 @@ class Config
*/ */
private function realpath($path) private function realpath($path)
{ {
if (preg_match('{^(?:/|[a-z]:|[a-z0-9.]+://)}i', $path)) { if (Preg::isMatch('{^(?:/|[a-z]:|[a-z0-9.]+://)}i', $path)) {
return $path; return $path;
} }

View File

@ -15,6 +15,7 @@ namespace Composer\Config;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Json\JsonManipulator; use Composer\Json\JsonManipulator;
use Composer\Json\JsonValidationException; use Composer\Json\JsonValidationException;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Silencer; use Composer\Util\Silencer;
@ -102,7 +103,7 @@ class JsonConfigSource implements ConfigSourceInterface
{ {
$authConfig = $this->authConfig; $authConfig = $this->authConfig;
$this->manipulateJson('addConfigSetting', $name, $value, function (&$config, $key, $val) use ($authConfig) { $this->manipulateJson('addConfigSetting', $name, $value, function (&$config, $key, $val) use ($authConfig) {
if (preg_match('{^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|bearer|http-basic|platform)\.}', $key)) { if (Preg::isMatch('{^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|bearer|http-basic|platform)\.}', $key)) {
list($key, $host) = explode('.', $key, 2); list($key, $host) = explode('.', $key, 2);
if ($authConfig) { if ($authConfig) {
$config[$key][$host] = $val; $config[$key][$host] = $val;
@ -122,7 +123,7 @@ class JsonConfigSource implements ConfigSourceInterface
{ {
$authConfig = $this->authConfig; $authConfig = $this->authConfig;
$this->manipulateJson('removeConfigSetting', $name, function (&$config, $key) use ($authConfig) { $this->manipulateJson('removeConfigSetting', $name, function (&$config, $key) use ($authConfig) {
if (preg_match('{^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|bearer|http-basic|platform)\.}', $key)) { if (Preg::isMatch('{^(bitbucket-oauth|github-oauth|gitlab-oauth|gitlab-token|bearer|http-basic|platform)\.}', $key)) {
list($key, $host) = explode('.', $key, 2); list($key, $host) = explode('.', $key, 2);
if ($authConfig) { if ($authConfig) {
unset($config[$key][$host]); unset($config[$key][$host]);

View File

@ -12,6 +12,7 @@
namespace Composer\Console; namespace Composer\Console;
use Composer\Pcre\Preg;
use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Formatter\OutputFormatterStyle;
@ -70,6 +71,7 @@ class HtmlOutputFormatter extends OutputFormatter
$clearEscapeCodes = '(?:39|49|0|22|24|25|27|28)'; $clearEscapeCodes = '(?:39|49|0|22|24|25|27|28)';
// TODO in 2.3 replace with Closure::fromCallable and then use Preg::replaceCallback
return preg_replace_callback("{\033\[([0-9;]+)m(.*?)\033\[(?:".$clearEscapeCodes.";)*?".$clearEscapeCodes."m}s", array($this, 'formatHtml'), $formatted); return preg_replace_callback("{\033\[([0-9;]+)m(.*?)\033\[(?:".$clearEscapeCodes.";)*?".$clearEscapeCodes."m}s", array($this, 'formatHtml'), $formatted);
} }

View File

@ -20,6 +20,7 @@ use Composer\Package\CompleteAliasPackage;
use Composer\Package\CompletePackage; use Composer\Package\CompletePackage;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\Version\StabilityFilter; use Composer\Package\Version\StabilityFilter;
use Composer\Pcre\Preg;
use Composer\Plugin\PluginEvents; use Composer\Plugin\PluginEvents;
use Composer\Plugin\PrePoolCreateEvent; use Composer\Plugin\PrePoolCreateEvent;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
@ -552,7 +553,7 @@ class PoolBuilder
{ {
foreach ($this->updateAllowList as $pattern => $void) { foreach ($this->updateAllowList as $pattern => $void) {
$patternRegexp = BasePackage::packageNameToRegexp($pattern); $patternRegexp = BasePackage::packageNameToRegexp($pattern);
if (preg_match($patternRegexp, $package->getName())) { if (Preg::isMatch($patternRegexp, $package->getName())) {
return true; return true;
} }
} }
@ -569,13 +570,13 @@ class PoolBuilder
$patternRegexp = BasePackage::packageNameToRegexp($pattern); $patternRegexp = BasePackage::packageNameToRegexp($pattern);
// update pattern matches a locked package? => all good // update pattern matches a locked package? => all good
foreach ($request->getLockedRepository()->getPackages() as $package) { foreach ($request->getLockedRepository()->getPackages() as $package) {
if (preg_match($patternRegexp, $package->getName())) { if (Preg::isMatch($patternRegexp, $package->getName())) {
continue 2; continue 2;
} }
} }
// update pattern matches a root require? => all good, probably a new package // update pattern matches a root require? => all good, probably a new package
foreach ($request->getRequires() as $packageName => $constraint) { foreach ($request->getRequires() as $packageName => $constraint) {
if (preg_match($patternRegexp, $packageName)) { if (Preg::isMatch($patternRegexp, $packageName)) {
continue 2; continue 2;
} }
} }

View File

@ -17,6 +17,7 @@ use Composer\Package\AliasPackage;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Pcre\Preg;
use Composer\Repository\RepositorySet; use Composer\Repository\RepositorySet;
use Composer\Repository\LockArrayRepository; use Composer\Repository\LockArrayRepository;
use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\Constraint;
@ -123,8 +124,8 @@ class Problem
$deduplicatableRuleTypes = array(Rule::RULE_PACKAGE_REQUIRES, Rule::RULE_PACKAGE_CONFLICT); $deduplicatableRuleTypes = array(Rule::RULE_PACKAGE_REQUIRES, Rule::RULE_PACKAGE_CONFLICT);
foreach ($rules as $rule) { foreach ($rules as $rule) {
$message = $rule->getPrettyString($repositorySet, $request, $pool, $isVerbose, $installedMap, $learnedPool); $message = $rule->getPrettyString($repositorySet, $request, $pool, $isVerbose, $installedMap, $learnedPool);
if (in_array($rule->getReason(), $deduplicatableRuleTypes, true) && preg_match('{^(?P<package>\S+) (?P<version>\S+) (?P<type>requires|conflicts)}', $message, $m)) { if (in_array($rule->getReason(), $deduplicatableRuleTypes, true) && Preg::isMatch('{^(?P<package>\S+) (?P<version>\S+) (?P<type>requires|conflicts)}', $message, $m)) {
$template = preg_replace('{^\S+ \S+ }', '%s%s ', $message); $template = Preg::replace('{^\S+ \S+ }', '%s%s ', $message);
$messages[] = $template; $messages[] = $template;
$templates[$template][$m[1]][$parser->normalize($m[2])] = $m[2]; $templates[$template][$m[1]][$parser->normalize($m[2])] = $m[2];
$sourcePackage = $rule->getSourcePackage($pool); $sourcePackage = $rule->getSourcePackage($pool);
@ -146,7 +147,7 @@ class Problem
} }
if (count($versions) > 1) { if (count($versions) > 1) {
// remove the s from requires/conflicts to correct grammar // remove the s from requires/conflicts to correct grammar
$message = preg_replace('{^(%s%s (?:require|conflict))s}', '$1', $message); $message = Preg::replace('{^(%s%s (?:require|conflict))s}', '$1', $message);
$result[] = sprintf($message, $package, '['.implode(', ', $versions).']'); $result[] = sprintf($message, $package, '['.implode(', ', $versions).']');
} else { } else {
$result[] = sprintf($message, $package, ' '.reset($versions)); $result[] = sprintf($message, $package, ' '.reset($versions));
@ -350,8 +351,8 @@ class Problem
return array("- Root composer.json requires $packageName".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose, $pool, $constraint).' but '.(self::hasMultipleNames($packages) ? 'these do' : 'it does').' not match the constraint.' . $suffix); return array("- Root composer.json requires $packageName".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose, $pool, $constraint).' but '.(self::hasMultipleNames($packages) ? 'these do' : 'it does').' not match the constraint.' . $suffix);
} }
if (!preg_match('{^[A-Za-z0-9_./-]+$}', $packageName)) { if (!Preg::isMatch('{^[A-Za-z0-9_./-]+$}', $packageName)) {
$illegalChars = preg_replace('{[A-Za-z0-9_./-]+}', '', $packageName); $illegalChars = Preg::replace('{[A-Za-z0-9_./-]+}', '', $packageName);
return array("- Root composer.json requires $packageName, it ", 'could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.'); return array("- Root composer.json requires $packageName, it ", 'could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.');
} }
@ -461,7 +462,7 @@ class Problem
if (0 === stripos($version, 'dev-')) { if (0 === stripos($version, 'dev-')) {
$byMajor['dev'][] = $pretty; $byMajor['dev'][] = $pretty;
} else { } else {
$byMajor[preg_replace('{^(\d+)\..*}', '$1', $version)][] = $pretty; $byMajor[Preg::replace('{^(\d+)\..*}', '$1', $version)][] = $pretty;
} }
} }
foreach ($byMajor as $majorVersion => $versionsForMajor) { foreach ($byMajor as $majorVersion => $versionsForMajor) {

View File

@ -14,6 +14,7 @@ namespace Composer\Downloader;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Exception\IrrecoverableDownloadException; use Composer\Exception\IrrecoverableDownloadException;
use React\Promise\PromiseInterface; use React\Promise\PromiseInterface;
@ -392,7 +393,7 @@ class DownloadManager
{ {
foreach ($this->packagePreferences as $pattern => $preference) { foreach ($this->packagePreferences as $pattern => $preference) {
$pattern = '{^'.str_replace('\\*', '.*', preg_quote($pattern)).'$}i'; $pattern = '{^'.str_replace('\\*', '.*', preg_quote($pattern)).'$}i';
if (preg_match($pattern, $package->getName())) { if (Preg::isMatch($pattern, $package->getName())) {
if ('dist' === $preference || (!$package->isDev() && 'auto' === $preference)) { if ('dist' === $preference || (!$package->isDev() && 'auto' === $preference)) {
return 'dist'; return 'dist';
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Downloader; namespace Composer\Downloader;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Pcre\Preg;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
/** /**
@ -108,7 +109,7 @@ class FossilDownloader extends VcsDownloader
$match = '/\d\d:\d\d:\d\d\s+\[' . $toReference . '\]/'; $match = '/\d\d:\d\d:\d\d\s+\[' . $toReference . '\]/';
foreach ($this->process->splitLines($output) as $line) { foreach ($this->process->splitLines($output) as $line) {
if (preg_match($match, $line)) { if (Preg::isMatch($match, $line)) {
break; break;
} }
$log .= $line; $log .= $line;

View File

@ -15,6 +15,7 @@ namespace Composer\Downloader;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Git as GitUtil; use Composer\Util\Git as GitUtil;
use Composer\Util\Url; use Composer\Util\Url;
@ -61,7 +62,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
{ {
GitUtil::cleanEnv(); GitUtil::cleanEnv();
$cachePath = $this->config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $url).'/'; $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', $url).'/';
$gitVersion = GitUtil::getVersion($this->process); $gitVersion = GitUtil::getVersion($this->process);
// --dissociate option is only available since git 2.3.0-rc0 // --dissociate option is only available since git 2.3.0-rc0
@ -86,7 +87,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
{ {
GitUtil::cleanEnv(); GitUtil::cleanEnv();
$path = $this->normalizePath($path); $path = $this->normalizePath($path);
$cachePath = $this->config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $url).'/'; $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', $url).'/';
$ref = $package->getSourceReference(); $ref = $package->getSourceReference();
$flag = Platform::isWindows() ? '/D ' : ''; $flag = Platform::isWindows() ? '/D ' : '';
@ -120,7 +121,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
ProcessExecutor::escape($url), ProcessExecutor::escape($url),
ProcessExecutor::escape($path), ProcessExecutor::escape($path),
ProcessExecutor::escape($cachePath), ProcessExecutor::escape($cachePath),
ProcessExecutor::escape(preg_replace('{://([^@]+?):(.+?)@}', '://', $url)), ProcessExecutor::escape(Preg::replace('{://([^@]+?):(.+?)@}', '://', $url)),
), ),
$command $command
); );
@ -155,7 +156,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
throw new \RuntimeException('The .git directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); throw new \RuntimeException('The .git directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information');
} }
$cachePath = $this->config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $url).'/'; $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', $url).'/';
$ref = $target->getSourceReference(); $ref = $target->getSourceReference();
if (!empty($this->cachedPackages[$target->getId()][$ref])) { if (!empty($this->cachedPackages[$target->getId()][$ref])) {
@ -178,7 +179,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
ProcessExecutor::escape($url), ProcessExecutor::escape($url),
ProcessExecutor::escape($ref.'^{commit}'), ProcessExecutor::escape($ref.'^{commit}'),
ProcessExecutor::escape($cachePath), ProcessExecutor::escape($cachePath),
ProcessExecutor::escape(preg_replace('{://([^@]+?):(.+?)@}', '://', $url)), ProcessExecutor::escape(Preg::replace('{://([^@]+?):(.+?)@}', '://', $url)),
), ),
$command $command
); );
@ -195,8 +196,8 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
$updateOriginUrl = false; $updateOriginUrl = false;
if ( if (
0 === $this->process->execute('git remote -v', $output, $path) 0 === $this->process->execute('git remote -v', $output, $path)
&& preg_match('{^origin\s+(?P<url>\S+)}m', $output, $originMatch) && Preg::isMatch('{^origin\s+(?P<url>\S+)}m', $output, $originMatch)
&& preg_match('{^composer\s+(?P<url>\S+)}m', $output, $composerMatch) && Preg::isMatch('{^composer\s+(?P<url>\S+)}m', $output, $composerMatch)
) { ) {
if ($originMatch['url'] === $composerMatch['url'] && $composerMatch['url'] !== $target->getSourceUrl()) { if ($originMatch['url'] === $composerMatch['url'] && $composerMatch['url'] !== $target->getSourceUrl()) {
$updateOriginUrl = true; $updateOriginUrl = true;
@ -244,13 +245,13 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
} }
$refs = trim($output); $refs = trim($output);
if (!preg_match('{^([a-f0-9]+) HEAD$}mi', $refs, $match)) { if (!Preg::isMatch('{^([a-f0-9]+) HEAD$}mi', $refs, $match)) {
// could not match the HEAD for some reason // could not match the HEAD for some reason
return null; return null;
} }
$headRef = $match[1]; $headRef = $match[1];
if (!preg_match_all('{^'.$headRef.' refs/heads/(.+)$}mi', $refs, $matches)) { if (!Preg::isMatchAll('{^'.$headRef.' refs/heads/(.+)$}mi', $refs, $matches)) {
// not on a branch, we are either on a not-modified tag or some sort of detached head, so skip this // not on a branch, we are either on a not-modified tag or some sort of detached head, so skip this
return null; return null;
} }
@ -267,7 +268,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
// try to find matching branch names in remote repos // try to find matching branch names in remote repos
foreach ($candidateBranches as $candidate) { foreach ($candidateBranches as $candidate) {
if (preg_match_all('{^[a-f0-9]+ refs/remotes/((?:[^/]+)/'.preg_quote($candidate).')$}mi', $refs, $matches)) { if (Preg::isMatchAll('{^[a-f0-9]+ refs/remotes/((?:[^/]+)/'.preg_quote($candidate).')$}mi', $refs, $matches)) {
foreach ($matches[1] as $match) { foreach ($matches[1] as $match) {
$branch = $candidate; $branch = $candidate;
$remoteBranches[] = $match; $remoteBranches[] = $match;
@ -359,7 +360,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
$changes = array_map(function ($elem) { $changes = array_map(function ($elem) {
return ' '.$elem; return ' '.$elem;
}, preg_split('{\s*\r?\n\s*}', $changes)); }, Preg::split('{\s*\r?\n\s*}', $changes));
$this->io->writeError(' <error>'.$package->getPrettyName().' has modified files:</error>'); $this->io->writeError(' <error>'.$package->getPrettyName().' has modified files:</error>');
$this->io->writeError(array_slice($changes, 0, 10)); $this->io->writeError(array_slice($changes, 0, 10));
if (count($changes) > 10) { if (count($changes) > 10) {
@ -448,7 +449,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
// If the non-existent branch is actually the name of a file, the file // If the non-existent branch is actually the name of a file, the file
// is checked out. // is checked out.
$template = 'git checkout '.$force.'%s -- && git reset --hard %1$s --'; $template = 'git checkout '.$force.'%s -- && git reset --hard %1$s --';
$branch = preg_replace('{(?:^dev-|(?:\.x)?-dev$)}i', '', $branch); $branch = Preg::replace('{(?:^dev-|(?:\.x)?-dev$)}i', '', $branch);
$branches = null; $branches = null;
if (0 === $this->process->execute('git branch -r', $output, $path)) { if (0 === $this->process->execute('git branch -r', $output, $path)) {
@ -457,9 +458,9 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
// check whether non-commitish are branches or tags, and fetch branches with the remote name // check whether non-commitish are branches or tags, and fetch branches with the remote name
$gitRef = $reference; $gitRef = $reference;
if (!preg_match('{^[a-f0-9]{40}$}', $reference) if (!Preg::isMatch('{^[a-f0-9]{40}$}', $reference)
&& $branches && $branches
&& preg_match('{^\s+composer/'.preg_quote($reference).'$}m', $branches) && Preg::isMatch('{^\s+composer/'.preg_quote($reference).'$}m', $branches)
) { ) {
$command = sprintf('git checkout '.$force.'-B %s %s -- && git reset --hard %2$s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference)); $command = sprintf('git checkout '.$force.'-B %s %s -- && git reset --hard %2$s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference));
if (0 === $this->process->execute($command, $output, $path)) { if (0 === $this->process->execute($command, $output, $path)) {
@ -468,9 +469,9 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
} }
// try to checkout branch by name and then reset it so it's on the proper branch name // try to checkout branch by name and then reset it so it's on the proper branch name
if (preg_match('{^[a-f0-9]{40}$}', $reference)) { if (Preg::isMatch('{^[a-f0-9]{40}$}', $reference)) {
// add 'v' in front of the branch if it was stripped when generating the pretty name // add 'v' in front of the branch if it was stripped when generating the pretty name
if (!preg_match('{^\s+composer/'.preg_quote($branch).'$}m', $branches) && preg_match('{^\s+composer/v'.preg_quote($branch).'$}m', $branches)) { if (!Preg::isMatch('{^\s+composer/'.preg_quote($branch).'$}m', $branches) && Preg::isMatch('{^\s+composer/v'.preg_quote($branch).'$}m', $branches)) {
$branch = 'v' . $branch; $branch = 'v' . $branch;
} }
@ -517,7 +518,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
protected function setPushUrl($path, $url) protected function setPushUrl($path, $url)
{ {
// set push url for github projects // set push url for github projects
if (preg_match('{^(?:https?|git)://'.GitUtil::getGitHubDomainsRegex($this->config).'/([^/]+)/([^/]+?)(?:\.git)?$}', $url, $match)) { if (Preg::isMatch('{^(?:https?|git)://'.GitUtil::getGitHubDomainsRegex($this->config).'/([^/]+)/([^/]+?)(?:\.git)?$}', $url, $match)) {
$protocols = $this->config->get('github-protocols'); $protocols = $this->config->get('github-protocols');
$pushUrl = 'git@'.$match[1].':'.$match[2].'/'.$match[3].'.git'; $pushUrl = 'git@'.$match[1].':'.$match[2].'/'.$match[3].'.git';
if (!in_array('ssh', $protocols, true)) { if (!in_array('ssh', $protocols, true)) {
@ -640,7 +641,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
*/ */
protected function getShortHash($reference) protected function getShortHash($reference)
{ {
if (!$this->io->isVerbose() && preg_match('{^[0-9a-f]{40}$}', $reference)) { if (!$this->io->isVerbose() && Preg::isMatch('{^[0-9a-f]{40}$}', $reference)) {
return substr($reference, 0, 10); return substr($reference, 0, 10);
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Downloader; namespace Composer\Downloader;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Pcre\Preg;
use Composer\Util\Svn as SvnUtil; use Composer\Util\Svn as SvnUtil;
use Composer\Repository\VcsRepository; use Composer\Repository\VcsRepository;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
@ -98,7 +99,7 @@ class SvnDownloader extends VcsDownloader
$this->process->execute('svn status --ignore-externals', $output, $path); $this->process->execute('svn status --ignore-externals', $output, $path);
return preg_match('{^ *[^X ] +}m', $output) ? $output : null; return Preg::isMatch('{^ *[^X ] +}m', $output) ? $output : null;
} }
/** /**
@ -145,7 +146,7 @@ class SvnDownloader extends VcsDownloader
$changes = array_map(function ($elem) { $changes = array_map(function ($elem) {
return ' '.$elem; return ' '.$elem;
}, preg_split('{\s*\r?\n\s*}', $changes)); }, Preg::split('{\s*\r?\n\s*}', $changes));
$countChanges = count($changes); $countChanges = count($changes);
$this->io->writeError(sprintf(' <error>'.$package->getPrettyName().' has modified file%s:</error>', $countChanges === 1 ? '' : 's')); $this->io->writeError(sprintf(' <error>'.$package->getPrettyName().' has modified file%s:</error>', $countChanges === 1 ? '' : 's'));
$this->io->writeError(array_slice($changes, 0, 10)); $this->io->writeError(array_slice($changes, 0, 10));
@ -192,7 +193,7 @@ class SvnDownloader extends VcsDownloader
*/ */
protected function getCommitLogs($fromReference, $toReference, $path) protected function getCommitLogs($fromReference, $toReference, $path)
{ {
if (preg_match('{@(\d+)$}', $fromReference) && preg_match('{@(\d+)$}', $toReference)) { if (Preg::isMatch('{@(\d+)$}', $fromReference) && Preg::isMatch('{@(\d+)$}', $toReference)) {
// retrieve the svn base url from the checkout folder // retrieve the svn base url from the checkout folder
$command = sprintf('svn info --non-interactive --xml -- %s', ProcessExecutor::escape($path)); $command = sprintf('svn info --non-interactive --xml -- %s', ProcessExecutor::escape($path));
if (0 !== $this->process->execute($command, $output, $path)) { if (0 !== $this->process->execute($command, $output, $path)) {
@ -202,7 +203,7 @@ class SvnDownloader extends VcsDownloader
} }
$urlPattern = '#<url>(.*)</url>#'; $urlPattern = '#<url>(.*)</url>#';
if (preg_match($urlPattern, $output, $matches)) { if (Preg::isMatch($urlPattern, $output, $matches)) {
$baseUrl = $matches[1]; $baseUrl = $matches[1];
} else { } else {
throw new \RuntimeException( throw new \RuntimeException(
@ -211,8 +212,8 @@ class SvnDownloader extends VcsDownloader
} }
// strip paths from references and only keep the actual revision // strip paths from references and only keep the actual revision
$fromRevision = preg_replace('{.*@(\d+)$}', '$1', $fromReference); $fromRevision = Preg::replace('{.*@(\d+)$}', '$1', $fromReference);
$toRevision = preg_replace('{.*@(\d+)$}', '$1', $toReference); $toRevision = Preg::replace('{.*@(\d+)$}', '$1', $toReference);
$command = sprintf('svn log -r%s:%s --incremental', ProcessExecutor::escape($fromRevision), ProcessExecutor::escape($toRevision)); $command = sprintf('svn log -r%s:%s --incremental', ProcessExecutor::escape($fromRevision), ProcessExecutor::escape($toRevision));

View File

@ -16,6 +16,7 @@ use Composer\DependencyResolver\Transaction;
use Composer\Installer\InstallerEvent; use Composer\Installer\InstallerEvent;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Composer; use Composer\Composer;
use Composer\Pcre\Preg;
use Composer\Util\Platform; use Composer\Util\Platform;
use Composer\DependencyResolver\Operation\OperationInterface; use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\Repository\RepositoryInterface; use Composer\Repository\RepositoryInterface;
@ -253,9 +254,9 @@ class EventDispatcher
$possibleLocalBinaries = $this->composer->getPackage()->getBinaries(); $possibleLocalBinaries = $this->composer->getPackage()->getBinaries();
if ($possibleLocalBinaries) { if ($possibleLocalBinaries) {
foreach ($possibleLocalBinaries as $localExec) { foreach ($possibleLocalBinaries as $localExec) {
if (preg_match('{\b'.preg_quote($callable).'$}', $localExec)) { if (Preg::isMatch('{\b'.preg_quote($callable).'$}', $localExec)) {
$caller = BinaryInstaller::determineBinaryCaller($localExec); $caller = BinaryInstaller::determineBinaryCaller($localExec);
$exec = preg_replace('{^'.preg_quote($callable).'}', $caller . ' ' . $localExec, $exec); $exec = Preg::replace('{^'.preg_quote($callable).'}', $caller . ' ' . $localExec, $exec);
break; break;
} }
} }
@ -274,13 +275,13 @@ class EventDispatcher
if (strpos($exec, '@php ') === 0) { if (strpos($exec, '@php ') === 0) {
$pathAndArgs = substr($exec, 5); $pathAndArgs = substr($exec, 5);
if (Platform::isWindows()) { if (Platform::isWindows()) {
$pathAndArgs = preg_replace_callback('{^\S+}', function ($path) { $pathAndArgs = Preg::replaceCallback('{^\S+}', function ($path) {
return str_replace('/', '\\', $path[0]); return str_replace('/', '\\', $path[0]);
}, $pathAndArgs); }, $pathAndArgs);
} }
// match somename (not in quote, and not a qualified path) and if it is not a valid path from CWD then try to find it // match somename (not in quote, and not a qualified path) and if it is not a valid path from CWD then try to find it
// in $PATH. This allows support for `@php foo` where foo is a binary name found in PATH but not an actual relative path // in $PATH. This allows support for `@php foo` where foo is a binary name found in PATH but not an actual relative path
$matched = preg_match('{^[^\'"\s/\\\\]+}', $pathAndArgs, $match); $matched = Preg::isMatch('{^[^\'"\s/\\\\]+}', $pathAndArgs, $match);
if ($matched && !file_exists($match[0])) { if ($matched && !file_exists($match[0])) {
$finder = new ExecutableFinder; $finder = new ExecutableFinder;
if ($pathToExec = $finder->find($match[0])) { if ($pathToExec = $finder->find($match[0])) {
@ -296,7 +297,7 @@ class EventDispatcher
} }
if (Platform::isWindows()) { if (Platform::isWindows()) {
$exec = preg_replace_callback('{^\S+}', function ($path) { $exec = Preg::replaceCallback('{^\S+}', function ($path) {
return str_replace('/', '\\', $path[0]); return str_replace('/', '\\', $path[0]);
}, $exec); }, $exec);
} }
@ -579,7 +580,7 @@ class EventDispatcher
if (is_dir($binDir)) { if (is_dir($binDir)) {
$binDir = realpath($binDir); $binDir = realpath($binDir);
$pathValue = Platform::getEnv($pathEnv); $pathValue = Platform::getEnv($pathEnv);
if (!preg_match('{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', $pathValue)) { if (!Preg::isMatch('{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', $pathValue)) {
Platform::putEnv($pathEnv, $binDir.PATH_SEPARATOR.$pathValue); Platform::putEnv($pathEnv, $binDir.PATH_SEPARATOR.$pathValue);
} }
} }

View File

@ -3,6 +3,7 @@
namespace Composer\Filter\PlatformRequirementFilter; namespace Composer\Filter\PlatformRequirementFilter;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Pcre\Preg;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
final class IgnoreListPlatformRequirementFilter implements PlatformRequirementFilterInterface final class IgnoreListPlatformRequirementFilter implements PlatformRequirementFilterInterface
@ -30,6 +31,6 @@ final class IgnoreListPlatformRequirementFilter implements PlatformRequirementFi
return false; return false;
} }
return 1 === preg_match($this->regexp, $req); return Preg::isMatch($this->regexp, $req);
} }
} }

View File

@ -13,6 +13,7 @@
namespace Composer\IO; namespace Composer\IO;
use Composer\Config; use Composer\Config;
use Composer\Pcre\Preg;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
@ -129,7 +130,7 @@ abstract class BaseIO implements IOInterface
foreach ($githubOauth as $domain => $token) { foreach ($githubOauth as $domain => $token) {
// allowed chars for GH tokens are from https://github.blog/changelog/2021-03-04-authentication-token-format-updates/ // allowed chars for GH tokens are from https://github.blog/changelog/2021-03-04-authentication-token-format-updates/
// plus dots which were at some point used for GH app integration tokens // plus dots which were at some point used for GH app integration tokens
if (!preg_match('{^[.A-Za-z0-9_]+$}', $token)) { if (!Preg::isMatch('{^[.A-Za-z0-9_]+$}', $token)) {
throw new \UnexpectedValueException('Your github oauth token for '.$domain.' contains invalid characters: "'.$token.'"'); throw new \UnexpectedValueException('Your github oauth token for '.$domain.' contains invalid characters: "'.$token.'"');
} }
$this->checkAndSetAuthentication($domain, $token, 'x-oauth-basic'); $this->checkAndSetAuthentication($domain, $token, 'x-oauth-basic');

View File

@ -12,6 +12,7 @@
namespace Composer\IO; namespace Composer\IO;
use Composer\Pcre\Preg;
use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Formatter\OutputFormatterInterface; use Symfony\Component\Console\Formatter\OutputFormatterInterface;
@ -55,7 +56,7 @@ class BufferIO extends ConsoleIO
$output = stream_get_contents($this->output->getStream()); $output = stream_get_contents($this->output->getStream());
$output = preg_replace_callback("{(?<=^|\n|\x08)(.+?)(\x08+)}", function ($matches) { $output = Preg::replaceCallback("{(?<=^|\n|\x08)(.+?)(\x08+)}", function ($matches) {
$pre = strip_tags($matches[1]); $pre = strip_tags($matches[1]);
if (strlen($pre) === strlen($matches[2])) { if (strlen($pre) === strlen($matches[2])) {

View File

@ -14,6 +14,7 @@ namespace Composer\Installer;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Platform; use Composer\Util\Platform;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
@ -153,7 +154,7 @@ class BinaryInstaller
$handle = fopen($bin, 'r'); $handle = fopen($bin, 'r');
$line = fgets($handle); $line = fgets($handle);
fclose($handle); fclose($handle);
if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) { if (Preg::isMatch('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) {
return trim($match[1]); return trim($match[1]);
} }
@ -255,7 +256,7 @@ class BinaryInstaller
$binContents = file_get_contents($bin); $binContents = file_get_contents($bin);
// For php files, we generate a PHP proxy instead of a shell one, // For php files, we generate a PHP proxy instead of a shell one,
// which allows calling the proxy with a custom php process // which allows calling the proxy with a custom php process
if (preg_match('{^(#!.*\r?\n)?<\?php}', $binContents, $match)) { if (Preg::isMatch('{^(#!.*\r?\n)?<\?php}', $binContents, $match)) {
// carry over the existing shebang if present, otherwise add our own // carry over the existing shebang if present, otherwise add our own
$proxyCode = empty($match[1]) ? '#!/usr/bin/env php' : trim($match[1]); $proxyCode = empty($match[1]) ? '#!/usr/bin/env php' : trim($match[1]);
$binPathExported = $this->filesystem->findShortestPathCode($link, $bin, false, true); $binPathExported = $this->filesystem->findShortestPathCode($link, $bin, false, true);

View File

@ -14,6 +14,7 @@ namespace Composer\Installer;
use Composer\Composer; use Composer\Composer;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Composer\Repository\InstalledRepositoryInterface; use Composer\Repository\InstalledRepositoryInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
@ -252,7 +253,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
$targetDir = $package->getTargetDir(); $targetDir = $package->getTargetDir();
if ($targetDir) { if ($targetDir) {
return preg_replace('{/*'.str_replace('/', '/+', preg_quote($targetDir)).'/?$}', '', $installPath); return Preg::replace('{/*'.str_replace('/', '/+', preg_quote($targetDir)).'/?$}', '', $installPath);
} }
return $installPath; return $installPath;

View File

@ -14,6 +14,7 @@ namespace Composer\Installer;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Pcre\Preg;
use Composer\Repository\InstalledRepository; use Composer\Repository\InstalledRepository;
use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatter;
@ -232,7 +233,7 @@ class SuggestedPackagesReporter
*/ */
private function removeControlCharacters($string) private function removeControlCharacters($string)
{ {
return preg_replace( return Preg::replace(
'/[[:cntrl:]]/', '/[[:cntrl:]]/',
'', '',
str_replace("\n", ' ', $string) str_replace("\n", ' ', $string)

View File

@ -12,6 +12,7 @@
namespace Composer\Json; namespace Composer\Json;
use Composer\Pcre\Preg;
use JsonSchema\Validator; use JsonSchema\Validator;
use Seld\JsonLint\JsonParser; use Seld\JsonLint\JsonParser;
use Seld\JsonLint\ParsingException; use Seld\JsonLint\ParsingException;
@ -55,7 +56,7 @@ class JsonFile
{ {
$this->path = $path; $this->path = $path;
if (null === $httpDownloader && preg_match('{^https?://}i', $path)) { if (null === $httpDownloader && Preg::isMatch('{^https?://}i', $path)) {
throw new \InvalidArgumentException('http urls require a HttpDownloader instance to be passed'); throw new \InvalidArgumentException('http urls require a HttpDownloader instance to be passed');
} }
$this->httpDownloader = $httpDownloader; $this->httpDownloader = $httpDownloader;
@ -245,8 +246,8 @@ class JsonFile
// compact brackets to follow recent php versions // compact brackets to follow recent php versions
if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) { if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) {
$json = preg_replace('/\[\s+\]/', '[]', $json); $json = Preg::replace('/\[\s+\]/', '[]', $json);
$json = preg_replace('/\{\s+\}/', '{}', $json); $json = Preg::replace('/\{\s+\}/', '{}', $json);
} }
return $json; return $json;

View File

@ -12,6 +12,8 @@
namespace Composer\Json; namespace Composer\Json;
use Composer\Pcre\Preg;
/** /**
* Formats json strings used for php < 5.4 because the json_encode doesn't * Formats json strings used for php < 5.4 because the json_encode doesn't
* supports the flags JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE * supports the flags JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
@ -66,7 +68,7 @@ class JsonFormatter
if ($unescapeUnicode && function_exists('mb_convert_encoding')) { if ($unescapeUnicode && function_exists('mb_convert_encoding')) {
// https://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha // https://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha
$buffer = preg_replace_callback('/(\\\\+)u([0-9a-f]{4})/i', function ($match) { $buffer = Preg::replaceCallback('/(\\\\+)u([0-9a-f]{4})/i', function ($match) {
$l = strlen($match[1]); $l = strlen($match[1]);
if ($l % 2) { if ($l % 2) {

View File

@ -12,6 +12,7 @@
namespace Composer\Json; namespace Composer\Json;
use Composer\Pcre\Preg;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
/** /**
@ -46,7 +47,7 @@ class JsonManipulator
if ($contents === '') { if ($contents === '') {
$contents = '{}'; $contents = '{}';
} }
if (!$this->pregMatch('#^\{(.*)\}$#s', $contents)) { if (!Preg::isMatch('#^\{(.*)\}$#s', $contents)) {
throw new \InvalidArgumentException('The json file must be an object ({})'); throw new \InvalidArgumentException('The json file must be an object ({})');
} }
$this->newline = false !== strpos($contents, "\r\n") ? "\r\n" : "\n"; $this->newline = false !== strpos($contents, "\r\n") ? "\r\n" : "\n";
@ -80,7 +81,7 @@ class JsonManipulator
$regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
'(?P<property>'.preg_quote(JsonFile::encode($type)).'\s*:\s*)(?P<value>(?&json))(?P<end>.*)}sx'; '(?P<property>'.preg_quote(JsonFile::encode($type)).'\s*:\s*)(?P<value>(?&json))(?P<end>.*)}sx';
if (!$this->pregMatch($regex, $this->contents, $matches)) { if (!Preg::isMatch($regex, $this->contents, $matches)) {
return false; return false;
} }
@ -89,17 +90,17 @@ class JsonManipulator
// try to find existing link // try to find existing link
$packageRegex = str_replace('/', '\\\\?/', preg_quote($package)); $packageRegex = str_replace('/', '\\\\?/', preg_quote($package));
$regex = '{'.self::$DEFINES.'"(?P<package>'.$packageRegex.')"(\s*:\s*)(?&string)}ix'; $regex = '{'.self::$DEFINES.'"(?P<package>'.$packageRegex.')"(\s*:\s*)(?&string)}ix';
if ($this->pregMatch($regex, $links, $packageMatches)) { if (Preg::isMatch($regex, $links, $packageMatches)) {
// update existing link // update existing link
$existingPackage = $packageMatches['package']; $existingPackage = $packageMatches['package'];
$packageRegex = str_replace('/', '\\\\?/', preg_quote($existingPackage)); $packageRegex = str_replace('/', '\\\\?/', preg_quote($existingPackage));
$links = preg_replace_callback('{'.self::$DEFINES.'"'.$packageRegex.'"(?P<separator>\s*:\s*)(?&string)}ix', function ($m) use ($existingPackage, $constraint) { $links = Preg::replaceCallback('{'.self::$DEFINES.'"'.$packageRegex.'"(?P<separator>\s*:\s*)(?&string)}ix', function ($m) use ($existingPackage, $constraint) {
return JsonFile::encode(str_replace('\\/', '/', $existingPackage)) . $m['separator'] . '"' . $constraint . '"'; return JsonFile::encode(str_replace('\\/', '/', $existingPackage)) . $m['separator'] . '"' . $constraint . '"';
}, $links); }, $links);
} else { } else {
if ($this->pregMatch('#^\s*\{\s*\S+.*?(\s*\}\s*)$#s', $links, $match)) { if (Preg::isMatch('#^\s*\{\s*\S+.*?(\s*\}\s*)$#s', $links, $match)) {
// link missing but non empty links // link missing but non empty links
$links = preg_replace( $links = Preg::replace(
'{'.preg_quote($match[1]).'$}', '{'.preg_quote($match[1]).'$}',
// addcslashes is used to double up backslashes/$ since preg_replace resolves them as back references otherwise, see #1588 // addcslashes is used to double up backslashes/$ since preg_replace resolves them as back references otherwise, see #1588
addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $match[1], '\\$'), addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $match[1], '\\$'),
@ -136,7 +137,7 @@ class JsonManipulator
{ {
$prefix = function ($requirement) { $prefix = function ($requirement) {
if (PlatformRepository::isPlatformPackage($requirement)) { if (PlatformRepository::isPlatformPackage($requirement)) {
return preg_replace( return Preg::replace(
array( array(
'/^php/', '/^php/',
'/^hhvm/', '/^hhvm/',
@ -277,7 +278,7 @@ class JsonManipulator
preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P<content>(?&object))(?P<end>.*)}sx'; preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P<content>(?&object))(?P<end>.*)}sx';
try { try {
if (!$this->pregMatch($nodeRegex, $this->contents, $match)) { if (!Preg::isMatch($nodeRegex, $this->contents, $match)) {
return false; return false;
} }
} catch (\RuntimeException $e) { } catch (\RuntimeException $e) {
@ -297,8 +298,8 @@ class JsonManipulator
// child exists // child exists
$childRegex = '{'.self::$DEFINES.'(?P<start>"'.preg_quote($name).'"\s*:\s*)(?P<content>(?&json))(?P<end>,?)}x'; $childRegex = '{'.self::$DEFINES.'(?P<start>"'.preg_quote($name).'"\s*:\s*)(?P<content>(?&json))(?P<end>,?)}x';
if ($this->pregMatch($childRegex, $children, $matches)) { if (Preg::isMatch($childRegex, $children, $matches)) {
$children = preg_replace_callback($childRegex, function ($matches) use ($subName, $value, $that) { $children = Preg::replaceCallback($childRegex, function ($matches) use ($subName, $value, $that) {
if ($subName !== null) { if ($subName !== null) {
$curVal = json_decode($matches['content'], true); $curVal = json_decode($matches['content'], true);
if (!is_array($curVal)) { if (!is_array($curVal)) {
@ -311,7 +312,7 @@ class JsonManipulator
return $matches['start'] . $that->format($value, 1) . $matches['end']; return $matches['start'] . $that->format($value, 1) . $matches['end'];
}, $children); }, $children);
} else { } else {
$this->pregMatch('#^{ (?P<leadingspace>\s*?) (?P<content>\S+.*?)? (?P<trailingspace>\s*) }$#sx', $children, $match); Preg::match('#^{ (?P<leadingspace>\s*?) (?P<content>\S+.*?)? (?P<trailingspace>\s*) }$#sx', $children, $match);
$whitespace = ''; $whitespace = '';
if (!empty($match['trailingspace'])) { if (!empty($match['trailingspace'])) {
@ -325,7 +326,7 @@ class JsonManipulator
// child missing but non empty children // child missing but non empty children
if ($append) { if ($append) {
$children = preg_replace( $children = Preg::replace(
'#'.$whitespace.'}$#', '#'.$whitespace.'}$#',
addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}', '\\$'), addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}', '\\$'),
$children $children
@ -336,7 +337,7 @@ class JsonManipulator
$whitespace = $match['leadingspace']; $whitespace = $match['leadingspace'];
} }
$children = preg_replace( $children = Preg::replace(
'#^{'.$whitespace.'#', '#^{'.$whitespace.'#',
addcslashes('{' . $whitespace . JsonFile::encode($name).': '.$this->format($value, 1) . ',' . $this->newline . $this->indent . $this->indent, '\\$'), addcslashes('{' . $whitespace . JsonFile::encode($name).': '.$this->format($value, 1) . ',' . $this->newline . $this->indent . $this->indent, '\\$'),
$children $children
@ -352,7 +353,7 @@ class JsonManipulator
} }
} }
$this->contents = preg_replace_callback($nodeRegex, function ($m) use ($children) { $this->contents = Preg::replaceCallback($nodeRegex, function ($m) use ($children) {
return $m['start'] . $children . $m['end']; return $m['start'] . $children . $m['end'];
}, $this->contents); }, $this->contents);
@ -377,7 +378,7 @@ class JsonManipulator
$nodeRegex = '{'.self::$DEFINES.'^(?P<start> \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'. $nodeRegex = '{'.self::$DEFINES.'^(?P<start> \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'.
preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P<content>(?&object))(?P<end>.*)}sx'; preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P<content>(?&object))(?P<end>.*)}sx';
try { try {
if (!$this->pregMatch($nodeRegex, $this->contents, $match)) { if (!Preg::isMatch($nodeRegex, $this->contents, $match)) {
return false; return false;
} }
} catch (\RuntimeException $e) { } catch (\RuntimeException $e) {
@ -406,18 +407,18 @@ class JsonManipulator
// try and find a match for the subkey // try and find a match for the subkey
$keyRegex = str_replace('/', '\\\\?/', preg_quote($name)); $keyRegex = str_replace('/', '\\\\?/', preg_quote($name));
if ($this->pregMatch('{"'.$keyRegex.'"\s*:}i', $children)) { if (Preg::isMatch('{"'.$keyRegex.'"\s*:}i', $children)) {
// find best match for the value of "name" // find best match for the value of "name"
if (preg_match_all('{'.self::$DEFINES.'"'.$keyRegex.'"\s*:\s*(?:(?&json))}x', $children, $matches)) { if (Preg::isMatchAll('{'.self::$DEFINES.'"'.$keyRegex.'"\s*:\s*(?:(?&json))}x', $children, $matches)) {
$bestMatch = ''; $bestMatch = '';
foreach ($matches[0] as $match) { foreach ($matches[0] as $match) {
if (strlen($bestMatch) < strlen($match)) { if (strlen($bestMatch) < strlen($match)) {
$bestMatch = $match; $bestMatch = $match;
} }
} }
$childrenClean = preg_replace('{,\s*'.preg_quote($bestMatch).'}i', '', $children, -1, $count); $childrenClean = Preg::replace('{,\s*'.preg_quote($bestMatch).'}i', '', $children, -1, $count);
if (1 !== $count) { if (1 !== $count) {
$childrenClean = preg_replace('{'.preg_quote($bestMatch).'\s*,?\s*}i', '', $childrenClean, -1, $count); $childrenClean = Preg::replace('{'.preg_quote($bestMatch).'\s*,?\s*}i', '', $childrenClean, -1, $count);
if (1 !== $count) { if (1 !== $count) {
return false; return false;
} }
@ -432,12 +433,12 @@ class JsonManipulator
} }
// no child data left, $name was the only key in // no child data left, $name was the only key in
$this->pregMatch('#^{ \s*? (?P<content>\S+.*?)? (?P<trailingspace>\s*) }$#sx', $childrenClean, $match); Preg::match('#^{ \s*? (?P<content>\S+.*?)? (?P<trailingspace>\s*) }$#sx', $childrenClean, $match);
if (empty($match['content'])) { if (empty($match['content'])) {
$newline = $this->newline; $newline = $this->newline;
$indent = $this->indent; $indent = $this->indent;
$this->contents = preg_replace_callback($nodeRegex, function ($matches) use ($indent, $newline) { $this->contents = Preg::replaceCallback($nodeRegex, function ($matches) use ($indent, $newline) {
return $matches['start'] . '{' . $newline . $indent . '}' . $matches['end']; return $matches['start'] . '{' . $newline . $indent . '}' . $matches['end'];
}, $this->contents); }, $this->contents);
@ -452,7 +453,7 @@ class JsonManipulator
} }
$that = $this; $that = $this;
$this->contents = preg_replace_callback($nodeRegex, function ($matches) use ($that, $name, $subName, $childrenClean) { $this->contents = Preg::replaceCallback($nodeRegex, function ($matches) use ($that, $name, $subName, $childrenClean) {
if ($subName !== null) { if ($subName !== null) {
$curVal = json_decode($matches['content'], true); $curVal = json_decode($matches['content'], true);
unset($curVal[$name][$subName]); unset($curVal[$name][$subName]);
@ -478,7 +479,7 @@ class JsonManipulator
// key exists already // key exists already
$regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
'(?P<key>'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))(?P<end>.*)}sx'; '(?P<key>'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))(?P<end>.*)}sx';
if (isset($decoded[$key]) && $this->pregMatch($regex, $this->contents, $matches)) { if (isset($decoded[$key]) && Preg::isMatch($regex, $this->contents, $matches)) {
// invalid match due to un-regexable content, abort // invalid match due to un-regexable content, abort
if (!@json_decode('{'.$matches['key'].'}')) { if (!@json_decode('{'.$matches['key'].'}')) {
return false; return false;
@ -490,8 +491,8 @@ class JsonManipulator
} }
// append at the end of the file and keep whitespace // append at the end of the file and keep whitespace
if ($this->pregMatch('#[^{\s](\s*)\}$#', $this->contents, $match)) { if (Preg::isMatch('#[^{\s](\s*)\}$#', $this->contents, $match)) {
$this->contents = preg_replace( $this->contents = Preg::replace(
'#'.$match[1].'\}$#', '#'.$match[1].'\}$#',
addcslashes(',' . $this->newline . $this->indent . JsonFile::encode($key). ': '. $content . $this->newline . '}', '\\$'), addcslashes(',' . $this->newline . $this->indent . JsonFile::encode($key). ': '. $content . $this->newline . '}', '\\$'),
$this->contents $this->contents
@ -501,7 +502,7 @@ class JsonManipulator
} }
// append at the end of the file // append at the end of the file
$this->contents = preg_replace( $this->contents = Preg::replace(
'#\}$#', '#\}$#',
addcslashes($this->indent . JsonFile::encode($key). ': '.$content . $this->newline . '}', '\\$'), addcslashes($this->indent . JsonFile::encode($key). ': '.$content . $this->newline . '}', '\\$'),
$this->contents $this->contents
@ -525,19 +526,19 @@ class JsonManipulator
// key exists already // key exists already
$regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. $regex = '{'.self::$DEFINES.'^(?P<start>\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'.
'(?P<removal>'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))\s*,?\s*(?P<end>.*)}sx'; '(?P<removal>'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))\s*,?\s*(?P<end>.*)}sx';
if ($this->pregMatch($regex, $this->contents, $matches)) { if (Preg::isMatch($regex, $this->contents, $matches)) {
// invalid match due to un-regexable content, abort // invalid match due to un-regexable content, abort
if (!@json_decode('{'.$matches['removal'].'}')) { if (!@json_decode('{'.$matches['removal'].'}')) {
return false; return false;
} }
// check that we are not leaving a dangling comma on the previous line if the last line was removed // check that we are not leaving a dangling comma on the previous line if the last line was removed
if (preg_match('#,\s*$#', $matches['start']) && preg_match('#^\}$#', $matches['end'])) { if (Preg::isMatch('#,\s*$#', $matches['start']) && Preg::isMatch('#^\}$#', $matches['end'])) {
$matches['start'] = rtrim(preg_replace('#,(\s*)$#', '$1', $matches['start']), $this->indent); $matches['start'] = rtrim(Preg::replace('#,(\s*)$#', '$1', $matches['start']), $this->indent);
} }
$this->contents = $matches['start'] . $matches['end']; $this->contents = $matches['start'] . $matches['end'];
if (preg_match('#^\{\s*\}\s*$#', $this->contents)) { if (Preg::isMatch('#^\{\s*\}\s*$#', $this->contents)) {
$this->contents = "{\n}"; $this->contents = "{\n}";
} }
@ -601,47 +602,10 @@ class JsonManipulator
*/ */
protected function detectIndenting() protected function detectIndenting()
{ {
if ($this->pregMatch('{^([ \t]+)"}m', $this->contents, $match)) { if (Preg::isMatch('{^([ \t]+)"}m', $this->contents, $match)) {
$this->indent = $match[1]; $this->indent = $match[1];
} else { } else {
$this->indent = ' '; $this->indent = ' ';
} }
} }
/**
* @param string $re
* @param string $str
* @param array<string> $matches
* @return int
*/
protected function pregMatch($re, $str, &$matches = array())
{
$count = preg_match($re, $str, $matches);
if ($count === false) {
switch (preg_last_error()) {
case PREG_NO_ERROR:
throw new \RuntimeException('Failed to execute regex: PREG_NO_ERROR', PREG_NO_ERROR);
case PREG_INTERNAL_ERROR:
throw new \RuntimeException('Failed to execute regex: PREG_INTERNAL_ERROR', PREG_INTERNAL_ERROR);
case PREG_BACKTRACK_LIMIT_ERROR:
throw new \RuntimeException('Failed to execute regex: PREG_BACKTRACK_LIMIT_ERROR', PREG_BACKTRACK_LIMIT_ERROR);
case PREG_RECURSION_LIMIT_ERROR:
throw new \RuntimeException('Failed to execute regex: PREG_RECURSION_LIMIT_ERROR', PREG_RECURSION_LIMIT_ERROR);
case PREG_BAD_UTF8_ERROR:
throw new \RuntimeException('Failed to execute regex: PREG_BAD_UTF8_ERROR', PREG_BAD_UTF8_ERROR);
case PREG_BAD_UTF8_OFFSET_ERROR:
throw new \RuntimeException('Failed to execute regex: PREG_BAD_UTF8_OFFSET_ERROR', PREG_BAD_UTF8_OFFSET_ERROR);
case 6: // PREG_JIT_STACKLIMIT_ERROR
if (PHP_VERSION_ID > 70000) {
throw new \RuntimeException('Failed to execute regex: PREG_JIT_STACKLIMIT_ERROR', 6);
}
// no break
default:
throw new \RuntimeException('Failed to execute regex: Unknown error');
}
}
return $count;
}
} }

View File

@ -12,6 +12,7 @@
namespace Composer\Package\Archiver; namespace Composer\Package\Archiver;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use FilesystemIterator; use FilesystemIterator;
use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\Finder;
@ -61,7 +62,7 @@ class ArchivableFilesFinder extends \FilterIterator
return false; return false;
} }
$relativePath = preg_replace( $relativePath = Preg::replace(
'#^'.preg_quote($sources, '#').'#', '#^'.preg_quote($sources, '#').'#',
'', '',
$fs->normalizePath($file->getRealPath()) $fs->normalizePath($file->getRealPath())

View File

@ -14,6 +14,7 @@ namespace Composer\Package\Archiver;
use Composer\Downloader\DownloadManager; use Composer\Downloader\DownloadManager;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Loop; use Composer\Util\Loop;
use Composer\Util\SyncHelper; use Composer\Util\SyncHelper;
@ -86,11 +87,11 @@ class ArchiveManager
if ($package->getArchiveName()) { if ($package->getArchiveName()) {
$baseName = $package->getArchiveName(); $baseName = $package->getArchiveName();
} else { } else {
$baseName = preg_replace('#[^a-z0-9-_]#i', '-', $package->getName()); $baseName = Preg::replace('#[^a-z0-9-_]#i', '-', $package->getName());
} }
$nameParts = array($baseName); $nameParts = array($baseName);
if (null !== $package->getDistReference() && preg_match('{^[a-f0-9]{40}$}', $package->getDistReference())) { if (null !== $package->getDistReference() && Preg::isMatch('{^[a-f0-9]{40}$}', $package->getDistReference())) {
array_push($nameParts, $package->getDistReference(), $package->getDistType()); array_push($nameParts, $package->getDistReference(), $package->getDistType());
} else { } else {
array_push($nameParts, $package->getPrettyVersion(), $package->getDistReference()); array_push($nameParts, $package->getPrettyVersion(), $package->getDistReference());

View File

@ -12,6 +12,7 @@
namespace Composer\Package\Archiver; namespace Composer\Package\Archiver;
use Composer\Pcre\Preg;
use Symfony\Component\Finder; use Symfony\Component\Finder;
/** /**
@ -59,8 +60,12 @@ abstract class BaseExcludeFilter
$path = $relativePath; $path = $relativePath;
} }
if (@preg_match($pattern, $path)) { try {
$exclude = !$negate; if (Preg::isMatch($pattern, $path)) {
$exclude = !$negate;
}
} catch (\RuntimeException $e) {
// suppressed
} }
} }

View File

@ -12,6 +12,8 @@
namespace Composer\Package\Archiver; namespace Composer\Package\Archiver;
use Composer\Pcre\Preg;
/** /**
* An exclude filter that processes gitattributes * An exclude filter that processes gitattributes
* *
@ -50,7 +52,7 @@ class GitExcludeFilter extends BaseExcludeFilter
*/ */
public function parseGitAttributesLine($line) public function parseGitAttributesLine($line)
{ {
$parts = preg_split('#\s+#', $line); $parts = Preg::split('#\s+#', $line);
if (count($parts) == 2 && $parts[1] === 'export-ignore') { if (count($parts) == 2 && $parts[1] === 'export-ignore') {
return $this->generatePattern($parts[0]); return $this->generatePattern($parts[0]);

View File

@ -21,6 +21,7 @@ use Composer\Package\CompletePackageInterface;
use Composer\Package\Link; use Composer\Package\Link;
use Composer\Package\RootAliasPackage; use Composer\Package\RootAliasPackage;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Pcre\Preg;
/** /**
* @author Konstantin Kudryashiv <ever.zet@gmail.com> * @author Konstantin Kudryashiv <ever.zet@gmail.com>
@ -227,7 +228,7 @@ class ArrayLoader implements LoaderInterface
} }
if (!empty($config['time'])) { if (!empty($config['time'])) {
$time = preg_match('/^\d++$/D', $config['time']) ? '@'.$config['time'] : $config['time']; $time = Preg::isMatch('/^\d++$/D', $config['time']) ? '@'.$config['time'] : $config['time'];
try { try {
$date = new \DateTime($time, new \DateTimeZone('UTC')); $date = new \DateTime($time, new \DateTimeZone('UTC'));
@ -298,7 +299,7 @@ class ArrayLoader implements LoaderInterface
} }
if ($aliasNormalized = $this->getBranchAlias($config)) { if ($aliasNormalized = $this->getBranchAlias($config)) {
$prettyAlias = preg_replace('{(\.9{7})+}', '.x', $aliasNormalized); $prettyAlias = Preg::replace('{(\.9{7})+}', '.x', $aliasNormalized);
if ($package instanceof RootPackage) { if ($package instanceof RootPackage) {
return new RootAliasPackage($package, $aliasNormalized, $prettyAlias); return new RootAliasPackage($package, $aliasNormalized, $prettyAlias);

View File

@ -16,6 +16,7 @@ use Composer\Package\BasePackage;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Package\RootAliasPackage; use Composer\Package\RootAliasPackage;
use Composer\Pcre\Preg;
use Composer\Repository\RepositoryFactory; use Composer\Repository\RepositoryFactory;
use Composer\Package\Version\VersionGuesser; use Composer\Package\Version\VersionGuesser;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
@ -196,7 +197,7 @@ class RootPackageLoader extends ArrayLoader
private function extractAliases(array $requires, array $aliases) private function extractAliases(array $requires, array $aliases)
{ {
foreach ($requires as $reqName => $reqVersion) { foreach ($requires as $reqName => $reqVersion) {
if (preg_match('{^([^,\s#]+)(?:#[^ ]+)? +as +([^,\s]+)$}', $reqVersion, $match)) { if (Preg::isMatch('{^([^,\s#]+)(?:#[^ ]+)? +as +([^,\s]+)$}', $reqVersion, $match)) {
$aliases[] = array( $aliases[] = array(
'package' => strtolower($reqName), 'package' => strtolower($reqName),
'version' => $this->versionParser->normalize($match[1], $reqVersion), 'version' => $this->versionParser->normalize($match[1], $reqVersion),
@ -232,9 +233,9 @@ class RootPackageLoader extends ArrayLoader
$constraints = array(); $constraints = array();
// extract all sub-constraints in case it is an OR/AND multi-constraint // extract all sub-constraints in case it is an OR/AND multi-constraint
$orSplit = preg_split('{\s*\|\|?\s*}', trim($reqVersion)); $orSplit = Preg::split('{\s*\|\|?\s*}', trim($reqVersion));
foreach ($orSplit as $orConstraint) { foreach ($orSplit as $orConstraint) {
$andSplit = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint); $andSplit = Preg::split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint);
foreach ($andSplit as $andConstraint) { foreach ($andSplit as $andConstraint) {
$constraints[] = $andConstraint; $constraints[] = $andConstraint;
} }
@ -243,7 +244,7 @@ class RootPackageLoader extends ArrayLoader
// parse explicit stability flags to the most unstable // parse explicit stability flags to the most unstable
$match = false; $match = false;
foreach ($constraints as $constraint) { foreach ($constraints as $constraint) {
if (preg_match('{^[^@]*?@('.implode('|', array_keys($stabilities)).')$}i', $constraint, $match)) { if (Preg::isMatch('{^[^@]*?@('.implode('|', array_keys($stabilities)).')$}i', $constraint, $match)) {
$name = strtolower($reqName); $name = strtolower($reqName);
$stability = $stabilities[VersionParser::normalizeStability($match[1])]; $stability = $stabilities[VersionParser::normalizeStability($match[1])];
@ -262,8 +263,8 @@ class RootPackageLoader extends ArrayLoader
foreach ($constraints as $constraint) { foreach ($constraints as $constraint) {
// infer flags for requirements that have an explicit -dev or -beta version specified but only // infer flags for requirements that have an explicit -dev or -beta version specified but only
// for those that are more unstable than the minimumStability or existing flags // for those that are more unstable than the minimumStability or existing flags
$reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $constraint); $reqVersion = Preg::replace('{^([^,\s@]+) as .+$}', '$1', $constraint);
if (preg_match('{^[^,\s@]+$}', $reqVersion) && 'stable' !== ($stabilityName = VersionParser::parseStability($reqVersion))) { if (Preg::isMatch('{^[^,\s@]+$}', $reqVersion) && 'stable' !== ($stabilityName = VersionParser::parseStability($reqVersion))) {
$name = strtolower($reqName); $name = strtolower($reqName);
$stability = $stabilities[$stabilityName]; $stability = $stabilities[$stabilityName];
if ((isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) || ($minimumStability > $stability)) { if ((isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) || ($minimumStability > $stability)) {
@ -288,8 +289,8 @@ class RootPackageLoader extends ArrayLoader
public static function extractReferences(array $requires, array $references) public static function extractReferences(array $requires, array $references)
{ {
foreach ($requires as $reqName => $reqVersion) { foreach ($requires as $reqName => $reqVersion) {
$reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion); $reqVersion = Preg::replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion);
if (preg_match('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) && 'dev' === VersionParser::parseStability($reqVersion)) { if (Preg::isMatch('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) && 'dev' === VersionParser::parseStability($reqVersion)) {
$name = strtolower($reqName); $name = strtolower($reqName);
$references[$name] = $match[1]; $references[$name] = $match[1];
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Package\Loader; namespace Composer\Package\Loader;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Pcre\Preg;
use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\Constraint;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
@ -251,7 +252,7 @@ class ValidatingArrayLoader implements LoaderInterface
} }
if ($err = self::hasPackageNamingError($package, true)) { if ($err = self::hasPackageNamingError($package, true)) {
$this->errors[] = $linkType.'.'.$err; $this->errors[] = $linkType.'.'.$err;
} elseif (!preg_match('{^[A-Za-z0-9_./-]+$}', $package)) { } elseif (!Preg::isMatch('{^[A-Za-z0-9_./-]+$}', $package)) {
$this->warnings[] = $linkType.'.'.$package.' : invalid key, package names must be strings containing only [A-Za-z0-9_./-]'; $this->warnings[] = $linkType.'.'.$package.' : invalid key, package names must be strings containing only [A-Za-z0-9_./-]';
} }
if (!is_string($constraint)) { if (!is_string($constraint)) {
@ -353,10 +354,10 @@ class ValidatingArrayLoader implements LoaderInterface
if (isset($this->config[$srcType]['reference']) && !is_string($this->config[$srcType]['reference']) && !is_int($this->config[$srcType]['reference'])) { if (isset($this->config[$srcType]['reference']) && !is_string($this->config[$srcType]['reference']) && !is_int($this->config[$srcType]['reference'])) {
$this->errors[] = $srcType . '.reference : should be a string or int, '.gettype($this->config[$srcType]['reference']).' given'; $this->errors[] = $srcType . '.reference : should be a string or int, '.gettype($this->config[$srcType]['reference']).' given';
} }
if (isset($this->config[$srcType]['reference']) && preg_match('{^\s*-}', (string) $this->config[$srcType]['reference'])) { if (isset($this->config[$srcType]['reference']) && Preg::isMatch('{^\s*-}', (string) $this->config[$srcType]['reference'])) {
$this->errors[] = $srcType . '.reference : must not start with a "-", "'.$this->config[$srcType]['reference'].'" given'; $this->errors[] = $srcType . '.reference : must not start with a "-", "'.$this->config[$srcType]['reference'].'" given';
} }
if (preg_match('{^\s*-}', $this->config[$srcType]['url'])) { if (Preg::isMatch('{^\s*-}', $this->config[$srcType]['url'])) {
$this->errors[] = $srcType . '.url : must not start with a "-", "'.$this->config[$srcType]['url'].'" given'; $this->errors[] = $srcType . '.url : must not start with a "-", "'.$this->config[$srcType]['url'].'" given';
} }
} }
@ -448,7 +449,7 @@ class ValidatingArrayLoader implements LoaderInterface
return null; return null;
} }
if (!preg_match('{^[a-z0-9](?:[_.-]?[a-z0-9]+)*/[a-z0-9](?:(?:[_.]?|-{0,2})[a-z0-9]+)*$}iD', $name)) { if (!Preg::isMatch('{^[a-z0-9](?:[_.-]?[a-z0-9]+)*/[a-z0-9](?:(?:[_.]?|-{0,2})[a-z0-9]+)*$}iD', $name)) {
return $name.' is invalid, it should have a vendor name, a forward slash, and a package name. The vendor and package name can be words separated by -, . or _. The complete name should match "^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]?|-{0,2})[a-z0-9]+)*$".'; return $name.' is invalid, it should have a vendor name, a forward slash, and a package name. The vendor and package name can be words separated by -, . or _. The complete name should match "^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]?|-{0,2})[a-z0-9]+)*$".';
} }
@ -458,16 +459,16 @@ class ValidatingArrayLoader implements LoaderInterface
return $name.' is reserved, package and vendor names can not match any of: '.implode(', ', $reservedNames).'.'; return $name.' is reserved, package and vendor names can not match any of: '.implode(', ', $reservedNames).'.';
} }
if (preg_match('{\.json$}', $name)) { if (Preg::isMatch('{\.json$}', $name)) {
return $name.' is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.'; return $name.' is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.';
} }
if (preg_match('{[A-Z]}', $name)) { if (Preg::isMatch('{[A-Z]}', $name)) {
if ($isLink) { if ($isLink) {
return $name.' is invalid, it should not contain uppercase characters. Please use '.strtolower($name).' instead.'; return $name.' is invalid, it should not contain uppercase characters. Please use '.strtolower($name).' instead.';
} }
$suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name); $suggestName = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
$suggestName = strtolower($suggestName); $suggestName = strtolower($suggestName);
return $name.' is invalid, it should not contain uppercase characters. We suggest using '.$suggestName.' instead.'; return $name.' is invalid, it should not contain uppercase characters. We suggest using '.$suggestName.' instead.';
@ -492,7 +493,7 @@ class ValidatingArrayLoader implements LoaderInterface
return false; return false;
} }
if (!preg_match('{^'.$regex.'$}u', $this->config[$property])) { if (!Preg::isMatch('{^'.$regex.'$}u', $this->config[$property])) {
$message = $property.' : invalid value ('.$this->config[$property].'), must match '.$regex; $message = $property.' : invalid value ('.$this->config[$property].'), must match '.$regex;
if ($mandatory) { if ($mandatory) {
$this->errors[] = $message; $this->errors[] = $message;
@ -591,7 +592,7 @@ class ValidatingArrayLoader implements LoaderInterface
continue; continue;
} }
if ($regex && !preg_match('{^'.$regex.'$}u', $value)) { if ($regex && !Preg::isMatch('{^'.$regex.'$}u', $value)) {
$this->warnings[] = $property.'.'.$key.' : invalid value ('.$value.'), must match '.$regex; $this->warnings[] = $property.'.'.$key.' : invalid value ('.$value.'), must match '.$regex;
unset($this->config[$property][$key]); unset($this->config[$property][$key]);
$pass = false; $pass = false;

View File

@ -14,6 +14,7 @@ namespace Composer\Package;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Installer\InstallationManager; use Composer\Installer\InstallationManager;
use Composer\Pcre\Preg;
use Composer\Repository\LockArrayRepository; use Composer\Repository\LockArrayRepository;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Package\Dumper\ArrayDumper; use Composer\Package\Dumper\ArrayDumper;
@ -492,13 +493,13 @@ class Locker
case 'git': case 'git':
GitUtil::cleanEnv(); GitUtil::cleanEnv();
if (0 === $this->process->execute('git log -n1 --pretty=%ct '.ProcessExecutor::escape($sourceRef).GitUtil::getNoShowSignatureFlag($this->process), $output, $path) && preg_match('{^\s*\d+\s*$}', $output)) { if (0 === $this->process->execute('git log -n1 --pretty=%ct '.ProcessExecutor::escape($sourceRef).GitUtil::getNoShowSignatureFlag($this->process), $output, $path) && Preg::isMatch('{^\s*\d+\s*$}', $output)) {
$datetime = new \DateTime('@'.trim($output), new \DateTimeZone('UTC')); $datetime = new \DateTime('@'.trim($output), new \DateTimeZone('UTC'));
} }
break; break;
case 'hg': case 'hg':
if (0 === $this->process->execute('hg log --template "{date|hgdate}" -r '.ProcessExecutor::escape($sourceRef), $output, $path) && preg_match('{^\s*(\d+)\s*}', $output, $match)) { if (0 === $this->process->execute('hg log --template "{date|hgdate}" -r '.ProcessExecutor::escape($sourceRef), $output, $path) && Preg::isMatch('{^\s*(\d+)\s*}', $output, $match)) {
$datetime = new \DateTime('@'.$match[1], new \DateTimeZone('UTC')); $datetime = new \DateTime('@'.$match[1], new \DateTimeZone('UTC'));
} }
break; break;

View File

@ -13,6 +13,7 @@
namespace Composer\Package; namespace Composer\Package;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Pcre\Preg;
use Composer\Util\ComposerMirror; use Composer\Util\ComposerMirror;
/** /**
@ -160,7 +161,7 @@ class Package extends BasePackage
return null; return null;
} }
return ltrim(preg_replace('{ (?:^|[\\\\/]+) \.\.? (?:[\\\\/]+|$) (?:\.\.? (?:[\\\\/]+|$) )*}x', '/', $this->targetDir), '/'); return ltrim(Preg::replace('{ (?:^|[\\\\/]+) \.\.? (?:[\\\\/]+|$) (?:\.\.? (?:[\\\\/]+|$) )*}x', '/', $this->targetDir), '/');
} }
/** /**
@ -703,10 +704,10 @@ class Package extends BasePackage
// TODO generalize this a bit for self-managed/on-prem versions? Some kind of replace token in dist urls which allow this? // TODO generalize this a bit for self-managed/on-prem versions? Some kind of replace token in dist urls which allow this?
if ( if (
$this->getDistUrl() !== null $this->getDistUrl() !== null
&& preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $this->getDistUrl()) && Preg::isMatch('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $this->getDistUrl())
) { ) {
$this->setDistReference($reference); $this->setDistReference($reference);
$this->setDistUrl(preg_replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $this->getDistUrl())); $this->setDistUrl(Preg::replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $this->getDistUrl()));
} elseif ($this->getDistReference()) { // update the dist reference if there was one, but if none was provided ignore it } elseif ($this->getDistReference()) { // update the dist reference if there was one, but if none was provided ignore it
$this->setDistReference($reference); $this->setDistReference($reference);
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Package\Version; namespace Composer\Package\Version;
use Composer\Config; use Composer\Config;
use Composer\Pcre\Preg;
use Composer\Repository\Vcs\HgDriver; use Composer\Repository\Vcs\HgDriver;
use Composer\IO\NullIO; use Composer\IO\NullIO;
use Composer\Semver\VersionParser as SemverVersionParser; use Composer\Semver\VersionParser as SemverVersionParser;
@ -108,12 +109,12 @@ class VersionGuesser
unset($versionData['feature_version'], $versionData['feature_pretty_version']); unset($versionData['feature_version'], $versionData['feature_pretty_version']);
} }
if ('-dev' === substr($versionData['version'], -4) && preg_match('{\.9{7}}', $versionData['version'])) { if ('-dev' === substr($versionData['version'], -4) && Preg::isMatch('{\.9{7}}', $versionData['version'])) {
$versionData['pretty_version'] = preg_replace('{(\.9{7})+}', '.x', $versionData['version']); $versionData['pretty_version'] = Preg::replace('{(\.9{7})+}', '.x', $versionData['version']);
} }
if (!empty($versionData['feature_version']) && '-dev' === substr($versionData['feature_version'], -4) && preg_match('{\.9{7}}', $versionData['feature_version'])) { if (!empty($versionData['feature_version']) && '-dev' === substr($versionData['feature_version'], -4) && Preg::isMatch('{\.9{7}}', $versionData['feature_version'])) {
$versionData['feature_pretty_version'] = preg_replace('{(\.9{7})+}', '.x', $versionData['feature_version']); $versionData['feature_pretty_version'] = Preg::replace('{(\.9{7})+}', '.x', $versionData['feature_version']);
} }
return $versionData; return $versionData;
@ -142,7 +143,7 @@ class VersionGuesser
// find current branch and collect all branch names // find current branch and collect all branch names
foreach ($this->process->splitLines($output) as $branch) { foreach ($this->process->splitLines($output) as $branch) {
if ($branch && preg_match('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\(HEAD detached at \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) { if ($branch && Preg::isMatch('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\(HEAD detached at \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
if ( if (
$match[1] === '(no branch)' $match[1] === '(no branch)'
|| strpos($match[1], '(detached ') === 0 || strpos($match[1], '(detached ') === 0
@ -163,8 +164,8 @@ class VersionGuesser
} }
} }
if ($branch && !preg_match('{^ *.+/HEAD }', $branch)) { if ($branch && !Preg::isMatch('{^ *.+/HEAD }', $branch)) {
if (preg_match('{^(?:\* )? *((?:remotes/(?:origin|upstream)/)?[^\s/]+) *([a-f0-9]+) .*$}', $branch, $match)) { if (Preg::isMatch('{^(?:\* )? *((?:remotes/(?:origin|upstream)/)?[^\s/]+) *([a-f0-9]+) .*$}', $branch, $match)) {
$branches[] = $match[1]; $branches[] = $match[1];
} }
} }
@ -284,7 +285,7 @@ class VersionGuesser
if (!isset($packageConfig['extra']['branch-alias'][$version]) if (!isset($packageConfig['extra']['branch-alias'][$version])
|| strpos(json_encode($packageConfig), '"self.version"') || strpos(json_encode($packageConfig), '"self.version"')
) { ) {
$branch = preg_replace('{^dev-}', '', $version); $branch = Preg::replace('{^dev-}', '', $version);
$length = PHP_INT_MAX; $length = PHP_INT_MAX;
// return directly, if branch is configured to be non-feature branch // return directly, if branch is configured to be non-feature branch
@ -307,7 +308,7 @@ class VersionGuesser
}); });
foreach ($branches as $candidate) { foreach ($branches as $candidate) {
$candidateVersion = preg_replace('{^remotes/\S+/}', '', $candidate); $candidateVersion = Preg::replace('{^remotes/\S+/}', '', $candidate);
// do not compare against itself or other feature branches // do not compare against itself or other feature branches
if ($candidate === $branch || $this->isFeatureBranch($packageConfig, $candidateVersion)) { if ($candidate === $branch || $this->isFeatureBranch($packageConfig, $candidateVersion)) {
@ -346,7 +347,7 @@ class VersionGuesser
$nonFeatureBranches = implode('|', $packageConfig['non-feature-branches']); $nonFeatureBranches = implode('|', $packageConfig['non-feature-branches']);
} }
return !preg_match('{^(' . $nonFeatureBranches . '|master|main|latest|next|current|support|tip|trunk|default|develop|\d+\..+)$}', $branchName, $match); return !Preg::isMatch('{^(' . $nonFeatureBranches . '|master|main|latest|next|current|support|tip|trunk|default|develop|\d+\..+)$}', $branchName, $match);
} }
/** /**
@ -396,7 +397,7 @@ class VersionGuesser
$urlPattern = '#<url>.*/(' . $trunkPath . '|(' . $branchesPath . '|' . $tagsPath . ')/(.*))</url>#'; $urlPattern = '#<url>.*/(' . $trunkPath . '|(' . $branchesPath . '|' . $tagsPath . ')/(.*))</url>#';
if (preg_match($urlPattern, $output, $matches)) { if (Preg::isMatch($urlPattern, $output, $matches)) {
if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) { if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) {
// we are in a branches path // we are in a branches path
$version = $this->versionParser->normalizeBranch($matches[3]); $version = $this->versionParser->normalizeBranch($matches[3]);

View File

@ -12,6 +12,7 @@
namespace Composer\Package\Version; namespace Composer\Package\Version;
use Composer\Pcre\Preg;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
use Composer\Semver\VersionParser as SemverVersionParser; use Composer\Semver\VersionParser as SemverVersionParser;
use Composer\Semver\Semver; use Composer\Semver\Semver;
@ -52,8 +53,8 @@ class VersionParser extends SemverVersionParser
$result = array(); $result = array();
for ($i = 0, $count = count($pairs); $i < $count; $i++) { for ($i = 0, $count = count($pairs); $i < $count; $i++) {
$pair = preg_replace('{^([^=: ]+)[=: ](.*)$}', '$1 $2', trim($pairs[$i])); $pair = Preg::replace('{^([^=: ]+)[=: ](.*)$}', '$1 $2', trim($pairs[$i]));
if (false === strpos($pair, ' ') && isset($pairs[$i + 1]) && false === strpos($pairs[$i + 1], '/') && !preg_match('{(?<=[a-z0-9_/-])\*|\*(?=[a-z0-9_/-])}i', $pairs[$i + 1]) && !PlatformRepository::isPlatformPackage($pairs[$i + 1])) { if (false === strpos($pair, ' ') && isset($pairs[$i + 1]) && false === strpos($pairs[$i + 1], '/') && !Preg::isMatch('{(?<=[a-z0-9_/-])\*|\*(?=[a-z0-9_/-])}i', $pairs[$i + 1]) && !PlatformRepository::isPlatformPackage($pairs[$i + 1])) {
$pair .= ' '.$pairs[$i + 1]; $pair .= ' '.$pairs[$i + 1];
$i++; $i++;
} }

View File

@ -21,6 +21,7 @@ use Composer\Package\PackageInterface;
use Composer\Composer; use Composer\Composer;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Dumper\ArrayDumper; use Composer\Package\Dumper\ArrayDumper;
use Composer\Pcre\Preg;
use Composer\Repository\RepositorySet; use Composer\Repository\RepositorySet;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\Constraint;
@ -192,7 +193,7 @@ class VersionSelector
$dumper = new ArrayDumper(); $dumper = new ArrayDumper();
$extra = $loader->getBranchAlias($dumper->dump($package)); $extra = $loader->getBranchAlias($dumper->dump($package));
if ($extra && $extra !== VersionParser::DEFAULT_BRANCH_ALIAS) { if ($extra && $extra !== VersionParser::DEFAULT_BRANCH_ALIAS) {
$extra = preg_replace('{^(\d+\.\d+\.\d+)(\.9999999)-dev$}', '$1.0', $extra, -1, $count); $extra = Preg::replace('{^(\d+\.\d+\.\d+)(\.9999999)-dev$}', '$1.0', $extra, -1, $count);
if ($count) { if ($count) {
$extra = str_replace('.9999999', '.0', $extra); $extra = str_replace('.9999999', '.0', $extra);
@ -217,7 +218,7 @@ class VersionSelector
$semanticVersionParts = explode('.', $version); $semanticVersionParts = explode('.', $version);
// check to see if we have a semver-looking version // check to see if we have a semver-looking version
if (count($semanticVersionParts) == 4 && preg_match('{^0\D?}', $semanticVersionParts[3])) { if (count($semanticVersionParts) == 4 && Preg::isMatch('{^0\D?}', $semanticVersionParts[3])) {
// remove the last parts (i.e. the patch version number and any extra) // remove the last parts (i.e. the patch version number and any extra)
if ($semanticVersionParts[0] === '0') { if ($semanticVersionParts[0] === '0') {
unset($semanticVersionParts[3]); unset($semanticVersionParts[3]);

View File

@ -12,6 +12,8 @@
namespace Composer\Platform; namespace Composer\Platform;
use Composer\Pcre\Preg;
/** /**
* @author Lars Strojny <lars@strojny.net> * @author Lars Strojny <lars@strojny.net>
*/ */
@ -26,7 +28,7 @@ class Version
{ {
$isFips = false; $isFips = false;
if (!preg_match('/^(?<version>[0-9.]+)(?<patch>[a-z]{0,2})?(?<suffix>(?:-?(?:dev|pre|alpha|beta|rc|fips)[\d]*)*)?(?<garbage>-\w+)?$/', $opensslVersion, $matches)) { if (!Preg::isMatch('/^(?<version>[0-9.]+)(?<patch>[a-z]{0,2})?(?<suffix>(?:-?(?:dev|pre|alpha|beta|rc|fips)[\d]*)*)?(?<garbage>-\w+)?$/', $opensslVersion, $matches)) {
return null; return null;
} }
@ -43,7 +45,7 @@ class Version
*/ */
public static function parseLibjpeg($libjpegVersion) public static function parseLibjpeg($libjpegVersion)
{ {
if (!preg_match('/^(?<major>\d+)(?<minor>[a-z]*)$/', $libjpegVersion, $matches)) { if (!Preg::isMatch('/^(?<major>\d+)(?<minor>[a-z]*)$/', $libjpegVersion, $matches)) {
return null; return null;
} }
@ -56,7 +58,7 @@ class Version
*/ */
public static function parseZoneinfoVersion($zoneinfoVersion) public static function parseZoneinfoVersion($zoneinfoVersion)
{ {
if (!preg_match('/^(?<year>\d{4})(?<revision>[a-z]*)$/', $zoneinfoVersion, $matches)) { if (!Preg::isMatch('/^(?<year>\d{4})(?<revision>[a-z]*)$/', $zoneinfoVersion, $matches)) {
return null; return null;
} }

View File

@ -18,6 +18,7 @@ use Composer\IO\IOInterface;
use Composer\Package\CompletePackage; use Composer\Package\CompletePackage;
use Composer\Package\Package; use Composer\Package\Package;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Pcre\Preg;
use Composer\Repository\RepositoryInterface; use Composer\Repository\RepositoryInterface;
use Composer\Repository\InstalledRepository; use Composer\Repository\InstalledRepository;
use Composer\Repository\RootPackageRepository; use Composer\Repository\RootPackageRepository;
@ -173,7 +174,7 @@ class PluginManager
return; return;
} }
if ($package->getName() === 'symfony/flex' && preg_match('{^[0-9.]+$}', $package->getVersion()) && version_compare($package->getVersion(), '1.9.8', '<')) { if ($package->getName() === 'symfony/flex' && Preg::isMatch('{^[0-9.]+$}', $package->getVersion()) && version_compare($package->getVersion(), '1.9.8', '<')) {
$this->io->writeError('<warning>The "' . $package->getName() . '" plugin '.($isGlobalPlugin ? '(installed globally) ' : '').'was skipped because it is not compatible with Composer 2+. Make sure to update it to version 1.9.8 or greater.</warning>'); $this->io->writeError('<warning>The "' . $package->getName() . '" plugin '.($isGlobalPlugin ? '(installed globally) ' : '').'was skipped because it is not compatible with Composer 2+. Make sure to update it to version 1.9.8 or greater.</warning>');
return; return;
@ -234,13 +235,13 @@ class PluginManager
if ($separatorPos) { if ($separatorPos) {
$className = substr($class, $separatorPos + 1); $className = substr($class, $separatorPos + 1);
} }
$code = preg_replace('{^((?:final\s+)?(?:\s*))class\s+('.preg_quote($className).')}mi', '$1class $2_composer_tmp'.self::$classCounter, $code, 1); $code = Preg::replace('{^((?:final\s+)?(?:\s*))class\s+('.preg_quote($className).')}mi', '$1class $2_composer_tmp'.self::$classCounter, $code, 1);
$code = strtr($code, array( $code = strtr($code, array(
'__FILE__' => var_export($path, true), '__FILE__' => var_export($path, true),
'__DIR__' => var_export(dirname($path), true), '__DIR__' => var_export(dirname($path), true),
'__CLASS__' => var_export($class, true), '__CLASS__' => var_export($class, true),
)); ));
$code = preg_replace('/^\s*<\?(php)?/i', '', $code, 1); $code = Preg::replace('/^\s*<\?(php)?/i', '', $code, 1);
eval($code); eval($code);
$class .= '_composer_tmp'.self::$classCounter; $class .= '_composer_tmp'.self::$classCounter;
self::$classCounter++; self::$classCounter++;

View File

@ -12,6 +12,7 @@
namespace Composer\Question; namespace Composer\Question;
use Composer\Pcre\Preg;
use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Question\Question;
@ -66,11 +67,11 @@ class StrictConfirmationQuestion extends Question
return $default; return $default;
} }
if (preg_match($trueRegex, $answer)) { if (Preg::isMatch($trueRegex, $answer)) {
return true; return true;
} }
if (preg_match($falseRegex, $answer)) { if (Preg::isMatch($falseRegex, $answer)) {
return false; return false;
} }

View File

@ -20,6 +20,7 @@ use Composer\Package\PackageInterface;
use Composer\Package\CompletePackageInterface; use Composer\Package\CompletePackageInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Package\Version\StabilityFilter; use Composer\Package\Version\StabilityFilter;
use Composer\Pcre\Preg;
use Composer\Semver\Constraint\ConstraintInterface; use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Semver\Constraint\Constraint; use Composer\Semver\Constraint\Constraint;
@ -147,7 +148,7 @@ class ArrayRepository implements RepositoryInterface
*/ */
public function search($query, $mode = 0, $type = null) public function search($query, $mode = 0, $type = null)
{ {
$regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i'; $regex = '{(?:'.implode('|', Preg::split('{\s+}', $query)).')}i';
$matches = array(); $matches = array();
foreach ($this->getPackages() as $package) { foreach ($this->getPackages() as $package) {
@ -155,8 +156,8 @@ class ArrayRepository implements RepositoryInterface
if (isset($matches[$name])) { if (isset($matches[$name])) {
continue; continue;
} }
if (preg_match($regex, $name) if (Preg::isMatch($regex, $name)
|| ($mode === self::SEARCH_FULLTEXT && $package instanceof CompletePackageInterface && preg_match($regex, implode(' ', (array) $package->getKeywords()) . ' ' . $package->getDescription())) || ($mode === self::SEARCH_FULLTEXT && $package instanceof CompletePackageInterface && Preg::isMatch($regex, implode(' ', (array) $package->getKeywords()) . ' ' . $package->getDescription()))
) { ) {
if (null !== $type && $package->getType() !== $type) { if (null !== $type && $package->getType() !== $type) {
continue; continue;

View File

@ -24,6 +24,7 @@ use Composer\Json\JsonFile;
use Composer\Cache; use Composer\Cache;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Composer\Plugin\PostFileDownloadEvent; use Composer\Plugin\PostFileDownloadEvent;
use Composer\Semver\CompilingMatcher; use Composer\Semver\CompilingMatcher;
use Composer\Util\HttpDownloader; use Composer\Util\HttpDownloader;
@ -135,7 +136,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
public function __construct(array $repoConfig, IOInterface $io, Config $config, HttpDownloader $httpDownloader, EventDispatcher $eventDispatcher = null) public function __construct(array $repoConfig, IOInterface $io, Config $config, HttpDownloader $httpDownloader, EventDispatcher $eventDispatcher = null)
{ {
parent::__construct(); parent::__construct();
if (!preg_match('{^[\w.]+\??://}', $repoConfig['url'])) { if (!Preg::isMatch('{^[\w.]+\??://}', $repoConfig['url'])) {
// assume http as the default protocol // assume http as the default protocol
$repoConfig['url'] = 'http://'.$repoConfig['url']; $repoConfig['url'] = 'http://'.$repoConfig['url'];
} }
@ -161,13 +162,13 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
$this->url = $repoConfig['url']; $this->url = $repoConfig['url'];
// force url for packagist.org to repo.packagist.org // force url for packagist.org to repo.packagist.org
if (preg_match('{^(?P<proto>https?)://packagist\.org/?$}i', $this->url, $match)) { if (Preg::isMatch('{^(?P<proto>https?)://packagist\.org/?$}i', $this->url, $match)) {
$this->url = $match['proto'].'://repo.packagist.org'; $this->url = $match['proto'].'://repo.packagist.org';
} }
$this->baseUrl = rtrim(preg_replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/'); $this->baseUrl = rtrim(Preg::replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/');
$this->io = $io; $this->io = $io;
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', Url::sanitize($this->url)), 'a-z0-9.$~'); $this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($this->url)), 'a-z0-9.$~');
$this->cache->setReadOnly($config->get('cache-read-only')); $this->cache->setReadOnly($config->get('cache-read-only'));
$this->versionParser = new VersionParser(); $this->versionParser = new VersionParser();
$this->loader = new ArrayLoader($this->versionParser); $this->loader = new ArrayLoader($this->versionParser);
@ -350,7 +351,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
if (null !== $packageFilter) { if (null !== $packageFilter) {
$packageFilterRegex = '{^'.str_replace('\\*', '.*?', preg_quote($packageFilter)).'$}i'; $packageFilterRegex = '{^'.str_replace('\\*', '.*?', preg_quote($packageFilter)).'$}i';
$packageFilterCb = function ($name) use ($packageFilterRegex) { $packageFilterCb = function ($name) use ($packageFilterRegex) {
return (bool) preg_match($packageFilterRegex, $name); return Preg::isMatch($packageFilterRegex, $name);
}; };
} }
@ -490,11 +491,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
if ($this->hasProviders() || $this->lazyProvidersUrl) { if ($this->hasProviders() || $this->lazyProvidersUrl) {
$results = array(); $results = array();
$regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i'; $regex = '{(?:'.implode('|', Preg::split('{\s+}', $query)).')}i';
$packageNames = $this->getPackageNames(); $packageNames = $this->getPackageNames();
foreach (preg_grep($regex, $packageNames) as $name) { foreach (Preg::grep($regex, $packageNames) as $name) {
$results[] = array('name' => $name, 'description' => ''); $results[] = array('name' => $name, 'description' => '');
} }
@ -793,7 +794,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
foreach ($packageNames as $name => $constraint) { foreach ($packageNames as $name => $constraint) {
$name = strtolower($name); $name = strtolower($name);
$realName = preg_replace('{~dev$}', '', $name); $realName = Preg::replace('{~dev$}', '', $name);
// skip platform packages, root package and composer-plugin-api // skip platform packages, root package and composer-plugin-api
if (PlatformRepository::isPlatformPackage($realName) || '__root__' === $realName) { if (PlatformRepository::isPlatformPackage($realName) || '__root__' === $realName) {
continue; continue;
@ -1044,7 +1045,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
private function canonicalizeUrl($url) private function canonicalizeUrl($url)
{ {
if ('/' === $url[0]) { if ('/' === $url[0]) {
if (preg_match('{^[^:]++://[^/]*+}', $this->url, $matches)) { if (Preg::isMatch('{^[^:]++://[^/]*+}', $this->url, $matches)) {
return $matches[0] . $url; return $matches[0] . $url;
} }
@ -1204,7 +1205,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
} }
// url-encode $ signs in URLs as bad proxies choke on them // url-encode $ signs in URLs as bad proxies choke on them
if (($pos = strpos($filename, '$')) && preg_match('{^https?://}i', $filename)) { if (($pos = strpos($filename, '$')) && Preg::isMatch('{^https?://}i', $filename)) {
$filename = substr($filename, 0, $pos) . '%24' . substr($filename, $pos + 1); $filename = substr($filename, 0, $pos) . '%24' . substr($filename, $pos + 1);
} }
@ -1509,7 +1510,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
if (is_array($this->availablePackagePatterns)) { if (is_array($this->availablePackagePatterns)) {
foreach ($this->availablePackagePatterns as $providerRegex) { foreach ($this->availablePackagePatterns as $providerRegex) {
if (preg_match($providerRegex, $name)) { if (Preg::isMatch($providerRegex, $name)) {
return true; return true;
} }
} }

View File

@ -14,6 +14,7 @@ namespace Composer\Repository;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Pcre\Preg;
/** /**
* Filters which packages are seen as canonical on this repo by loadPackages * Filters which packages are seen as canonical on this repo by loadPackages
@ -202,9 +203,9 @@ class FilterRepository implements RepositoryInterface
} }
if ($this->only) { if ($this->only) {
return (bool) preg_match($this->only, $name); return Preg::isMatch($this->only, $name);
} }
return !preg_match($this->exclude, $name); return !Preg::isMatch($this->exclude, $name);
} }
} }

View File

@ -14,6 +14,7 @@ namespace Composer\Repository;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Loader\ValidatingArrayLoader; use Composer\Package\Loader\ValidatingArrayLoader;
use Composer\Pcre\Preg;
/** /**
* Package repository. * Package repository.
@ -62,6 +63,6 @@ class PackageRepository extends ArrayRepository
public function getRepoName() public function getRepoName()
{ {
return preg_replace('{^array }', 'package ', parent::getRepoName()); return Preg::replace('{^array }', 'package ', parent::getRepoName());
} }
} }

View File

@ -18,6 +18,7 @@ use Composer\Json\JsonFile;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Version\VersionGuesser; use Composer\Package\Version\VersionGuesser;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Pcre\Preg;
use Composer\Util\Platform; use Composer\Util\Platform;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
@ -141,9 +142,9 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn
$urlMatches = $this->getUrlMatches(); $urlMatches = $this->getUrlMatches();
if (empty($urlMatches)) { if (empty($urlMatches)) {
if (preg_match('{[*{}]}', $this->url)) { if (Preg::isMatch('{[*{}]}', $this->url)) {
$url = $this->url; $url = $this->url;
while (preg_match('{[*{}]}', $url)) { while (Preg::isMatch('{[*{}]}', $url)) {
$url = dirname($url); $url = dirname($url);
} }
// the parent directory before any wildcard exists, so we assume it is correctly configured but simply empty // the parent directory before any wildcard exists, so we assume it is correctly configured but simply empty

View File

@ -18,6 +18,7 @@ use Composer\Package\CompletePackageInterface;
use Composer\Package\Link; use Composer\Package\Link;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Pcre\Preg;
use Composer\Platform\HhvmDetector; use Composer\Platform\HhvmDetector;
use Composer\Platform\Runtime; use Composer\Platform\Runtime;
use Composer\Platform\Version; use Composer\Platform\Version;
@ -146,7 +147,7 @@ class PlatformRepository extends ArrayRepository
$prettyVersion = $this->runtime->getConstant('PHP_VERSION'); $prettyVersion = $this->runtime->getConstant('PHP_VERSION');
$version = $this->versionParser->normalize($prettyVersion); $version = $this->versionParser->normalize($prettyVersion);
} catch (\UnexpectedValueException $e) { } catch (\UnexpectedValueException $e) {
$prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', $this->runtime->getConstant('PHP_VERSION')); $prettyVersion = Preg::replace('#^([^~+-]+).*$#', '$1', $this->runtime->getConstant('PHP_VERSION'));
$version = $this->versionParser->normalize($prettyVersion); $version = $this->versionParser->normalize($prettyVersion);
} }
@ -205,12 +206,12 @@ class PlatformRepository extends ArrayRepository
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
// librabbitmq version => 0.9.0 // librabbitmq version => 0.9.0
if (preg_match('/^librabbitmq version => (?<version>.+)$/im', $info, $librabbitmqMatches)) { if (Preg::isMatch('/^librabbitmq version => (?<version>.+)$/im', $info, $librabbitmqMatches)) {
$this->addLibrary($name.'-librabbitmq', $librabbitmqMatches['version'], 'AMQP librabbitmq version'); $this->addLibrary($name.'-librabbitmq', $librabbitmqMatches['version'], 'AMQP librabbitmq version');
} }
// AMQP protocol version => 0-9-1 // AMQP protocol version => 0-9-1
if (preg_match('/^AMQP protocol version => (?<version>.+)$/im', $info, $protocolMatches)) { if (Preg::isMatch('/^AMQP protocol version => (?<version>.+)$/im', $info, $protocolMatches)) {
$this->addLibrary($name.'-protocol', str_replace('-', '.', $protocolMatches['version']), 'AMQP protocol version'); $this->addLibrary($name.'-protocol', str_replace('-', '.', $protocolMatches['version']), 'AMQP protocol version');
} }
break; break;
@ -219,7 +220,7 @@ class PlatformRepository extends ArrayRepository
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
// BZip2 Version => 1.0.6, 6-Sept-2010 // BZip2 Version => 1.0.6, 6-Sept-2010
if (preg_match('/^BZip2 Version => (?<version>.*),/im', $info, $matches)) { if (Preg::isMatch('/^BZip2 Version => (?<version>.*),/im', $info, $matches)) {
$this->addLibrary($name, $matches['version']); $this->addLibrary($name, $matches['version']);
} }
break; break;
@ -231,7 +232,7 @@ class PlatformRepository extends ArrayRepository
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
// SSL Version => OpenSSL/1.0.1t // SSL Version => OpenSSL/1.0.1t
if (preg_match('{^SSL Version => (?<library>[^/]+)/(?<version>.+)$}im', $info, $sslMatches)) { if (Preg::isMatch('{^SSL Version => (?<library>[^/]+)/(?<version>.+)$}im', $info, $sslMatches)) {
$library = strtolower($sslMatches['library']); $library = strtolower($sslMatches['library']);
if ($library === 'openssl') { if ($library === 'openssl') {
$parsedVersion = Version::parseOpenssl($sslMatches['version'], $isFips); $parsedVersion = Version::parseOpenssl($sslMatches['version'], $isFips);
@ -242,12 +243,12 @@ class PlatformRepository extends ArrayRepository
} }
// libSSH Version => libssh2/1.4.3 // libSSH Version => libssh2/1.4.3
if (preg_match('{^libSSH Version => (?<library>[^/]+)/(?<version>.+?)(?:/.*)?$}im', $info, $sshMatches)) { if (Preg::isMatch('{^libSSH Version => (?<library>[^/]+)/(?<version>.+?)(?:/.*)?$}im', $info, $sshMatches)) {
$this->addLibrary($name.'-'.strtolower($sshMatches['library']), $sshMatches['version'], 'curl '.$sshMatches['library'].' version'); $this->addLibrary($name.'-'.strtolower($sshMatches['library']), $sshMatches['version'], 'curl '.$sshMatches['library'].' version');
} }
// ZLib Version => 1.2.8 // ZLib Version => 1.2.8
if (preg_match('{^ZLib Version => (?<version>.+)$}im', $info, $zlibMatches)) { if (Preg::isMatch('{^ZLib Version => (?<version>.+)$}im', $info, $zlibMatches)) {
$this->addLibrary($name.'-zlib', $zlibMatches['version'], 'curl zlib version'); $this->addLibrary($name.'-zlib', $zlibMatches['version'], 'curl zlib version');
} }
break; break;
@ -256,14 +257,14 @@ class PlatformRepository extends ArrayRepository
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
// timelib version => 2018.03 // timelib version => 2018.03
if (preg_match('/^timelib version => (?<version>.+)$/im', $info, $timelibMatches)) { if (Preg::isMatch('/^timelib version => (?<version>.+)$/im', $info, $timelibMatches)) {
$this->addLibrary($name.'-timelib', $timelibMatches['version'], 'date timelib version'); $this->addLibrary($name.'-timelib', $timelibMatches['version'], 'date timelib version');
} }
// Timezone Database => internal // Timezone Database => internal
if (preg_match('/^Timezone Database => (?<source>internal|external)$/im', $info, $zoneinfoSourceMatches)) { if (Preg::isMatch('/^Timezone Database => (?<source>internal|external)$/im', $info, $zoneinfoSourceMatches)) {
$external = $zoneinfoSourceMatches['source'] === 'external'; $external = $zoneinfoSourceMatches['source'] === 'external';
if (preg_match('/^"Olson" Timezone Database Version => (?<version>.+?)(\.system)?$/im', $info, $zoneinfoMatches)) { if (Preg::isMatch('/^"Olson" Timezone Database Version => (?<version>.+?)(\.system)?$/im', $info, $zoneinfoMatches)) {
// If the timezonedb is provided by ext/timezonedb, register that version as a replacement // If the timezonedb is provided by ext/timezonedb, register that version as a replacement
if ($external && in_array('timezonedb', $loadedExtensions, true)) { if ($external && in_array('timezonedb', $loadedExtensions, true)) {
$this->addLibrary('timezonedb-zoneinfo', $zoneinfoMatches['version'], 'zoneinfo ("Olson") database for date (replaced by timezonedb)', array($name.'-zoneinfo')); $this->addLibrary('timezonedb-zoneinfo', $zoneinfoMatches['version'], 'zoneinfo ("Olson") database for date (replaced by timezonedb)', array($name.'-zoneinfo'));
@ -278,7 +279,7 @@ class PlatformRepository extends ArrayRepository
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
// libmagic => 537 // libmagic => 537
if (preg_match('/^libmagic => (?<version>.+)$/im', $info, $magicMatches)) { if (Preg::isMatch('/^libmagic => (?<version>.+)$/im', $info, $magicMatches)) {
$this->addLibrary($name.'-libmagic', $magicMatches['version'], 'fileinfo libmagic version'); $this->addLibrary($name.'-libmagic', $magicMatches['version'], 'fileinfo libmagic version');
} }
break; break;
@ -288,19 +289,19 @@ class PlatformRepository extends ArrayRepository
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
if (preg_match('/^libJPEG Version => (?<version>.+?)(?: compatible)?$/im', $info, $libjpegMatches)) { if (Preg::isMatch('/^libJPEG Version => (?<version>.+?)(?: compatible)?$/im', $info, $libjpegMatches)) {
$this->addLibrary($name.'-libjpeg', Version::parseLibjpeg($libjpegMatches['version']), 'libjpeg version for gd'); $this->addLibrary($name.'-libjpeg', Version::parseLibjpeg($libjpegMatches['version']), 'libjpeg version for gd');
} }
if (preg_match('/^libPNG Version => (?<version>.+)$/im', $info, $libpngMatches)) { if (Preg::isMatch('/^libPNG Version => (?<version>.+)$/im', $info, $libpngMatches)) {
$this->addLibrary($name.'-libpng', $libpngMatches['version'], 'libpng version for gd'); $this->addLibrary($name.'-libpng', $libpngMatches['version'], 'libpng version for gd');
} }
if (preg_match('/^FreeType Version => (?<version>.+)$/im', $info, $freetypeMatches)) { if (Preg::isMatch('/^FreeType Version => (?<version>.+)$/im', $info, $freetypeMatches)) {
$this->addLibrary($name.'-freetype', $freetypeMatches['version'], 'freetype version for gd'); $this->addLibrary($name.'-freetype', $freetypeMatches['version'], 'freetype version for gd');
} }
if (preg_match('/^libXpm Version => (?<versionId>\d+)$/im', $info, $libxpmMatches)) { if (Preg::isMatch('/^libXpm Version => (?<versionId>\d+)$/im', $info, $libxpmMatches)) {
$this->addLibrary($name.'-libxpm', Version::convertLibxpmVersionId($libxpmMatches['versionId']), 'libxpm version for gd'); $this->addLibrary($name.'-libxpm', Version::convertLibxpmVersionId($libxpmMatches['versionId']), 'libxpm version for gd');
} }
@ -321,12 +322,12 @@ class PlatformRepository extends ArrayRepository
// Truthy check is for testing only so we can make the condition fail // Truthy check is for testing only so we can make the condition fail
if ($this->runtime->hasConstant('INTL_ICU_VERSION')) { if ($this->runtime->hasConstant('INTL_ICU_VERSION')) {
$this->addLibrary('icu', $this->runtime->getConstant('INTL_ICU_VERSION'), $description); $this->addLibrary('icu', $this->runtime->getConstant('INTL_ICU_VERSION'), $description);
} elseif (preg_match('/^ICU version => (?<version>.+)$/im', $info, $matches)) { } elseif (Preg::isMatch('/^ICU version => (?<version>.+)$/im', $info, $matches)) {
$this->addLibrary('icu', $matches['version'], $description); $this->addLibrary('icu', $matches['version'], $description);
} }
// ICU TZData version => 2019c // ICU TZData version => 2019c
if (preg_match('/^ICU TZData version => (?<version>.*)$/im', $info, $zoneinfoMatches)) { if (Preg::isMatch('/^ICU TZData version => (?<version>.*)$/im', $info, $zoneinfoMatches)) {
$this->addLibrary('icu-zoneinfo', Version::parseZoneinfoVersion($zoneinfoMatches['version']), 'zoneinfo ("Olson") database for icu'); $this->addLibrary('icu-zoneinfo', Version::parseZoneinfoVersion($zoneinfoMatches['version']), 'zoneinfo ("Olson") database for icu');
} }
@ -345,7 +346,7 @@ class PlatformRepository extends ArrayRepository
$imageMagickVersion = $this->runtime->construct('Imagick')->getVersion(); $imageMagickVersion = $this->runtime->construct('Imagick')->getVersion();
// 6.x: ImageMagick 6.2.9 08/24/06 Q16 http://www.imagemagick.org // 6.x: ImageMagick 6.2.9 08/24/06 Q16 http://www.imagemagick.org
// 7.x: ImageMagick 7.0.8-34 Q16 x86_64 2019-03-23 https://imagemagick.org // 7.x: ImageMagick 7.0.8-34 Q16 x86_64 2019-03-23 https://imagemagick.org
preg_match('/^ImageMagick (?<version>[\d.]+)(?:-(?<patch>\d+))?/', $imageMagickVersion['versionString'], $matches); Preg::match('/^ImageMagick (?<version>[\d.]+)(?:-(?<patch>\d+))?/', $imageMagickVersion['versionString'], $matches);
$version = $matches['version']; $version = $matches['version'];
if (isset($matches['patch'])) { if (isset($matches['patch'])) {
$version .= '.'.$matches['patch']; $version .= '.'.$matches['patch'];
@ -357,7 +358,7 @@ class PlatformRepository extends ArrayRepository
case 'ldap': case 'ldap':
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
if (preg_match('/^Vendor Version => (?<versionId>\d+)$/im', $info, $matches) && preg_match('/^Vendor Name => (?<vendor>.+)$/im', $info, $vendorMatches)) { if (Preg::isMatch('/^Vendor Version => (?<versionId>\d+)$/im', $info, $matches) && Preg::isMatch('/^Vendor Name => (?<vendor>.+)$/im', $info, $vendorMatches)) {
$this->addLibrary($name.'-'.strtolower($vendorMatches['vendor']), Version::convertOpenldapVersionId($matches['versionId']), $vendorMatches['vendor'].' version of ldap'); $this->addLibrary($name.'-'.strtolower($vendorMatches['vendor']), Version::convertOpenldapVersionId($matches['versionId']), $vendorMatches['vendor'].' version of ldap');
} }
break; break;
@ -375,7 +376,7 @@ class PlatformRepository extends ArrayRepository
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
// libmbfl version => 1.3.2 // libmbfl version => 1.3.2
if (preg_match('/^libmbfl version => (?<version>.+)$/im', $info, $libmbflMatches)) { if (Preg::isMatch('/^libmbfl version => (?<version>.+)$/im', $info, $libmbflMatches)) {
$this->addLibrary($name.'-libmbfl', $libmbflMatches['version'], 'mbstring libmbfl version'); $this->addLibrary($name.'-libmbfl', $libmbflMatches['version'], 'mbstring libmbfl version');
} }
@ -384,7 +385,7 @@ class PlatformRepository extends ArrayRepository
// Multibyte regex (oniguruma) version => 5.9.5 // Multibyte regex (oniguruma) version => 5.9.5
// oniguruma version => 6.9.0 // oniguruma version => 6.9.0
} elseif (preg_match('/^(?:oniguruma|Multibyte regex \(oniguruma\)) version => (?<version>.+)$/im', $info, $onigurumaMatches)) { } elseif (Preg::isMatch('/^(?:oniguruma|Multibyte regex \(oniguruma\)) version => (?<version>.+)$/im', $info, $onigurumaMatches)) {
$this->addLibrary($name.'-oniguruma', $onigurumaMatches['version'], 'mbstring oniguruma version'); $this->addLibrary($name.'-oniguruma', $onigurumaMatches['version'], 'mbstring oniguruma version');
} }
@ -394,26 +395,26 @@ class PlatformRepository extends ArrayRepository
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
// libmemcached version => 1.0.18 // libmemcached version => 1.0.18
if (preg_match('/^libmemcached version => (?<version>.+)$/im', $info, $matches)) { if (Preg::isMatch('/^libmemcached version => (?<version>.+)$/im', $info, $matches)) {
$this->addLibrary($name.'-libmemcached', $matches['version'], 'libmemcached version'); $this->addLibrary($name.'-libmemcached', $matches['version'], 'libmemcached version');
} }
break; break;
case 'openssl': case 'openssl':
// OpenSSL 1.1.1g 21 Apr 2020 // OpenSSL 1.1.1g 21 Apr 2020
if (preg_match('{^(?:OpenSSL|LibreSSL)?\s*(?<version>\S+)}i', $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), $matches)) { if (Preg::isMatch('{^(?:OpenSSL|LibreSSL)?\s*(?<version>\S+)}i', $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), $matches)) {
$parsedVersion = Version::parseOpenssl($matches['version'], $isFips); $parsedVersion = Version::parseOpenssl($matches['version'], $isFips);
$this->addLibrary($name.($isFips ? '-fips' : ''), $parsedVersion, $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), array(), $isFips ? array($name) : array()); $this->addLibrary($name.($isFips ? '-fips' : ''), $parsedVersion, $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), array(), $isFips ? array($name) : array());
} }
break; break;
case 'pcre': case 'pcre':
$this->addLibrary($name, preg_replace('{^(\S+).*}', '$1', $this->runtime->getConstant('PCRE_VERSION'))); $this->addLibrary($name, Preg::replace('{^(\S+).*}', '$1', $this->runtime->getConstant('PCRE_VERSION')));
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
// PCRE Unicode Version => 12.1.0 // PCRE Unicode Version => 12.1.0
if (preg_match('/^PCRE Unicode Version => (?<version>.+)$/im', $info, $pcreUnicodeMatches)) { if (Preg::isMatch('/^PCRE Unicode Version => (?<version>.+)$/im', $info, $pcreUnicodeMatches)) {
$this->addLibrary($name.'-unicode', $pcreUnicodeMatches['version'], 'PCRE Unicode version support'); $this->addLibrary($name.'-unicode', $pcreUnicodeMatches['version'], 'PCRE Unicode version support');
} }
@ -423,7 +424,7 @@ class PlatformRepository extends ArrayRepository
case 'pdo_mysql': case 'pdo_mysql':
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
if (preg_match('/^(?:Client API version|Version) => mysqlnd (?<version>.+?) /mi', $info, $matches)) { if (Preg::isMatch('/^(?:Client API version|Version) => mysqlnd (?<version>.+?) /mi', $info, $matches)) {
$this->addLibrary($name.'-mysqlnd', $matches['version'], 'mysqlnd library version for '.$name); $this->addLibrary($name.'-mysqlnd', $matches['version'], 'mysqlnd library version for '.$name);
} }
break; break;
@ -431,11 +432,11 @@ class PlatformRepository extends ArrayRepository
case 'mongodb': case 'mongodb':
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
if (preg_match('/^libmongoc bundled version => (?<version>.+)$/im', $info, $libmongocMatches)) { if (Preg::isMatch('/^libmongoc bundled version => (?<version>.+)$/im', $info, $libmongocMatches)) {
$this->addLibrary($name.'-libmongoc', $libmongocMatches['version'], 'libmongoc version of mongodb'); $this->addLibrary($name.'-libmongoc', $libmongocMatches['version'], 'libmongoc version of mongodb');
} }
if (preg_match('/^libbson bundled version => (?<version>.+)$/im', $info, $libbsonMatches)) { if (Preg::isMatch('/^libbson bundled version => (?<version>.+)$/im', $info, $libbsonMatches)) {
$this->addLibrary($name.'-libbson', $libbsonMatches['version'], 'libbson version of mongodb'); $this->addLibrary($name.'-libbson', $libbsonMatches['version'], 'libbson version of mongodb');
} }
break; break;
@ -444,7 +445,7 @@ class PlatformRepository extends ArrayRepository
case 'pdo_pgsql': case 'pdo_pgsql':
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
if (preg_match('/^PostgreSQL\(libpq\) Version => (?<version>.*)$/im', $info, $matches)) { if (Preg::isMatch('/^PostgreSQL\(libpq\) Version => (?<version>.*)$/im', $info, $matches)) {
$this->addLibrary($name.'-libpq', $matches['version'], 'libpq for '.$name); $this->addLibrary($name.'-libpq', $matches['version'], 'libpq for '.$name);
} }
break; break;
@ -460,7 +461,7 @@ class PlatformRepository extends ArrayRepository
case 'pdo_sqlite': case 'pdo_sqlite':
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
if (preg_match('/^SQLite Library => (?<version>.+)$/im', $info, $matches)) { if (Preg::isMatch('/^SQLite Library => (?<version>.+)$/im', $info, $matches)) {
$this->addLibrary($name.'-sqlite', $matches['version']); $this->addLibrary($name.'-sqlite', $matches['version']);
} }
break; break;
@ -468,7 +469,7 @@ class PlatformRepository extends ArrayRepository
case 'ssh2': case 'ssh2':
$info = $this->runtime->getExtensionInfo($name); $info = $this->runtime->getExtensionInfo($name);
if (preg_match('/^libssh2 version => (?<version>.+)$/im', $info, $matches)) { if (Preg::isMatch('/^libssh2 version => (?<version>.+)$/im', $info, $matches)) {
$this->addLibrary($name.'-libssh2', $matches['version']); $this->addLibrary($name.'-libssh2', $matches['version']);
} }
break; break;
@ -477,7 +478,7 @@ class PlatformRepository extends ArrayRepository
$this->addLibrary('libxslt', $this->runtime->getConstant('LIBXSLT_DOTTED_VERSION'), null, array('xsl')); $this->addLibrary('libxslt', $this->runtime->getConstant('LIBXSLT_DOTTED_VERSION'), null, array('xsl'));
$info = $this->runtime->getExtensionInfo('xsl'); $info = $this->runtime->getExtensionInfo('xsl');
if (preg_match('/^libxslt compiled against libxml Version => (?<version>.+)$/im', $info, $matches)) { if (Preg::isMatch('/^libxslt compiled against libxml Version => (?<version>.+)$/im', $info, $matches)) {
$this->addLibrary('libxslt-libxml', $matches['version'], 'libxml version libxslt is compiled against'); $this->addLibrary('libxslt-libxml', $matches['version'], 'libxml version libxslt is compiled against');
} }
break; break;
@ -485,7 +486,7 @@ class PlatformRepository extends ArrayRepository
case 'yaml': case 'yaml':
$info = $this->runtime->getExtensionInfo('yaml'); $info = $this->runtime->getExtensionInfo('yaml');
if (preg_match('/^LibYAML Version => (?<version>.+)$/im', $info, $matches)) { if (Preg::isMatch('/^LibYAML Version => (?<version>.+)$/im', $info, $matches)) {
$this->addLibrary($name.'-libyaml', $matches['version'], 'libyaml version of yaml'); $this->addLibrary($name.'-libyaml', $matches['version'], 'libyaml version of yaml');
} }
break; break;
@ -501,7 +502,7 @@ class PlatformRepository extends ArrayRepository
$this->addLibrary($name, $this->runtime->getConstant('ZLIB_VERSION')); $this->addLibrary($name, $this->runtime->getConstant('ZLIB_VERSION'));
// Linked Version => 1.2.8 // Linked Version => 1.2.8
} elseif (preg_match('/^Linked Version => (?<version>.+)$/im', $this->runtime->getExtensionInfo($name), $matches)) { } elseif (Preg::isMatch('/^Linked Version => (?<version>.+)$/im', $this->runtime->getExtensionInfo($name), $matches)) {
$this->addLibrary($name, $matches['version']); $this->addLibrary($name, $matches['version']);
} }
break; break;
@ -517,7 +518,7 @@ class PlatformRepository extends ArrayRepository
$prettyVersion = $hhvmVersion; $prettyVersion = $hhvmVersion;
$version = $this->versionParser->normalize($prettyVersion); $version = $this->versionParser->normalize($prettyVersion);
} catch (\UnexpectedValueException $e) { } catch (\UnexpectedValueException $e) {
$prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', $hhvmVersion); $prettyVersion = Preg::replace('#^([^~+-]+).*$#', '$1', $hhvmVersion);
$version = $this->versionParser->normalize($prettyVersion); $version = $this->versionParser->normalize($prettyVersion);
} }
@ -625,7 +626,7 @@ class PlatformRepository extends ArrayRepository
$version = $this->versionParser->normalize($prettyVersion); $version = $this->versionParser->normalize($prettyVersion);
} catch (\UnexpectedValueException $e) { } catch (\UnexpectedValueException $e) {
$extraDescription = ' (actual version: '.$prettyVersion.')'; $extraDescription = ' (actual version: '.$prettyVersion.')';
if (preg_match('{^(\d+\.\d+\.\d+(?:\.\d+)?)}', $prettyVersion, $match)) { if (Preg::isMatch('{^(\d+\.\d+\.\d+(?:\.\d+)?)}', $prettyVersion, $match)) {
$prettyVersion = $match[1]; $prettyVersion = $match[1];
} else { } else {
$prettyVersion = '0'; $prettyVersion = '0';
@ -709,7 +710,7 @@ class PlatformRepository extends ArrayRepository
return $cache[$name]; return $cache[$name];
} }
return $cache[$name] = (bool) preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name); return $cache[$name] = Preg::isMatch(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name);
} }
/** /**

View File

@ -16,6 +16,7 @@ use Composer\Factory;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Config; use Composer\Config;
use Composer\EventDispatcher\EventDispatcher; use Composer\EventDispatcher\EventDispatcher;
use Composer\Pcre\Preg;
use Composer\Util\HttpDownloader; use Composer\Util\HttpDownloader;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
@ -179,7 +180,7 @@ class RepositoryFactory
*/ */
public static function generateRepositoryName($index, array $repo, array $existingRepos) public static function generateRepositoryName($index, array $repo, array $existingRepos)
{ {
$name = is_int($index) && isset($repo['url']) ? preg_replace('{^https?://}i', '', $repo['url']) : $index; $name = is_int($index) && isset($repo['url']) ? Preg::replace('{^https?://}i', '', $repo['url']) : $index;
while (isset($existingRepos[$name])) { while (isset($existingRepos[$name])) {
$name .= '2'; $name .= '2';
} }

View File

@ -14,6 +14,7 @@ namespace Composer\Repository\Vcs;
use Composer\Cache; use Composer\Cache;
use Composer\Config; use Composer\Config;
use Composer\Pcre\Preg;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
@ -54,7 +55,7 @@ class FossilDriver extends VcsDriver
throw new \RuntimeException('FossilDriver requires a usable cache directory, and it looks like you set it to be disabled'); throw new \RuntimeException('FossilDriver requires a usable cache directory, and it looks like you set it to be disabled');
} }
$localName = preg_replace('{[^a-z0-9]}i', '-', $this->url); $localName = Preg::replace('{[^a-z0-9]}i', '-', $this->url);
$this->repoFile = $this->config->get('cache-repo-dir') . '/' . $localName . '.fossil'; $this->repoFile = $this->config->get('cache-repo-dir') . '/' . $localName . '.fossil';
$this->checkoutDir = $this->config->get('cache-vcs-dir') . '/' . $localName . '/'; $this->checkoutDir = $this->config->get('cache-vcs-dir') . '/' . $localName . '/';
@ -208,7 +209,7 @@ class FossilDriver extends VcsDriver
$this->process->execute('fossil branch list', $output, $this->checkoutDir); $this->process->execute('fossil branch list', $output, $this->checkoutDir);
foreach ($this->process->splitLines($output) as $branch) { foreach ($this->process->splitLines($output) as $branch) {
$branch = trim(preg_replace('/^\*/', '', trim($branch))); $branch = trim(Preg::replace('/^\*/', '', trim($branch)));
$branches[$branch] = $branch; $branches[$branch] = $branch;
} }
@ -223,11 +224,11 @@ class FossilDriver extends VcsDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (preg_match('#(^(?:https?|ssh)://(?:[^@]@)?(?:chiselapp\.com|fossil\.))#i', $url)) { if (Preg::isMatch('#(^(?:https?|ssh)://(?:[^@]@)?(?:chiselapp\.com|fossil\.))#i', $url)) {
return true; return true;
} }
if (preg_match('!/fossil/|\.fossil!', $url)) { if (Preg::isMatch('!/fossil/|\.fossil!', $url)) {
return true; return true;
} }

View File

@ -17,6 +17,7 @@ use Composer\IO\IOInterface;
use Composer\Cache; use Composer\Cache;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Pcre\Preg;
use Composer\Util\Bitbucket; use Composer\Util\Bitbucket;
use Composer\Util\Http\Response; use Composer\Util\Http\Response;
@ -60,7 +61,7 @@ class GitBitbucketDriver extends VcsDriver
*/ */
public function initialize() public function initialize()
{ {
preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)?$#i', $this->url, $match); Preg::match('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)?$#i', $this->url, $match);
$this->owner = $match[1]; $this->owner = $match[1];
$this->repository = $match[2]; $this->repository = $match[2];
$this->originUrl = 'bitbucket.org'; $this->originUrl = 'bitbucket.org';
@ -463,7 +464,7 @@ class GitBitbucketDriver extends VcsDriver
if ($cloneLink['name'] === 'https') { if ($cloneLink['name'] === 'https') {
// Format: https://(user@)bitbucket.org/{user}/{repo} // Format: https://(user@)bitbucket.org/{user}/{repo}
// Strip username from URL (only present in clone URL's for private repositories) // Strip username from URL (only present in clone URL's for private repositories)
$this->cloneHttpsUrl = preg_replace('/https:\/\/([^@]+@)?/', 'https://', $cloneLink['href']); $this->cloneHttpsUrl = Preg::replace('/https:\/\/([^@]+@)?/', 'https://', $cloneLink['href']);
} }
} }
} }
@ -525,7 +526,7 @@ class GitBitbucketDriver extends VcsDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (!preg_match('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)?$#i', $url)) { if (!Preg::isMatch('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)?$#i', $url)) {
return false; return false;
} }

View File

@ -12,6 +12,7 @@
namespace Composer\Repository\Vcs; namespace Composer\Repository\Vcs;
use Composer\Pcre\Preg;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Url; use Composer\Util\Url;
@ -40,7 +41,7 @@ class GitDriver extends VcsDriver
public function initialize() public function initialize()
{ {
if (Filesystem::isLocalPath($this->url)) { if (Filesystem::isLocalPath($this->url)) {
$this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url); $this->url = Preg::replace('{[\\/]\.git/?$}', '', $this->url);
if (!is_dir($this->url)) { if (!is_dir($this->url)) {
throw new \RuntimeException('Failed to read package information from '.$this->url.' as the path does not exist'); throw new \RuntimeException('Failed to read package information from '.$this->url.' as the path does not exist');
} }
@ -51,7 +52,7 @@ class GitDriver extends VcsDriver
throw new \RuntimeException('GitDriver requires a usable cache directory, and it looks like you set it to be disabled'); throw new \RuntimeException('GitDriver requires a usable cache directory, and it looks like you set it to be disabled');
} }
$this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/'; $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . Preg::replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
GitUtil::cleanEnv(); GitUtil::cleanEnv();
@ -62,7 +63,7 @@ class GitDriver extends VcsDriver
throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.dirname($this->repoDir).'" directory is not writable by the current user.'); throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.dirname($this->repoDir).'" directory is not writable by the current user.');
} }
if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) { if (Preg::isMatch('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) {
throw new \InvalidArgumentException('The source URL '.$this->url.' is invalid, ssh URLs should have a port number after ":".'."\n".'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.'); throw new \InvalidArgumentException('The source URL '.$this->url.' is invalid, ssh URLs should have a port number after ":".'."\n".'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.');
} }
@ -80,7 +81,7 @@ class GitDriver extends VcsDriver
$this->getTags(); $this->getTags();
$this->getBranches(); $this->getBranches();
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', Url::sanitize($cacheUrl))); $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($cacheUrl)));
$this->cache->setReadOnly($this->config->get('cache-read-only')); $this->cache->setReadOnly($this->config->get('cache-read-only'));
} }
@ -97,7 +98,7 @@ class GitDriver extends VcsDriver
$branches = $this->process->splitLines($output); $branches = $this->process->splitLines($output);
if (!in_array('* master', $branches)) { if (!in_array('* master', $branches)) {
foreach ($branches as $branch) { foreach ($branches as $branch) {
if ($branch && preg_match('{^\* +(\S+)}', $branch, $match)) { if ($branch && Preg::isMatch('{^\* +(\S+)}', $branch, $match)) {
$this->rootIdentifier = $match[1]; $this->rootIdentifier = $match[1];
break; break;
} }
@ -170,7 +171,7 @@ class GitDriver extends VcsDriver
$this->process->execute('git show-ref --tags --dereference', $output, $this->repoDir); $this->process->execute('git show-ref --tags --dereference', $output, $this->repoDir);
foreach ($output = $this->process->splitLines($output) as $tag) { foreach ($output = $this->process->splitLines($output) as $tag) {
if ($tag && preg_match('{^([a-f0-9]{40}) refs/tags/(\S+?)(\^\{\})?$}', $tag, $match)) { if ($tag && Preg::isMatch('{^([a-f0-9]{40}) refs/tags/(\S+?)(\^\{\})?$}', $tag, $match)) {
$this->tags[$match[2]] = $match[1]; $this->tags[$match[2]] = $match[1];
} }
} }
@ -189,8 +190,8 @@ class GitDriver extends VcsDriver
$this->process->execute('git branch --no-color --no-abbrev -v', $output, $this->repoDir); $this->process->execute('git branch --no-color --no-abbrev -v', $output, $this->repoDir);
foreach ($this->process->splitLines($output) as $branch) { foreach ($this->process->splitLines($output) as $branch) {
if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) { if ($branch && !Preg::isMatch('{^ *[^/]+/HEAD }', $branch)) {
if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}', $branch, $match)) { if (Preg::isMatch('{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}', $branch, $match)) {
$branches[$match[1]] = $match[2]; $branches[$match[1]] = $match[2];
} }
} }
@ -207,7 +208,7 @@ class GitDriver extends VcsDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (preg_match('#(^git://|\.git/?$|git(?:olite)?@|//git\.|//github.com/)#i', $url)) { if (Preg::isMatch('#(^git://|\.git/?$|git(?:olite)?@|//git\.|//github.com/)#i', $url)) {
return true; return true;
} }

View File

@ -17,6 +17,7 @@ use Composer\Downloader\TransportException;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Cache; use Composer\Cache;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Composer\Util\GitHub; use Composer\Util\GitHub;
use Composer\Util\Http\Response; use Composer\Util\Http\Response;
@ -58,7 +59,7 @@ class GitHubDriver extends VcsDriver
*/ */
public function initialize() public function initialize()
{ {
preg_match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $this->url, $match); Preg::match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $this->url, $match);
$this->owner = $match[3]; $this->owner = $match[3];
$this->repository = $match[4]; $this->repository = $match[4];
$this->originUrl = strtolower(!empty($match[1]) ? $match[1] : $match[2]); $this->originUrl = strtolower(!empty($match[1]) ? $match[1] : $match[2]);
@ -227,20 +228,20 @@ class GitHubDriver extends VcsDriver
$result = array(); $result = array();
$key = null; $key = null;
foreach (preg_split('{\r?\n}', $funding) as $line) { foreach (Preg::split('{\r?\n}', $funding) as $line) {
$line = trim($line); $line = trim($line);
if (preg_match('{^(\w+)\s*:\s*(.+)$}', $line, $match)) { if (Preg::isMatch('{^(\w+)\s*:\s*(.+)$}', $line, $match)) {
if (preg_match('{^\[(.*)\](?:\s*#.*)?$}', $match[2], $match2)) { if (Preg::isMatch('{^\[(.*)\](?:\s*#.*)?$}', $match[2], $match2)) {
foreach (array_map('trim', preg_split('{[\'"]?\s*,\s*[\'"]?}', $match2[1])) as $item) { foreach (array_map('trim', Preg::split('{[\'"]?\s*,\s*[\'"]?}', $match2[1])) as $item) {
$result[] = array('type' => $match[1], 'url' => trim($item, '"\' ')); $result[] = array('type' => $match[1], 'url' => trim($item, '"\' '));
} }
} elseif (preg_match('{^([^#].*?)(\s+#.*)?$}', $match[2], $match2)) { } elseif (Preg::isMatch('{^([^#].*?)(\s+#.*)?$}', $match[2], $match2)) {
$result[] = array('type' => $match[1], 'url' => trim($match2[1], '"\' ')); $result[] = array('type' => $match[1], 'url' => trim($match2[1], '"\' '));
} }
$key = null; $key = null;
} elseif (preg_match('{^(\w+)\s*:\s*#\s*$}', $line, $match)) { } elseif (Preg::isMatch('{^(\w+)\s*:\s*#\s*$}', $line, $match)) {
$key = $match[1]; $key = $match[1];
} elseif ($key && preg_match('{^-\s*(.+)(\s+#.*)?$}', $line, $match)) { } elseif ($key && Preg::isMatch('{^-\s*(.+)(\s+#.*)?$}', $line, $match)) {
$result[] = array('type' => $key, 'url' => trim($match[1], '"\' ')); $result[] = array('type' => $key, 'url' => trim($match[1], '"\' '));
} }
} }
@ -377,12 +378,12 @@ class GitHubDriver extends VcsDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (!preg_match('#^((?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $url, $matches)) { if (!Preg::isMatch('#^((?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/(.+?)(?:\.git|/)?$#', $url, $matches)) {
return false; return false;
} }
$originUrl = !empty($matches[2]) ? $matches[2] : $matches[3]; $originUrl = !empty($matches[2]) ? $matches[2] : $matches[3];
if (!in_array(strtolower(preg_replace('{^www\.}i', '', $originUrl)), $config->get('github-domains'))) { if (!in_array(strtolower(Preg::replace('{^www\.}i', '', $originUrl)), $config->get('github-domains'))) {
return false; return false;
} }
@ -608,7 +609,7 @@ class GitHubDriver extends VcsDriver
$links = explode(',', $header); $links = explode(',', $header);
foreach ($links as $link) { foreach ($links as $link) {
if (preg_match('{<(.+?)>; *rel="next"}', $link, $match)) { if (Preg::isMatch('{<(.+?)>; *rel="next"}', $link, $match)) {
return $match[1]; return $match[1];
} }
} }

View File

@ -17,6 +17,7 @@ use Composer\Cache;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Pcre\Preg;
use Composer\Util\HttpDownloader; use Composer\Util\HttpDownloader;
use Composer\Util\GitLab; use Composer\Util\GitLab;
use Composer\Util\Http\Response; use Composer\Util\Http\Response;
@ -92,7 +93,7 @@ class GitLabDriver extends VcsDriver
*/ */
public function initialize() public function initialize()
{ {
if (!preg_match(self::URL_REGEX, $this->url, $match)) { if (!Preg::isMatch(self::URL_REGEX, $this->url, $match)) {
throw new \InvalidArgumentException('The URL provided is invalid. It must be the HTTP URL of a GitLab project.'); throw new \InvalidArgumentException('The URL provided is invalid. It must be the HTTP URL of a GitLab project.');
} }
@ -119,7 +120,7 @@ class GitLabDriver extends VcsDriver
} }
$this->namespace = implode('/', $urlParts); $this->namespace = implode('/', $urlParts);
$this->repository = preg_replace('#(\.git)$#', '', $match['repo']); $this->repository = Preg::replace('#(\.git)$#', '', $match['repo']);
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->namespace.'/'.$this->repository); $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->namespace.'/'.$this->repository);
$this->cache->setReadOnly($this->config->get('cache-read-only')); $this->cache->setReadOnly($this->config->get('cache-read-only'));
@ -186,7 +187,7 @@ class GitLabDriver extends VcsDriver
} }
// Convert the root identifier to a cacheable commit id // Convert the root identifier to a cacheable commit id
if (!preg_match('{[a-f0-9]{40}}i', $identifier)) { if (!Preg::isMatch('{[a-f0-9]{40}}i', $identifier)) {
$branches = $this->getBranches(); $branches = $this->getBranches();
if (isset($branches[$identifier])) { if (isset($branches[$identifier])) {
$identifier = $branches[$identifier]; $identifier = $branches[$identifier];
@ -560,7 +561,7 @@ class GitLabDriver extends VcsDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (!preg_match(self::URL_REGEX, $url, $match)) { if (!Preg::isMatch(self::URL_REGEX, $url, $match)) {
return false; return false;
} }
@ -590,7 +591,7 @@ class GitLabDriver extends VcsDriver
$links = explode(',', $header); $links = explode(',', $header);
foreach ($links as $link) { foreach ($links as $link) {
if (preg_match('{<(.+?)>; *rel="next"}', $link, $match)) { if (Preg::isMatch('{<(.+?)>; *rel="next"}', $link, $match)) {
return $match[1]; return $match[1];
} }
} }
@ -625,7 +626,7 @@ class GitLabDriver extends VcsDriver
while (null !== ($part = array_shift($urlParts))) { while (null !== ($part = array_shift($urlParts))) {
$guessedDomain .= '/' . $part; $guessedDomain .= '/' . $part;
if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array(preg_replace('{:\d+}', '', $guessedDomain), $configuredDomains))) { if (in_array($guessedDomain, $configuredDomains) || ($portNumber && in_array(Preg::replace('{:\d+}', '', $guessedDomain), $configuredDomains))) {
return $guessedDomain; return $guessedDomain;
} }
} }

View File

@ -14,6 +14,7 @@ namespace Composer\Repository\Vcs;
use Composer\Config; use Composer\Config;
use Composer\Cache; use Composer\Cache;
use Composer\Pcre\Preg;
use Composer\Util\Hg as HgUtils; use Composer\Util\Hg as HgUtils;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
@ -46,7 +47,7 @@ class HgDriver extends VcsDriver
} }
$cacheDir = $this->config->get('cache-vcs-dir'); $cacheDir = $this->config->get('cache-vcs-dir');
$this->repoDir = $cacheDir . '/' . preg_replace('{[^a-z0-9]}i', '-', $this->url) . '/'; $this->repoDir = $cacheDir . '/' . Preg::replace('{[^a-z0-9]}i', '-', $this->url) . '/';
$fs = new Filesystem(); $fs = new Filesystem();
$fs->ensureDirectoryExists($cacheDir); $fs->ensureDirectoryExists($cacheDir);
@ -162,7 +163,7 @@ class HgDriver extends VcsDriver
$this->process->execute('hg tags', $output, $this->repoDir); $this->process->execute('hg tags', $output, $this->repoDir);
foreach ($this->process->splitLines($output) as $tag) { foreach ($this->process->splitLines($output) as $tag) {
if ($tag && preg_match('(^([^\s]+)\s+\d+:(.*)$)', $tag, $match)) { if ($tag && Preg::isMatch('(^([^\s]+)\s+\d+:(.*)$)', $tag, $match)) {
$tags[$match[1]] = $match[2]; $tags[$match[1]] = $match[2];
} }
} }
@ -185,14 +186,14 @@ class HgDriver extends VcsDriver
$this->process->execute('hg branches', $output, $this->repoDir); $this->process->execute('hg branches', $output, $this->repoDir);
foreach ($this->process->splitLines($output) as $branch) { foreach ($this->process->splitLines($output) as $branch) {
if ($branch && preg_match('(^([^\s]+)\s+\d+:([a-f0-9]+))', $branch, $match)) { if ($branch && Preg::isMatch('(^([^\s]+)\s+\d+:([a-f0-9]+))', $branch, $match)) {
$branches[$match[1]] = $match[2]; $branches[$match[1]] = $match[2];
} }
} }
$this->process->execute('hg bookmarks', $output, $this->repoDir); $this->process->execute('hg bookmarks', $output, $this->repoDir);
foreach ($this->process->splitLines($output) as $branch) { foreach ($this->process->splitLines($output) as $branch) {
if ($branch && preg_match('(^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$)', $branch, $match)) { if ($branch && Preg::isMatch('(^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$)', $branch, $match)) {
$bookmarks[$match[1]] = $match[2]; $bookmarks[$match[1]] = $match[2];
} }
} }
@ -209,7 +210,7 @@ class HgDriver extends VcsDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if (preg_match('#(^(?:https?|ssh)://(?:[^@]+@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) { if (Preg::isMatch('#(^(?:https?|ssh)://(?:[^@]+@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) {
return true; return true;
} }

View File

@ -15,6 +15,7 @@ namespace Composer\Repository\Vcs;
use Composer\Config; use Composer\Config;
use Composer\Cache; use Composer\Cache;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Util\Perforce; use Composer\Util\Perforce;
@ -160,7 +161,7 @@ class PerforceDriver extends VcsDriver
*/ */
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
if ($deep || preg_match('#\b(perforce|p4)\b#i', $url)) { if ($deep || Preg::isMatch('#\b(perforce|p4)\b#i', $url)) {
return Perforce::checkServerExists($url, new ProcessExecutor($io)); return Perforce::checkServerExists($url, new ProcessExecutor($io));
} }

View File

@ -15,6 +15,7 @@ namespace Composer\Repository\Vcs;
use Composer\Cache; use Composer\Cache;
use Composer\Config; use Composer\Config;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Pcre\Preg;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Url; use Composer\Util\Url;
@ -82,7 +83,7 @@ class SvnDriver extends VcsDriver
$this->baseUrl = substr($this->url, 0, $pos); $this->baseUrl = substr($this->url, 0, $pos);
} }
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', Url::sanitize($this->baseUrl))); $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($this->baseUrl)));
$this->cache->setReadOnly($this->config->get('cache-read-only')); $this->cache->setReadOnly($this->config->get('cache-read-only'));
$this->getBranches(); $this->getBranches();
@ -126,7 +127,7 @@ class SvnDriver extends VcsDriver
*/ */
protected function shouldCache($identifier) protected function shouldCache($identifier)
{ {
return $this->cache && preg_match('{@\d+$}', $identifier); return $this->cache && Preg::isMatch('{@\d+$}', $identifier);
} }
/** /**
@ -168,7 +169,7 @@ class SvnDriver extends VcsDriver
{ {
$identifier = '/' . trim($identifier, '/') . '/'; $identifier = '/' . trim($identifier, '/') . '/';
preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match); Preg::match('{^(.+?)(@\d+)?/$}', $identifier, $match);
if (!empty($match[2])) { if (!empty($match[2])) {
$path = $match[1]; $path = $match[1];
$rev = $match[2]; $rev = $match[2];
@ -197,7 +198,7 @@ class SvnDriver extends VcsDriver
{ {
$identifier = '/' . trim($identifier, '/') . '/'; $identifier = '/' . trim($identifier, '/') . '/';
preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match); Preg::match('{^(.+?)(@\d+)?/$}', $identifier, $match);
if (!empty($match[2])) { if (!empty($match[2])) {
$path = $match[1]; $path = $match[1];
$rev = $match[2]; $rev = $match[2];
@ -208,7 +209,7 @@ class SvnDriver extends VcsDriver
$output = $this->execute('svn info', $this->baseUrl . $path . $rev); $output = $this->execute('svn info', $this->baseUrl . $path . $rev);
foreach ($this->process->splitLines($output) as $line) { foreach ($this->process->splitLines($output) as $line) {
if ($line && preg_match('{^Last Changed Date: ([^(]+)}', $line, $match)) { if ($line && Preg::isMatch('{^Last Changed Date: ([^(]+)}', $line, $match)) {
return new \DateTime($match[1], new \DateTimeZone('UTC')); return new \DateTime($match[1], new \DateTimeZone('UTC'));
} }
} }
@ -229,7 +230,7 @@ class SvnDriver extends VcsDriver
if ($output) { if ($output) {
foreach ($this->process->splitLines($output) as $line) { foreach ($this->process->splitLines($output) as $line) {
$line = trim($line); $line = trim($line);
if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { if ($line && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
if (isset($match[1], $match[2]) && $match[2] !== './') { if (isset($match[1], $match[2]) && $match[2] !== './') {
$tags[rtrim($match[2], '/')] = $this->buildIdentifier( $tags[rtrim($match[2], '/')] = $this->buildIdentifier(
'/' . $this->tagsPath . '/' . $match[2], '/' . $this->tagsPath . '/' . $match[2],
@ -265,7 +266,7 @@ class SvnDriver extends VcsDriver
if ($output) { if ($output) {
foreach ($this->process->splitLines($output) as $line) { foreach ($this->process->splitLines($output) as $line) {
$line = trim($line); $line = trim($line);
if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { if ($line && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
if (isset($match[1], $match[2]) && $match[2] === './') { if (isset($match[1], $match[2]) && $match[2] === './') {
$branches['trunk'] = $this->buildIdentifier( $branches['trunk'] = $this->buildIdentifier(
'/' . $this->trunkPath, '/' . $this->trunkPath,
@ -284,7 +285,7 @@ class SvnDriver extends VcsDriver
if ($output) { if ($output) {
foreach ($this->process->splitLines(trim($output)) as $line) { foreach ($this->process->splitLines(trim($output)) as $line) {
$line = trim($line); $line = trim($line);
if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { if ($line && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
if (isset($match[1], $match[2]) && $match[2] !== './') { if (isset($match[1], $match[2]) && $match[2] !== './') {
$branches[rtrim($match[2], '/')] = $this->buildIdentifier( $branches[rtrim($match[2], '/')] = $this->buildIdentifier(
'/' . $this->branchesPath . '/' . $match[2], '/' . $this->branchesPath . '/' . $match[2],
@ -308,7 +309,7 @@ class SvnDriver extends VcsDriver
public static function supports(IOInterface $io, Config $config, $url, $deep = false) public static function supports(IOInterface $io, Config $config, $url, $deep = false)
{ {
$url = self::normalizeUrl($url); $url = self::normalizeUrl($url);
if (preg_match('#(^svn://|^svn\+ssh://|svn\.)#i', $url)) { if (Preg::isMatch('#(^svn://|^svn\+ssh://|svn\.)#i', $url)) {
return true; return true;
} }

View File

@ -17,6 +17,7 @@ use Composer\Downloader\TransportException;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Pcre\Preg;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Util\HttpDownloader; use Composer\Util\HttpDownloader;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
@ -80,7 +81,7 @@ abstract class VcsDriver implements VcsDriverInterface
*/ */
protected function shouldCache($identifier) protected function shouldCache($identifier)
{ {
return $this->cache && preg_match('{^[a-f0-9]{40}$}iD', $identifier); return $this->cache && Preg::isMatch('{^[a-f0-9]{40}$}iD', $identifier);
} }
/** /**

View File

@ -13,6 +13,7 @@
namespace Composer\Repository; namespace Composer\Repository;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Pcre\Preg;
use Composer\Repository\Vcs\VcsDriverInterface; use Composer\Repository\Vcs\VcsDriverInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
@ -270,8 +271,8 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
} }
// make sure tag packages have no -dev flag // make sure tag packages have no -dev flag
$data['version'] = preg_replace('{[.-]?dev$}i', '', $data['version']); $data['version'] = Preg::replace('{[.-]?dev$}i', '', $data['version']);
$data['version_normalized'] = preg_replace('{(^dev-|[.-]?dev$)}i', '', $data['version_normalized']); $data['version_normalized'] = Preg::replace('{(^dev-|[.-]?dev$)}i', '', $data['version_normalized']);
// make sure tag do not contain the default-branch marker // make sure tag do not contain the default-branch marker
unset($data['default-branch']); unset($data['default-branch']);
@ -279,7 +280,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
// broken package, version doesn't match tag // broken package, version doesn't match tag
if ($data['version_normalized'] !== $parsedTag) { if ($data['version_normalized'] !== $parsedTag) {
if ($isVeryVerbose) { if ($isVeryVerbose) {
if (preg_match('{(^dev-|[.-]?dev$)}i', $parsedTag)) { if (Preg::isMatch('{(^dev-|[.-]?dev$)}i', $parsedTag)) {
$this->io->writeError('<warning>Skipped tag '.$tag.', invalid tag name, tags can not use dev prefixes or suffixes</warning>'); $this->io->writeError('<warning>Skipped tag '.$tag.', invalid tag name, tags can not use dev prefixes or suffixes</warning>');
} else { } else {
$this->io->writeError('<warning>Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json</warning>'); $this->io->writeError('<warning>Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json</warning>');
@ -348,7 +349,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt
$version = 'dev-' . $branch; $version = 'dev-' . $branch;
} else { } else {
$prefix = strpos($branch, 'v') === 0 ? 'v' : ''; $prefix = strpos($branch, 'v') === 0 ? 'v' : '';
$version = $prefix . preg_replace('{(\.9{7})+}', '.x', $parsedBranch); $version = $prefix . Preg::replace('{(\.9{7})+}', '.x', $parsedBranch);
} }
$cachedPackage = $this->getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose, $driver->getRootIdentifier() === $branch); $cachedPackage = $this->getCachedPackageVersion($version, $identifier, $isVerbose, $isVeryVerbose, $driver->getRootIdentifier() === $branch);

View File

@ -12,6 +12,8 @@
namespace Composer\SelfUpdate; namespace Composer\SelfUpdate;
use Composer\Pcre\Preg;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*/ */
@ -24,7 +26,7 @@ class Keys
*/ */
public static function fingerprint($path) public static function fingerprint($path)
{ {
$hash = strtoupper(hash('sha256', preg_replace('{\s}', '', file_get_contents($path)))); $hash = strtoupper(hash('sha256', Preg::replace('{\s}', '', file_get_contents($path))));
return implode(' ', array( return implode(' ', array(
substr($hash, 0, 8), substr($hash, 0, 8),

View File

@ -15,6 +15,7 @@ namespace Composer\Util;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Pcre\Preg;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
@ -209,7 +210,7 @@ class AuthHelper
$headers[] = 'Authorization: Bearer '.$auth['username']; $headers[] = 'Authorization: Bearer '.$auth['username'];
} elseif ('github.com' === $origin && 'x-oauth-basic' === $auth['password']) { } elseif ('github.com' === $origin && 'x-oauth-basic' === $auth['password']) {
// only add the access_token if it is actually a github API URL // only add the access_token if it is actually a github API URL
if (preg_match('{^https?://api\.github\.com/}', $url)) { if (Preg::isMatch('{^https?://api\.github\.com/}', $url)) {
$headers[] = 'Authorization: token '.$auth['username']; $headers[] = 'Authorization: token '.$auth['username'];
$authenticationDisplayMessage = 'Using GitHub token authentication'; $authenticationDisplayMessage = 'Using GitHub token authentication';
} }

View File

@ -12,6 +12,8 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\Pcre\Preg;
/** /**
* Composer mirror utilities * Composer mirror utilities
* *
@ -32,7 +34,7 @@ class ComposerMirror
public static function processUrl($mirrorUrl, $packageName, $version, $reference, $type, $prettyVersion = null) public static function processUrl($mirrorUrl, $packageName, $version, $reference, $type, $prettyVersion = null)
{ {
if ($reference) { if ($reference) {
$reference = preg_match('{^([a-f0-9]*|%reference%)$}', $reference) ? $reference : md5($reference); $reference = Preg::isMatch('{^([a-f0-9]*|%reference%)$}', $reference) ? $reference : md5($reference);
} }
$version = strpos($version, '/') === false ? $version : md5($version); $version = strpos($version, '/') === false ? $version : md5($version);
@ -56,12 +58,12 @@ class ComposerMirror
*/ */
public static function processGitUrl($mirrorUrl, $packageName, $url, $type) public static function processGitUrl($mirrorUrl, $packageName, $url, $type)
{ {
if (preg_match('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) { if (Preg::isMatch('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) {
$url = 'gh-'.$match[1].'/'.$match[2]; $url = 'gh-'.$match[1].'/'.$match[2];
} elseif (preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)(?:\.git)?/?$#', $url, $match)) { } elseif (Preg::isMatch('#^https://bitbucket\.org/([^/]+)/(.+?)(?:\.git)?/?$#', $url, $match)) {
$url = 'bb-'.$match[1].'/'.$match[2]; $url = 'bb-'.$match[1].'/'.$match[2];
} else { } else {
$url = preg_replace('{[^a-z0-9_.-]}i', '-', trim($url, '/')); $url = Preg::replace('{[^a-z0-9_.-]}i', '-', trim($url, '/'));
} }
return str_replace( return str_replace(

View File

@ -18,6 +18,7 @@ use Composer\Package\Loader\InvalidPackageException;
use Composer\Json\JsonValidationException; use Composer\Json\JsonValidationException;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Pcre\Preg;
use Composer\Spdx\SpdxLicenses; use Composer\Spdx\SpdxLicenses;
/** /**
@ -93,12 +94,12 @@ class ConfigValidator
foreach ($licenses as $license) { foreach ($licenses as $license) {
$spdxLicense = $licenseValidator->getLicenseByIdentifier($license); $spdxLicense = $licenseValidator->getLicenseByIdentifier($license);
if ($spdxLicense && $spdxLicense[3]) { if ($spdxLicense && $spdxLicense[3]) {
if (preg_match('{^[AL]?GPL-[123](\.[01])?\+$}i', $license)) { if (Preg::isMatch('{^[AL]?GPL-[123](\.[01])?\+$}i', $license)) {
$warnings[] = sprintf( $warnings[] = sprintf(
'License "%s" is a deprecated SPDX license identifier, use "'.str_replace('+', '', $license).'-or-later" instead', 'License "%s" is a deprecated SPDX license identifier, use "'.str_replace('+', '', $license).'-or-later" instead',
$license $license
); );
} elseif (preg_match('{^[AL]?GPL-[123](\.[01])?$}i', $license)) { } elseif (Preg::isMatch('{^[AL]?GPL-[123](\.[01])?$}i', $license)) {
$warnings[] = sprintf( $warnings[] = sprintf(
'License "%s" is a deprecated SPDX license identifier, use "'.$license.'-only" or "'.$license.'-or-later" instead', 'License "%s" is a deprecated SPDX license identifier, use "'.$license.'-only" or "'.$license.'-or-later" instead',
$license $license
@ -117,8 +118,8 @@ class ConfigValidator
$warnings[] = 'The version field is present, it is recommended to leave it out if the package is published on Packagist.'; $warnings[] = 'The version field is present, it is recommended to leave it out if the package is published on Packagist.';
} }
if (!empty($manifest['name']) && preg_match('{[A-Z]}', $manifest['name'])) { if (!empty($manifest['name']) && Preg::isMatch('{[A-Z]}', $manifest['name'])) {
$suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $manifest['name']); $suggestName = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $manifest['name']);
$suggestName = strtolower($suggestName); $suggestName = strtolower($suggestName);
$publishErrors[] = sprintf( $publishErrors[] = sprintf(
@ -162,7 +163,7 @@ class ConfigValidator
$requireDev = isset($manifest['require-dev']) ? $manifest['require-dev'] : array(); $requireDev = isset($manifest['require-dev']) ? $manifest['require-dev'] : array();
$packages = array_merge($require, $requireDev); $packages = array_merge($require, $requireDev);
foreach ($packages as $package => $version) { foreach ($packages as $package => $version) {
if (preg_match('/#/', $version) === 1) { if (Preg::isMatch('/#/', $version)) {
$warnings[] = sprintf( $warnings[] = sprintf(
'The package "%s" is pointing to a commit-ref, this is bad practice and can cause unforeseen issues.', 'The package "%s" is pointing to a commit-ref, this is bad practice and can cause unforeseen issues.',
$package $package

View File

@ -13,6 +13,7 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
/** /**
* Convert PHP errors into exceptions * Convert PHP errors into exceptions
@ -55,7 +56,7 @@ class ErrorHandler
if (self::$io) { if (self::$io) {
// ignore symfony/* deprecation warnings // ignore symfony/* deprecation warnings
// TODO remove in 2.3 // TODO remove in 2.3
if (preg_match('{^Return type of Symfony\\\\.*ReturnTypeWillChange}is', $message)) { if (Preg::isMatch('{^Return type of Symfony\\\\.*ReturnTypeWillChange}is', $message)) {
return true; return true;
} }
if (strpos(strtr($file, '\\', '/'), 'vendor/symfony/') !== false) { if (strpos(strtr($file, '\\', '/'), 'vendor/symfony/') !== false) {

View File

@ -12,6 +12,7 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\Pcre\Preg;
use React\Promise\PromiseInterface; use React\Promise\PromiseInterface;
use RecursiveDirectoryIterator; use RecursiveDirectoryIterator;
use RecursiveIteratorIterator; use RecursiveIteratorIterator;
@ -196,7 +197,7 @@ class Filesystem
return true; return true;
} }
if (preg_match('{^(?:[a-z]:)?[/\\\\]+$}i', $directory)) { if (Preg::isMatch('{^(?:[a-z]:)?[/\\\\]+$}i', $directory)) {
throw new \RuntimeException('Aborting an attempted deletion of '.$directory.', this was probably not intended, if it is a real use case please report it.'); throw new \RuntimeException('Aborting an attempted deletion of '.$directory.', this was probably not intended, if it is a real use case please report it.');
} }
@ -464,7 +465,7 @@ class Filesystem
} }
$commonPath = $to; $commonPath = $to;
while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath)) { while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !Preg::isMatch('{^[a-z]:/?$}i', $commonPath)) {
$commonPath = strtr(\dirname($commonPath), '\\', '/'); $commonPath = strtr(\dirname($commonPath), '\\', '/');
} }
@ -503,7 +504,7 @@ class Filesystem
} }
$commonPath = $to; $commonPath = $to;
while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath) && '.' !== $commonPath) { while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !Preg::isMatch('{^[a-z]:/?$}i', $commonPath) && '.' !== $commonPath) {
$commonPath = strtr(\dirname($commonPath), '\\', '/'); $commonPath = strtr(\dirname($commonPath), '\\', '/');
} }
@ -578,7 +579,7 @@ class Filesystem
} }
// extract a prefix being a protocol://, protocol:, protocol://drive: or simply drive: // extract a prefix being a protocol://, protocol:, protocol://drive: or simply drive:
if (preg_match('{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix', $path, $match)) { if (Preg::isMatch('{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix', $path, $match)) {
$prefix = $match[1]; $prefix = $match[1];
$path = substr($path, \strlen($prefix)); $path = substr($path, \strlen($prefix));
} }
@ -612,7 +613,7 @@ class Filesystem
*/ */
public static function trimTrailingSlash($path) public static function trimTrailingSlash($path)
{ {
if (!preg_match('{^[/\\\\]+$}', $path)) { if (!Preg::isMatch('{^[/\\\\]+$}', $path)) {
$path = rtrim($path, '/\\'); $path = rtrim($path, '/\\');
} }
@ -627,7 +628,7 @@ class Filesystem
*/ */
public static function isLocalPath($path) public static function isLocalPath($path)
{ {
return (bool) preg_match('{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path); return Preg::isMatch('{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path);
} }
/** /**
@ -638,10 +639,10 @@ class Filesystem
public static function getPlatformPath($path) public static function getPlatformPath($path)
{ {
if (Platform::isWindows()) { if (Platform::isWindows()) {
$path = preg_replace('{^(?:file:///([a-z]):?/)}i', 'file://$1:/', $path); $path = Preg::replace('{^(?:file:///([a-z]):?/)}i', 'file://$1:/', $path);
} }
return (string) preg_replace('{^file://}i', '', $path); return (string) Preg::replace('{^file://}i', '', $path);
} }
/** /**

View File

@ -14,6 +14,7 @@ namespace Composer\Util;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
@ -58,14 +59,14 @@ class Git
$cwd = null; $cwd = null;
} }
if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $url)) { if (Preg::isMatch('{^ssh://[^@]+@[^:]+:[^0-9]+}', $url)) {
throw new \InvalidArgumentException('The source URL ' . $url . ' is invalid, ssh URLs should have a port number after ":".' . "\n" . 'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.'); throw new \InvalidArgumentException('The source URL ' . $url . ' is invalid, ssh URLs should have a port number after ":".' . "\n" . 'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.');
} }
if (!$initialClone) { if (!$initialClone) {
// capture username/password from URL if there is one and we have no auth configured yet // capture username/password from URL if there is one and we have no auth configured yet
$this->process->execute('git remote -v', $output, $cwd); $this->process->execute('git remote -v', $output, $cwd);
if (preg_match('{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im', $output, $match) && !$this->io->hasAuthentication($match[3])) { if (Preg::isMatch('{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im', $output, $match) && !$this->io->hasAuthentication($match[3])) {
$this->io->setAuthentication($match[3], rawurldecode($match[1]), rawurldecode($match[2])); $this->io->setAuthentication($match[3], rawurldecode($match[1]), rawurldecode($match[2]));
} }
} }
@ -75,7 +76,7 @@ class Git
throw new \RuntimeException('Config value "github-protocols" must be an array, got ' . gettype($protocols)); throw new \RuntimeException('Config value "github-protocols" must be an array, got ' . gettype($protocols));
} }
// public github, autoswitch protocols // public github, autoswitch protocols
if (preg_match('{^(?:https?|git)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)) { if (Preg::isMatch('{^(?:https?|git)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)) {
$messages = array(); $messages = array();
foreach ($protocols as $protocol) { foreach ($protocols as $protocol) {
if ('ssh' === $protocol) { if ('ssh' === $protocol) {
@ -87,7 +88,7 @@ class Git
if (0 === $this->process->execute(call_user_func($commandCallable, $protoUrl), $ignoredOutput, $cwd)) { if (0 === $this->process->execute(call_user_func($commandCallable, $protoUrl), $ignoredOutput, $cwd)) {
return; return;
} }
$messages[] = '- ' . $protoUrl . "\n" . preg_replace('#^#m', ' ', $this->process->getErrorOutput()); $messages[] = '- ' . $protoUrl . "\n" . Preg::replace('#^#m', ' ', $this->process->getErrorOutput());
if ($initialClone && isset($origCwd)) { if ($initialClone && isset($origCwd)) {
$this->filesystem->removeDirectory($origCwd); $this->filesystem->removeDirectory($origCwd);
@ -101,7 +102,7 @@ class Git
} }
// if we have a private github url and the ssh protocol is disabled then we skip it and directly fallback to https // if we have a private github url and the ssh protocol is disabled then we skip it and directly fallback to https
$bypassSshForGitHub = preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url) && !in_array('ssh', $protocols, true); $bypassSshForGitHub = Preg::isMatch('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url) && !in_array('ssh', $protocols, true);
$command = call_user_func($commandCallable, $url); $command = call_user_func($commandCallable, $url);
@ -110,8 +111,8 @@ class Git
if ($bypassSshForGitHub || 0 !== $this->process->execute($command, $ignoredOutput, $cwd)) { if ($bypassSshForGitHub || 0 !== $this->process->execute($command, $ignoredOutput, $cwd)) {
$errorMsg = $this->process->getErrorOutput(); $errorMsg = $this->process->getErrorOutput();
// private github repository without ssh key access, try https with auth // private github repository without ssh key access, try https with auth
if (preg_match('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match) if (Preg::isMatch('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match)
|| preg_match('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*?)(?:\.git)?$}i', $url, $match) || Preg::isMatch('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*?)(?:\.git)?$}i', $url, $match)
) { ) {
if (!$this->io->hasAuthentication($match[1])) { if (!$this->io->hasAuthentication($match[1])) {
$gitHubUtil = new GitHub($this->io, $this->config, $this->process); $gitHubUtil = new GitHub($this->io, $this->config, $this->process);
@ -133,7 +134,7 @@ class Git
$credentials = array(rawurlencode($auth['username']), rawurlencode($auth['password'])); $credentials = array(rawurlencode($auth['username']), rawurlencode($auth['password']));
$errorMsg = $this->process->getErrorOutput(); $errorMsg = $this->process->getErrorOutput();
} }
} elseif (preg_match('{^https://(bitbucket\.org)/(.*?)(?:\.git)?$}i', $url, $match)) { //bitbucket oauth } elseif (Preg::isMatch('{^https://(bitbucket\.org)/(.*?)(?:\.git)?$}i', $url, $match)) { //bitbucket oauth
$bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process); $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process);
if (!$this->io->hasAuthentication($match[1])) { if (!$this->io->hasAuthentication($match[1])) {
@ -178,8 +179,8 @@ class Git
$errorMsg = $this->process->getErrorOutput(); $errorMsg = $this->process->getErrorOutput();
} }
} elseif ( } elseif (
preg_match('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match) Preg::isMatch('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match)
|| preg_match('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}i', $url, $match) || Preg::isMatch('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}i', $url, $match)
) { ) {
if ($match[1] === 'git') { if ($match[1] === 'git') {
$match[1] = 'https'; $match[1] = 'https';
@ -283,7 +284,7 @@ class Git
if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') { if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') {
try { try {
$commandCallable = function ($url) { $commandCallable = function ($url) {
$sanitizedUrl = preg_replace('{://([^@]+?):(.+?)@}', '://', $url); $sanitizedUrl = Preg::replace('{://([^@]+?):(.+?)@}', '://', $url);
return sprintf('git remote set-url origin -- %s && git remote update --prune origin && git remote set-url origin -- %s && git gc --auto', ProcessExecutor::escape($url), ProcessExecutor::escape($sanitizedUrl)); return sprintf('git remote set-url origin -- %s && git remote update --prune origin && git remote set-url origin -- %s && git gc --auto', ProcessExecutor::escape($url), ProcessExecutor::escape($sanitizedUrl));
}; };
@ -369,7 +370,7 @@ class Git
*/ */
private function isAuthenticationFailure($url, &$match) private function isAuthenticationFailure($url, &$match)
{ {
if (!preg_match('{^(https?://)([^/]+)(.*)$}i', $url, $match)) { if (!Preg::isMatch('{^(https?://)([^/]+)(.*)$}i', $url, $match)) {
return false; return false;
} }
@ -465,7 +466,7 @@ class Git
{ {
if (false === self::$version) { if (false === self::$version) {
self::$version = null; self::$version = null;
if (0 === $process->execute('git --version', $output) && preg_match('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) { if (0 === $process->execute('git --version', $output) && Preg::isMatch('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) {
self::$version = $matches[1]; self::$version = $matches[1];
} }
} }

View File

@ -16,6 +16,7 @@ use Composer\Factory;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Config; use Composer\Config;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Pcre\Preg;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
@ -180,7 +181,7 @@ class GitHub
public function isRateLimited(array $headers) public function isRateLimited(array $headers)
{ {
foreach ($headers as $header) { foreach ($headers as $header) {
if (preg_match('{^X-RateLimit-Remaining: *0$}i', trim($header))) { if (Preg::isMatch('{^X-RateLimit-Remaining: *0$}i', trim($header))) {
return true; return true;
} }
} }

View File

@ -16,6 +16,7 @@ use Composer\IO\IOInterface;
use Composer\Config; use Composer\Config;
use Composer\Factory; use Composer\Factory;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Pcre\Preg;
/** /**
* @author Roshan Gautam <roshan.gautam@hotmail.com> * @author Roshan Gautam <roshan.gautam@hotmail.com>
@ -57,7 +58,7 @@ class GitLab
public function authorizeOAuth($originUrl) public function authorizeOAuth($originUrl)
{ {
// before composer 1.9, origin URLs had no port number in them // before composer 1.9, origin URLs had no port number in them
$bcOriginUrl = preg_replace('{:\d+}', '', $originUrl); $bcOriginUrl = Preg::replace('{:\d+}', '', $originUrl);
if (!in_array($originUrl, $this->config->get('gitlab-domains'), true) && !in_array($bcOriginUrl, $this->config->get('gitlab-domains'), true)) { if (!in_array($originUrl, $this->config->get('gitlab-domains'), true) && !in_array($bcOriginUrl, $this->config->get('gitlab-domains'), true)) {
return false; return false;

View File

@ -14,6 +14,7 @@ namespace Composer\Util;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
/** /**
* @author Jonas Renaudot <jonas.renaudot@gmail.com> * @author Jonas Renaudot <jonas.renaudot@gmail.com>
@ -64,7 +65,7 @@ class Hg
} }
// Try with the authentication information available // Try with the authentication information available
if (preg_match('{^(https?)://((.+)(?:\:(.+))?@)?([^/]+)(/.*)?}mi', $url, $match) && $this->io->hasAuthentication($match[5])) { if (Preg::isMatch('{^(https?)://((.+)(?:\:(.+))?@)?([^/]+)(/.*)?}mi', $url, $match) && $this->io->hasAuthentication($match[5])) {
$auth = $this->io->getAuthentication($match[5]); $auth = $this->io->getAuthentication($match[5]);
$authenticatedUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[5] . (!empty($match[6]) ? $match[6] : null); $authenticatedUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[5] . (!empty($match[6]) ? $match[6] : null);
@ -106,7 +107,7 @@ class Hg
{ {
if (false === self::$version) { if (false === self::$version) {
self::$version = null; self::$version = null;
if (0 === $process->execute('hg --version', $output) && preg_match('/^.+? (\d+(?:\.\d+)+)\)?\r?\n/', $output, $matches)) { if (0 === $process->execute('hg --version', $output) && Preg::isMatch('/^.+? (\d+(?:\.\d+)+)\)?\r?\n/', $output, $matches)) {
self::$version = $matches[1]; self::$version = $matches[1];
} }
} }

View File

@ -16,6 +16,7 @@ use Composer\Config;
use Composer\Downloader\MaxFileSizeExceededException; use Composer\Downloader\MaxFileSizeExceededException;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Pcre\Preg;
use Composer\Util\StreamContextFactory; use Composer\Util\StreamContextFactory;
use Composer\Util\AuthHelper; use Composer\Util\AuthHelper;
use Composer\Util\Url; use Composer\Util\Url;
@ -167,7 +168,7 @@ class CurlDownloader
$originalOptions = $options; $originalOptions = $options;
// check URL can be accessed (i.e. is not insecure), but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256 // check URL can be accessed (i.e. is not insecure), but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256
if (!preg_match('{^http://(repo\.)?packagist\.org/p/}', $url) || (false === strpos($url, '$') && false === strpos($url, '%24'))) { if (!Preg::isMatch('{^http://(repo\.)?packagist\.org/p/}', $url) || (false === strpos($url, '$') && false === strpos($url, '%24'))) {
$this->config->prohibitUrlByConfig($url, $this->io); $this->config->prohibitUrlByConfig($url, $this->io);
} }
@ -181,7 +182,7 @@ class CurlDownloader
if ($errorMessage) { if ($errorMessage) {
$errorMessage .= "\n"; $errorMessage .= "\n";
} }
$errorMessage .= preg_replace('{^fopen\(.*?\): }', '', $msg); $errorMessage .= Preg::replace('{^fopen\(.*?\): }', '', $msg);
}); });
$bodyHandle = fopen($copyTo.'~', 'w+b'); $bodyHandle = fopen($copyTo.'~', 'w+b');
restore_error_handler(); restore_error_handler();
@ -500,11 +501,11 @@ class CurlDownloader
$urlHost = parse_url($job['url'], PHP_URL_HOST); $urlHost = parse_url($job['url'], PHP_URL_HOST);
// Replace path using hostname as an anchor. // Replace path using hostname as an anchor.
$targetUrl = preg_replace('{^(.+(?://|@)'.preg_quote($urlHost).'(?::\d+)?)(?:[/\?].*)?$}', '\1'.$locationHeader, $job['url']); $targetUrl = Preg::replace('{^(.+(?://|@)'.preg_quote($urlHost).'(?::\d+)?)(?:[/\?].*)?$}', '\1'.$locationHeader, $job['url']);
} else { } else {
// Relative path; e.g. foo // Relative path; e.g. foo
// This actually differs from PHP which seems to add duplicate slashes. // This actually differs from PHP which seems to add duplicate slashes.
$targetUrl = preg_replace('{^(.+/)[^/?]*(?:\?.*)?$}', '\1'.$locationHeader, $job['url']); $targetUrl = Preg::replace('{^(.+/)[^/?]*(?:\?.*)?$}', '\1'.$locationHeader, $job['url']);
} }
} }
@ -540,7 +541,7 @@ class CurlDownloader
&& !$this->authHelper->isPublicBitBucketDownload($job['url']) && !$this->authHelper->isPublicBitBucketDownload($job['url'])
&& substr($job['url'], -4) === '.zip' && substr($job['url'], -4) === '.zip'
&& (!$locationHeader || substr($locationHeader, -4) !== '.zip') && (!$locationHeader || substr($locationHeader, -4) !== '.zip')
&& preg_match('{^text/html\b}i', $response->getHeader('content-type')) && Preg::isMatch('{^text/html\b}i', $response->getHeader('content-type'))
) { ) {
$needsAuthRetry = 'Bitbucket requires authentication and it was not provided'; $needsAuthRetry = 'Bitbucket requires authentication and it was not provided';
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Util\Http; namespace Composer\Util\Http;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Pcre\Preg;
use Composer\Util\HttpDownloader; use Composer\Util\HttpDownloader;
/** /**
@ -61,7 +62,7 @@ class Response
{ {
$value = null; $value = null;
foreach ($this->headers as $header) { foreach ($this->headers as $header) {
if (preg_match('{^HTTP/\S+ \d+}i', $header)) { if (Preg::isMatch('{^HTTP/\S+ \d+}i', $header)) {
// In case of redirects, headers contain the headers of all responses // In case of redirects, headers contain the headers of all responses
// so we can not return directly and need to keep iterating // so we can not return directly and need to keep iterating
$value = $header; $value = $header;
@ -123,7 +124,7 @@ class Response
{ {
$value = null; $value = null;
foreach ($headers as $header) { foreach ($headers as $header) {
if (preg_match('{^'.preg_quote($name).':\s*(.+?)\s*$}i', $header, $match)) { if (Preg::isMatch('{^'.preg_quote($name).':\s*(.+?)\s*$}i', $header, $match)) {
$value = $match[1]; $value = $match[1];
} }
} }

View File

@ -15,6 +15,7 @@ namespace Composer\Util;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\Pcre\Preg;
use Composer\Util\Http\Response; use Composer\Util\Http\Response;
use Composer\Util\Http\CurlDownloader; use Composer\Util\Http\CurlDownloader;
use Composer\Composer; use Composer\Composer;
@ -226,7 +227,7 @@ class HttpDownloader
} }
// capture username/password from URL if there is one // capture username/password from URL if there is one
if (preg_match('{^https?://([^:/]+):([^@/]+)@([^/]+)}i', $request['url'], $match)) { if (Preg::isMatch('{^https?://([^:/]+):([^@/]+)@([^/]+)}i', $request['url'], $match)) {
$this->io->setAuthentication($job['origin'], rawurldecode($match[1]), rawurldecode($match[2])); $this->io->setAuthentication($job['origin'], rawurldecode($match[1]), rawurldecode($match[2]));
} }
@ -536,7 +537,7 @@ class HttpDownloader
return false; return false;
} }
if (!preg_match('{^https?://}i', $job['request']['url'])) { if (!Preg::isMatch('{^https?://}i', $job['request']['url'])) {
return false; return false;
} }

View File

@ -12,6 +12,7 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\Pcre\Preg;
use stdClass; use stdClass;
/** /**
@ -39,7 +40,7 @@ class NoProxyPattern
*/ */
public function __construct($pattern) public function __construct($pattern)
{ {
$this->hostNames = preg_split('{[\s,]+}', $pattern, -1, PREG_SPLIT_NO_EMPTY); $this->hostNames = Preg::split('{[\s,]+}', $pattern, -1, PREG_SPLIT_NO_EMPTY);
$this->noproxy = empty($this->hostNames) || '*' === $this->hostNames[0]; $this->noproxy = empty($this->hostNames) || '*' === $this->hostNames[0];
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
/** /**
@ -634,7 +635,7 @@ class Perforce
foreach ($resArray as $line) { foreach ($resArray as $line) {
$resBits = explode(' ', $line); $resBits = explode(' ', $line);
if (count($resBits) > 4) { if (count($resBits) > 4) {
$branch = preg_replace('/[^A-Za-z0-9 ]/', '', $resBits[4]); $branch = Preg::replace('/[^A-Za-z0-9 ]/', '', $resBits[4]);
$possibleBranches[$branch] = $resBits[1]; $possibleBranches[$branch] = $resBits[1];
} }
} }

View File

@ -12,6 +12,8 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\Pcre\Preg;
/** /**
* Platform helper for uniform platform-specific tests. * Platform helper for uniform platform-specific tests.
* *
@ -76,11 +78,11 @@ class Platform
*/ */
public static function expandPath($path) public static function expandPath($path)
{ {
if (preg_match('#^~[\\/]#', $path)) { if (Preg::isMatch('#^~[\\/]#', $path)) {
return self::getUserDirectory() . substr($path, 1); return self::getUserDirectory() . substr($path, 1);
} }
return preg_replace_callback('#^(\$|(?P<percent>%))(?P<var>\w++)(?(percent)%)(?P<path>.*)#', function ($matches) { return Preg::replaceCallback('#^(\$|(?P<percent>%))(?P<var>\w++)(?(percent)%)(?P<path>.*)#', function ($matches) {
// Treat HOME as an alias for USERPROFILE on Windows for legacy reasons // Treat HOME as an alias for USERPROFILE on Windows for legacy reasons
if (Platform::isWindows() && $matches['var'] == 'HOME') { if (Platform::isWindows() && $matches['var'] == 'HOME') {
return (Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE')) . $matches['path']; return (Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE')) . $matches['path'];

View File

@ -13,6 +13,7 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\RuntimeException; use Symfony\Component\Process\Exception\RuntimeException;
use React\Promise\Promise; use React\Promise\Promise;
@ -102,15 +103,15 @@ class ProcessExecutor
private function doExecute($command, $cwd, $tty, &$output = null) private function doExecute($command, $cwd, $tty, &$output = null)
{ {
if ($this->io && $this->io->isDebug()) { if ($this->io && $this->io->isDebug()) {
$safeCommand = preg_replace_callback('{://(?P<user>[^:/\s]+):(?P<password>[^@\s/]+)@}i', function ($m) { $safeCommand = Preg::replaceCallback('{://(?P<user>[^:/\s]+):(?P<password>[^@\s/]+)@}i', function ($m) {
// if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx) we obfuscate that // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx) we obfuscate that
if (preg_match('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+)$}', $m['user'])) { if (Preg::isMatch('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+)$}', $m['user'])) {
return '://***:***@'; return '://***:***@';
} }
return '://'.$m['user'].':***@'; return '://'.$m['user'].':***@';
}, $command); }, $command);
$safeCommand = preg_replace("{--password (.*[^\\\\]\') }", '--password \'***\' ', $safeCommand); $safeCommand = Preg::replace("{--password (.*[^\\\\]\') }", '--password \'***\' ', $safeCommand);
$this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand); $this->io->writeError('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand);
} }
@ -249,14 +250,14 @@ class ProcessExecutor
$cwd = $job['cwd']; $cwd = $job['cwd'];
if ($this->io && $this->io->isDebug()) { if ($this->io && $this->io->isDebug()) {
$safeCommand = preg_replace_callback('{://(?P<user>[^:/\s]+):(?P<password>[^@\s/]+)@}i', function ($m) { $safeCommand = Preg::replaceCallback('{://(?P<user>[^:/\s]+):(?P<password>[^@\s/]+)@}i', function ($m) {
if (preg_match('{^[a-f0-9]{12,}$}', $m['user'])) { if (Preg::isMatch('{^[a-f0-9]{12,}$}', $m['user'])) {
return '://***:***@'; return '://***:***@';
} }
return '://'.$m['user'].':***@'; return '://'.$m['user'].':***@';
}, $command); }, $command);
$safeCommand = preg_replace("{--password (.*[^\\\\]\') }", '--password \'***\' ', $safeCommand); $safeCommand = Preg::replace("{--password (.*[^\\\\]\') }", '--password \'***\' ', $safeCommand);
$this->io->writeError('Executing async command ('.($cwd ?: 'CWD').'): '.$safeCommand); $this->io->writeError('Executing async command ('.($cwd ?: 'CWD').'): '.$safeCommand);
} }
@ -384,7 +385,7 @@ class ProcessExecutor
{ {
$output = trim((string) $output); $output = trim((string) $output);
return $output === '' ? array() : preg_split('{\r?\n}', $output); return $output === '' ? array() : Preg::split('{\r?\n}', $output);
} }
/** /**
@ -482,20 +483,20 @@ class ProcessExecutor
$argument = strtr($argument, "\n", ' '); $argument = strtr($argument, "\n", ' ');
$quote = strpbrk($argument, " \t") !== false; $quote = strpbrk($argument, " \t") !== false;
$argument = preg_replace('/(\\\\*)"/', '$1$1\\"', $argument, -1, $dquotes); $argument = Preg::replace('/(\\\\*)"/', '$1$1\\"', $argument, -1, $dquotes);
$meta = $dquotes || preg_match('/%[^%]+%|![^!]+!/', $argument); $meta = $dquotes || Preg::isMatch('/%[^%]+%|![^!]+!/', $argument);
if (!$meta && !$quote) { if (!$meta && !$quote) {
$quote = strpbrk($argument, '^&|<>()') !== false; $quote = strpbrk($argument, '^&|<>()') !== false;
} }
if ($quote) { if ($quote) {
$argument = '"'.preg_replace('/(\\\\*)$/', '$1$1', $argument).'"'; $argument = '"'.Preg::replace('/(\\\\*)$/', '$1$1', $argument).'"';
} }
if ($meta) { if ($meta) {
$argument = preg_replace('/(["^&|<>()%])/', '^$1', $argument); $argument = Preg::replace('/(["^&|<>()%])/', '^$1', $argument);
$argument = preg_replace('/(!)/', '^^$1', $argument); $argument = Preg::replace('/(!)/', '^^$1', $argument);
} }
return $argument; return $argument;

View File

@ -17,6 +17,7 @@ use Composer\Downloader\MaxFileSizeExceededException;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Downloader\TransportException; use Composer\Downloader\TransportException;
use Composer\CaBundle\CaBundle; use Composer\CaBundle\CaBundle;
use Composer\Pcre\Preg;
use Composer\Util\Http\Response; use Composer\Util\Http\Response;
use Composer\Util\Http\ProxyManager; use Composer\Util\Http\ProxyManager;
@ -177,7 +178,7 @@ class RemoteFilesystem
{ {
$value = null; $value = null;
foreach ($headers as $header) { foreach ($headers as $header) {
if (preg_match('{^HTTP/\S+ (\d+)}i', $header, $match)) { if (Preg::isMatch('{^HTTP/\S+ (\d+)}i', $header, $match)) {
// In case of redirects, http_response_headers contains the headers of all responses // In case of redirects, http_response_headers contains the headers of all responses
// so we can not return directly and need to keep iterating // so we can not return directly and need to keep iterating
$value = (int) $match[1]; $value = (int) $match[1];
@ -195,7 +196,7 @@ class RemoteFilesystem
{ {
$value = null; $value = null;
foreach ($headers as $header) { foreach ($headers as $header) {
if (preg_match('{^HTTP/\S+ \d+}i', $header)) { if (Preg::isMatch('{^HTTP/\S+ \d+}i', $header)) {
// In case of redirects, http_response_headers contains the headers of all responses // In case of redirects, http_response_headers contains the headers of all responses
// so we can not return directly and need to keep iterating // so we can not return directly and need to keep iterating
$value = $header; $value = $header;
@ -281,7 +282,7 @@ class RemoteFilesystem
unset($origFileUrl, $proxy, $usingProxy); unset($origFileUrl, $proxy, $usingProxy);
// Check for secure HTTP, but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256 // Check for secure HTTP, but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256
if ((!preg_match('{^http://(repo\.)?packagist\.org/p/}', $fileUrl) || (false === strpos($fileUrl, '$') && false === strpos($fileUrl, '%24'))) && empty($degradedPackagist)) { if ((!Preg::isMatch('{^http://(repo\.)?packagist\.org/p/}', $fileUrl) || (false === strpos($fileUrl, '$') && false === strpos($fileUrl, '%24'))) && empty($degradedPackagist)) {
$this->config->prohibitUrlByConfig($fileUrl, $this->io); $this->config->prohibitUrlByConfig($fileUrl, $this->io);
} }
@ -296,7 +297,7 @@ class RemoteFilesystem
if ($errorMessage) { if ($errorMessage) {
$errorMessage .= "\n"; $errorMessage .= "\n";
} }
$errorMessage .= preg_replace('{^file_get_contents\(.*?\): }', '', $msg); $errorMessage .= Preg::replace('{^file_get_contents\(.*?\): }', '', $msg);
return true; return true;
}); });
@ -386,7 +387,7 @@ class RemoteFilesystem
&& !$this->authHelper->isPublicBitBucketDownload($fileUrl) && !$this->authHelper->isPublicBitBucketDownload($fileUrl)
&& substr($fileUrl, -4) === '.zip' && substr($fileUrl, -4) === '.zip'
&& (!$locationHeader || substr(parse_url($locationHeader, PHP_URL_PATH), -4) !== '.zip') && (!$locationHeader || substr(parse_url($locationHeader, PHP_URL_PATH), -4) !== '.zip')
&& $contentType && preg_match('{^text/html\b}i', $contentType) && $contentType && Preg::isMatch('{^text/html\b}i', $contentType)
) { ) {
$result = false; $result = false;
if ($retryAuthFailure) { if ($retryAuthFailure) {
@ -463,7 +464,7 @@ class RemoteFilesystem
if ($errorMessage) { if ($errorMessage) {
$errorMessage .= "\n"; $errorMessage .= "\n";
} }
$errorMessage .= preg_replace('{^file_put_contents\(.*?\): }', '', $msg); $errorMessage .= Preg::replace('{^file_put_contents\(.*?\): }', '', $msg);
return true; return true;
}); });
@ -752,11 +753,11 @@ class RemoteFilesystem
$urlHost = parse_url($this->fileUrl, PHP_URL_HOST); $urlHost = parse_url($this->fileUrl, PHP_URL_HOST);
// Replace path using hostname as an anchor. // Replace path using hostname as an anchor.
$targetUrl = preg_replace('{^(.+(?://|@)'.preg_quote($urlHost).'(?::\d+)?)(?:[/\?].*)?$}', '\1'.$locationHeader, $this->fileUrl); $targetUrl = Preg::replace('{^(.+(?://|@)'.preg_quote($urlHost).'(?::\d+)?)(?:[/\?].*)?$}', '\1'.$locationHeader, $this->fileUrl);
} else { } else {
// Relative path; e.g. foo // Relative path; e.g. foo
// This actually differs from PHP which seems to add duplicate slashes. // This actually differs from PHP which seems to add duplicate slashes.
$targetUrl = preg_replace('{^(.+/)[^/?]*(?:\?.*)?$}', '\1'.$locationHeader, $this->fileUrl); $targetUrl = Preg::replace('{^(.+/)[^/?]*(?:\?.*)?$}', '\1'.$locationHeader, $this->fileUrl);
} }
} }

View File

@ -14,6 +14,7 @@ namespace Composer\Util;
use Composer\Config; use Composer\Config;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Pcre\Preg;
/** /**
* @author Till Klampaeckel <till@php.net> * @author Till Klampaeckel <till@php.net>
@ -380,7 +381,7 @@ class Svn
{ {
if (!self::$version) { if (!self::$version) {
if (0 === $this->process->execute('svn --version', $output)) { if (0 === $this->process->execute('svn --version', $output)) {
if (preg_match('{(\d+(?:\.\d+)+)}', $output, $match)) { if (Preg::isMatch('{(\d+(?:\.\d+)+)}', $output, $match)) {
self::$version = $match[1]; self::$version = $match[1];
} }
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\CaBundle\CaBundle; use Composer\CaBundle\CaBundle;
use Composer\Pcre\Preg;
/** /**
* @author Chris Smith <chris@cs278.org> * @author Chris Smith <chris@cs278.org>
@ -75,7 +76,7 @@ final class TlsHelper
$subjectAltNames = array(); $subjectAltNames = array();
if (isset($info['extensions']['subjectAltName'])) { if (isset($info['extensions']['subjectAltName'])) {
$subjectAltNames = preg_split('{\s*,\s*}', $info['extensions']['subjectAltName']); $subjectAltNames = Preg::split('{\s*,\s*}', $info['extensions']['subjectAltName']);
$subjectAltNames = array_filter(array_map(function ($name) { $subjectAltNames = array_filter(array_map(function ($name) {
if (0 === strpos($name, 'DNS:')) { if (0 === strpos($name, 'DNS:')) {
return strtolower(ltrim(substr($name, 4))); return strtolower(ltrim(substr($name, 4)));
@ -198,7 +199,7 @@ final class TlsHelper
$wildcardRegex = "{^{$wildcardRegex}$}"; $wildcardRegex = "{^{$wildcardRegex}$}";
return function ($hostname) use ($wildcardRegex) { return function ($hostname) use ($wildcardRegex) {
return 1 === preg_match($wildcardRegex, $hostname); return Preg::isMatch($wildcardRegex, $hostname);
}; };
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Util; namespace Composer\Util;
use Composer\Config; use Composer\Config;
use Composer\Pcre\Preg;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
@ -30,30 +31,30 @@ class Url
$host = parse_url($url, PHP_URL_HOST); $host = parse_url($url, PHP_URL_HOST);
if ($host === 'api.github.com' || $host === 'github.com' || $host === 'www.github.com') { if ($host === 'api.github.com' || $host === 'github.com' || $host === 'www.github.com') {
if (preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/(zip|tar)ball/(.+)$}i', $url, $match)) { if (Preg::isMatch('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/(zip|tar)ball/(.+)$}i', $url, $match)) {
// update legacy github archives to API calls with the proper reference // update legacy github archives to API calls with the proper reference
$url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref; $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
} elseif (preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/archive/.+\.(zip|tar)(?:\.gz)?$}i', $url, $match)) { } elseif (Preg::isMatch('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/archive/.+\.(zip|tar)(?:\.gz)?$}i', $url, $match)) {
// update current github web archives to API calls with the proper reference // update current github web archives to API calls with the proper reference
$url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref; $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
} elseif (preg_match('{^https?://api\.github\.com/repos/([^/]+)/([^/]+)/(zip|tar)ball(?:/.+)?$}i', $url, $match)) { } elseif (Preg::isMatch('{^https?://api\.github\.com/repos/([^/]+)/([^/]+)/(zip|tar)ball(?:/.+)?$}i', $url, $match)) {
// update api archives to the proper reference // update api archives to the proper reference
$url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref; $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $ref;
} }
} elseif ($host === 'bitbucket.org' || $host === 'www.bitbucket.org') { } elseif ($host === 'bitbucket.org' || $host === 'www.bitbucket.org') {
if (preg_match('{^https?://(?:www\.)?bitbucket\.org/([^/]+)/([^/]+)/get/(.+)\.(zip|tar\.gz|tar\.bz2)$}i', $url, $match)) { if (Preg::isMatch('{^https?://(?:www\.)?bitbucket\.org/([^/]+)/([^/]+)/get/(.+)\.(zip|tar\.gz|tar\.bz2)$}i', $url, $match)) {
// update Bitbucket archives to the proper reference // update Bitbucket archives to the proper reference
$url = 'https://bitbucket.org/' . $match[1] . '/'. $match[2] . '/get/' . $ref . '.' . $match[4]; $url = 'https://bitbucket.org/' . $match[1] . '/'. $match[2] . '/get/' . $ref . '.' . $match[4];
} }
} elseif ($host === 'gitlab.com' || $host === 'www.gitlab.com') { } elseif ($host === 'gitlab.com' || $host === 'www.gitlab.com') {
if (preg_match('{^https?://(?:www\.)?gitlab\.com/api/v[34]/projects/([^/]+)/repository/archive\.(zip|tar\.gz|tar\.bz2|tar)\?sha=.+$}i', $url, $match)) { if (Preg::isMatch('{^https?://(?:www\.)?gitlab\.com/api/v[34]/projects/([^/]+)/repository/archive\.(zip|tar\.gz|tar\.bz2|tar)\?sha=.+$}i', $url, $match)) {
// update Gitlab archives to the proper reference // update Gitlab archives to the proper reference
$url = 'https://gitlab.com/api/v4/projects/' . $match[1] . '/repository/archive.' . $match[2] . '?sha=' . $ref; $url = 'https://gitlab.com/api/v4/projects/' . $match[1] . '/repository/archive.' . $match[2] . '?sha=' . $ref;
} }
} elseif (in_array($host, $config->get('github-domains'), true)) { } elseif (in_array($host, $config->get('github-domains'), true)) {
$url = preg_replace('{(/repos/[^/]+/[^/]+/(zip|tar)ball)(?:/.+)?$}i', '$1/'.$ref, $url); $url = Preg::replace('{(/repos/[^/]+/[^/]+/(zip|tar)ball)(?:/.+)?$}i', '$1/'.$ref, $url);
} elseif (in_array($host, $config->get('gitlab-domains'), true)) { } elseif (in_array($host, $config->get('gitlab-domains'), true)) {
$url = preg_replace('{(/api/v[34]/projects/[^/]+/repository/archive\.(?:zip|tar\.gz|tar\.bz2|tar)\?sha=).+$}i', '${1}'.$ref, $url); $url = Preg::replace('{(/api/v[34]/projects/[^/]+/repository/archive\.(?:zip|tar\.gz|tar\.bz2|tar)\?sha=).+$}i', '${1}'.$ref, $url);
} }
return $url; return $url;
@ -111,11 +112,11 @@ class Url
{ {
// GitHub repository rename result in redirect locations containing the access_token as GET parameter // GitHub repository rename result in redirect locations containing the access_token as GET parameter
// e.g. https://api.github.com/repositories/9999999999?access_token=github_token // e.g. https://api.github.com/repositories/9999999999?access_token=github_token
$url = preg_replace('{([&?]access_token=)[^&]+}', '$1***', $url); $url = Preg::replace('{([&?]access_token=)[^&]+}', '$1***', $url);
$url = preg_replace_callback('{^(?P<prefix>[a-z0-9]+://)?(?P<user>[^:/\s@]+):(?P<password>[^@\s/]+)@}i', function ($m) { $url = Preg::replaceCallback('{^(?P<prefix>[a-z0-9]+://)?(?P<user>[^:/\s@]+):(?P<password>[^@\s/]+)@}i', function ($m) {
// if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx) we obfuscate that // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx) we obfuscate that
if (preg_match('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+)$}', $m['user'])) { if (Preg::isMatch('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+)$}', $m['user'])) {
return $m['prefix'].'***:***@'; return $m['prefix'].'***:***@';
} }

View File

@ -12,6 +12,7 @@
namespace Composer\Test; namespace Composer\Test;
use Composer\Pcre\Preg;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\Finder;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
@ -147,10 +148,10 @@ class AllFunctionalTest extends TestCase
$line++; $line++;
} }
if ($expected[$i] === '%') { if ($expected[$i] === '%') {
preg_match('{%(.+?)%}', substr($expected, $i), $match); Preg::isMatch('{%(.+?)%}', substr($expected, $i), $match);
$regex = $match[1]; $regex = $match[1];
if (preg_match('{'.$regex.'}', substr($output, $j), $match)) { if (Preg::isMatch('{'.$regex.'}', substr($output, $j), $match)) {
$i += strlen($regex) + 2; $i += strlen($regex) + 2;
$j += strlen($match[0]); $j += strlen($match[0]);
continue; continue;
@ -207,7 +208,7 @@ class AllFunctionalTest extends TestCase
*/ */
private function parseTestFile($file) private function parseTestFile($file)
{ {
$tokens = preg_split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file), -1, PREG_SPLIT_DELIM_CAPTURE); $tokens = Preg::split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file), -1, PREG_SPLIT_DELIM_CAPTURE);
$data = array(); $data = array();
$section = null; $section = null;

View File

@ -17,6 +17,7 @@ use Composer\DependencyResolver\Pool;
use Composer\DependencyResolver\PoolOptimizer; use Composer\DependencyResolver\PoolOptimizer;
use Composer\Config; use Composer\Config;
use Composer\IO\NullIO; use Composer\IO\NullIO;
use Composer\Pcre\Preg;
use Composer\Repository\ArrayRepository; use Composer\Repository\ArrayRepository;
use Composer\Repository\FilterRepository; use Composer\Repository\FilterRepository;
use Composer\Repository\LockArrayRepository; use Composer\Repository\LockArrayRepository;
@ -188,7 +189,7 @@ class PoolBuilderTest extends TestCase
$fixturesDir = realpath(__DIR__.'/Fixtures/poolbuilder/'); $fixturesDir = realpath(__DIR__.'/Fixtures/poolbuilder/');
$tests = array(); $tests = array();
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if (!preg_match('/\.test$/', $file)) { if (!Preg::isMatch('/\.test$/', $file)) {
continue; continue;
} }
@ -224,7 +225,7 @@ class PoolBuilderTest extends TestCase
*/ */
protected function readTestFile(\SplFileInfo $file, $fixturesDir) protected function readTestFile(\SplFileInfo $file, $fixturesDir)
{ {
$tokens = preg_split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file->getRealPath()), -1, PREG_SPLIT_DELIM_CAPTURE); $tokens = Preg::split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file->getRealPath()), -1, PREG_SPLIT_DELIM_CAPTURE);
$sectionInfo = array( $sectionInfo = array(
'TEST' => true, 'TEST' => true,

View File

@ -21,6 +21,7 @@ use Composer\Package\AliasPackage;
use Composer\Package\BasePackage; use Composer\Package\BasePackage;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Pcre\Preg;
use Composer\Repository\LockArrayRepository; use Composer\Repository\LockArrayRepository;
use Composer\Test\TestCase; use Composer\Test\TestCase;
@ -75,7 +76,7 @@ class PoolOptimizerTest extends TestCase
$fixturesDir = realpath(__DIR__.'/Fixtures/pooloptimizer/'); $fixturesDir = realpath(__DIR__.'/Fixtures/pooloptimizer/');
$tests = array(); $tests = array();
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if (!preg_match('/\.test$/', $file)) { if (!Preg::isMatch('/\.test$/', $file)) {
continue; continue;
} }
@ -102,7 +103,7 @@ class PoolOptimizerTest extends TestCase
*/ */
protected function readTestFile(\SplFileInfo $file, $fixturesDir) protected function readTestFile(\SplFileInfo $file, $fixturesDir)
{ {
$tokens = preg_split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file->getRealPath()), -1, PREG_SPLIT_DELIM_CAPTURE); $tokens = Preg::split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file->getRealPath()), -1, PREG_SPLIT_DELIM_CAPTURE);
/** @var array<string, bool> $sectionInfo */ /** @var array<string, bool> $sectionInfo */
$sectionInfo = array( $sectionInfo = array(

View File

@ -14,6 +14,7 @@ namespace Composer\Test\Downloader;
use Composer\Downloader\GitDownloader; use Composer\Downloader\GitDownloader;
use Composer\Config; use Composer\Config;
use Composer\Pcre\Preg;
use Composer\Test\TestCase; use Composer\Test\TestCase;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
use Composer\Util\Platform; use Composer\Util\Platform;
@ -159,7 +160,7 @@ class GitDownloaderTest extends TestCase
$config = new Config; $config = new Config;
$this->setupConfig($config); $this->setupConfig($config);
$cachePath = $config->get('cache-vcs-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', 'https://example.com/composer/composer').'/'; $cachePath = $config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', 'https://example.com/composer/composer').'/';
$filesystem = new \Composer\Util\Filesystem; $filesystem = new \Composer\Util\Filesystem;
$filesystem->removeDirectory($cachePath); $filesystem->removeDirectory($cachePath);

View File

@ -8,7 +8,7 @@ Checks that package versions in InstalledVersions are correct on initial install
update update
--EXPECT-- --EXPECT--
> Hooks::preUpdate > Hooks::preUpdate
!!PreUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process"] !!PreUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process"]
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
Loading composer repositories with package information Loading composer repositories with package information
Updating dependencies Updating dependencies
@ -26,12 +26,12 @@ Package operations: 6 installs, 0 updates, 0 removals%(\nAs there is no 'unzip'
- Downloading symfony/filesystem (%v?[2-8]\.\d+\.\d+%) - Downloading symfony/filesystem (%v?[2-8]\.\d+\.\d+%)
- Installing symfony/console (99999.1.2): Symlinking from symfony-console - Installing symfony/console (99999.1.2): Symlinking from symfony-console
- Installing plugin/a (1.1.1): Symlinking from plugin-a - Installing plugin/a (1.1.1): Symlinking from plugin-a
!!PluginAInit["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","root/pkg"] !!PluginAInit["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","root/pkg"]
!!PluginA:null !!PluginA:null
!!PluginB:null !!PluginB:null
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
- Installing plugin/b (2.2.2): Symlinking from plugin-b - Installing plugin/b (2.2.2): Symlinking from plugin-b
!!PluginBInit["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","root/pkg"] !!PluginBInit["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","root/pkg"]
!!PluginA:1.1.1.0 !!PluginA:1.1.1.0
!!PluginB:null !!PluginB:null
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
@ -42,7 +42,7 @@ Generating autoload files
2 packages you are using are looking for funding. 2 packages you are using are looking for funding.
Use the `composer fund` command to find out more! Use the `composer fund` command to find out more!
> Hooks::postUpdate > Hooks::postUpdate
!!PostUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"] !!PostUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"]
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
--EXPECT-EXIT-CODE-- --EXPECT-EXIT-CODE--

View File

@ -7,14 +7,14 @@ Checks that package versions in InstalledVersions are correct during an upgrade.
--RUN-- --RUN--
update plugin/* symfony/console symfony/filesystem symfony/process update plugin/* symfony/console symfony/filesystem symfony/process
--EXPECT-- --EXPECT--
!!PluginA:1.1.1.0["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"] !!PluginA:1.1.1.0["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"]
!!PluginB:2.2.2.0 !!PluginB:2.2.2.0
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
!!PluginB:2.2.2.0["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"] !!PluginB:2.2.2.0["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"]
!!PluginA:1.1.1.0 !!PluginA:1.1.1.0
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
> Hooks::preUpdate > Hooks::preUpdate
!!PreUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"] !!PreUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"]
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
Loading composer repositories with package information Loading composer repositories with package information
Updating dependencies Updating dependencies
@ -30,12 +30,12 @@ Package operations: 0 installs, 5 updates, 0 removals%(\nAs there is no 'unzip'
- Downloading symfony/filesystem (%v?[2-8]\.\d+\.\d+%) - Downloading symfony/filesystem (%v?[2-8]\.\d+\.\d+%)
- Upgrading symfony/console (99999.1.2 => 99999.1.3): Mirroring from symfony-console - Upgrading symfony/console (99999.1.2 => 99999.1.3): Mirroring from symfony-console
- Upgrading plugin/a (1.1.1 => 1.1.2): Mirroring from plugin-a - Upgrading plugin/a (1.1.1 => 1.1.2): Mirroring from plugin-a
!!PluginAInit["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"] !!PluginAInit["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"]
!!PluginA:1.1.1.0 !!PluginA:1.1.1.0
!!PluginB:2.2.2.0 !!PluginB:2.2.2.0
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
- Upgrading plugin/b (2.2.2 => 2.2.3): Mirroring from plugin-b - Upgrading plugin/b (2.2.2 => 2.2.3): Mirroring from plugin-b
!!PluginBInit["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"] !!PluginBInit["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"]
!!PluginA:1.1.2.0 !!PluginA:1.1.2.0
!!PluginB:2.2.2.0 !!PluginB:2.2.2.0
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
@ -45,7 +45,7 @@ Generating autoload files
2 packages you are using are looking for funding. 2 packages you are using are looking for funding.
Use the `composer fund` command to find out more! Use the `composer fund` command to find out more!
> Hooks::postUpdate > Hooks::postUpdate
!!PostUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"] !!PostUpdate:["composer/ca-bundle","composer/composer","composer/metadata-minifier","composer/pcre","composer/semver","composer/spdx-licenses","composer/xdebug-handler","justinrainbow/json-schema","psr/log","react/promise","seld/jsonlint","seld/phar-utils","symfony/console","symfony/debug","symfony/filesystem","symfony/finder","symfony/polyfill-ctype","symfony/polyfill-mbstring","symfony/process","plugin/a","plugin/b","root/pkg"]
!!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0% !!Versions:console:%[2-8]\.\d+\.\d+.0%;process:%[2-8]\.\d+\.\d+.0%;filesystem:%[2-8]\.\d+\.\d+.0%
!!PluginA:1.1.2.0 !!PluginA:1.1.2.0
!!PluginB:2.2.3.0 !!PluginB:2.2.3.0

Some files were not shown because too many files have changed in this diff Show More