From bd6a5019b3bf5edf13640522796f54accaad789e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 17 Nov 2022 11:34:54 +0100 Subject: [PATCH] Update to composer/pcre 2.1 (#11189) --- composer.json | 2 +- composer.lock | 138 +++++++++--------- src/Composer/Command/ConfigCommand.php | 2 +- src/Composer/Command/CreateProjectCommand.php | 2 +- src/Composer/Command/DiagnoseCommand.php | 8 +- src/Composer/Command/InitCommand.php | 9 +- src/Composer/Command/ShowCommand.php | 2 +- src/Composer/DependencyResolver/Problem.php | 2 +- src/Composer/Downloader/GitDownloader.php | 8 +- src/Composer/Downloader/SvnDownloader.php | 2 +- src/Composer/Downloader/ZipDownloader.php | 2 +- .../EventDispatcher/EventDispatcher.php | 2 +- src/Composer/Installer/BinaryInstaller.php | 6 +- src/Composer/Json/JsonManipulator.php | 47 ++++-- .../Package/Loader/RootPackageLoader.php | 6 +- .../Package/Version/VersionBumper.php | 2 +- .../Package/Version/VersionGuesser.php | 14 +- .../Package/Version/VersionSelector.php | 2 +- src/Composer/Platform/Version.php | 6 +- .../Repository/ComposerRepository.php | 2 +- .../Repository/PlatformRepository.php | 38 ++--- .../Repository/Vcs/GitBitbucketDriver.php | 2 +- src/Composer/Repository/Vcs/GitDriver.php | 4 +- src/Composer/Repository/Vcs/GitHubDriver.php | 22 +-- src/Composer/Repository/Vcs/GitLabDriver.php | 14 +- src/Composer/Repository/Vcs/HgDriver.php | 6 +- src/Composer/Repository/Vcs/SvnDriver.php | 4 +- src/Composer/Util/Filesystem.php | 2 +- src/Composer/Util/Git.php | 14 +- src/Composer/Util/Hg.php | 6 +- src/Composer/Util/HttpDownloader.php | 2 +- src/Composer/Util/ProcessExecutor.php | 2 +- tests/Composer/Test/AllFunctionalTest.php | 4 +- 33 files changed, 203 insertions(+), 181 deletions(-) diff --git a/composer.json b/composer.json index 60e2508e5..86fd27907 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "symfony/finder": "^5.4 || ^6.0", "symfony/process": "^5.4 || ^6.0", "react/promise": "^2.8", - "composer/pcre": "^2 || ^3", + "composer/pcre": "^2.1 || ^3.1", "symfony/polyfill-php73": "^1.24", "symfony/polyfill-php80": "^1.24", "symfony/polyfill-php81": "^1.24", diff --git a/composer.lock b/composer.lock index f144b2bf9..52c8a6709 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2dc8cd355eee4bb6c9fb0d2e10ffb7c6", + "content-hash": "63b34757131aff5b81d2ed8ce5933fe4", "packages": [ { "name": "composer/ca-bundle", @@ -226,16 +226,16 @@ }, { "name": "composer/pcre", - "version": "2.0.1", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "562ca94029b37bb04205e2abb43be5550d2945d7" + "reference": "3fdb2807b31a78a40ad89570e30ec77466c98717" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/562ca94029b37bb04205e2abb43be5550d2945d7", - "reference": "562ca94029b37bb04205e2abb43be5550d2945d7", + "url": "https://api.github.com/repos/composer/pcre/zipball/3fdb2807b31a78a40ad89570e30ec77466c98717", + "reference": "3fdb2807b31a78a40ad89570e30ec77466c98717", "shasum": "" }, "require": { @@ -277,7 +277,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/2.0.1" + "source": "https://github.com/composer/pcre/tree/2.1.0" }, "funding": [ { @@ -293,7 +293,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T15:56:01+00:00" + "time": "2022-11-16T18:32:04+00:00" }, { "name": "composer/semver", @@ -1234,16 +1234,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "shasum": "" }, "require": { @@ -1258,7 +1258,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1296,7 +1296,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" }, "funding": [ { @@ -1312,20 +1312,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "433d05519ce6990bf3530fba6957499d327395c2" + "reference": "511a08c03c1960e08a883f4cffcacd219b758354" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", - "reference": "433d05519ce6990bf3530fba6957499d327395c2", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", + "reference": "511a08c03c1960e08a883f4cffcacd219b758354", "shasum": "" }, "require": { @@ -1337,7 +1337,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1377,7 +1377,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" }, "funding": [ { @@ -1393,20 +1393,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "219aa369ceff116e673852dce47c3a41794c14bd" + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", - "reference": "219aa369ceff116e673852dce47c3a41794c14bd", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", "shasum": "" }, "require": { @@ -1418,7 +1418,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1461,7 +1461,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" }, "funding": [ { @@ -1477,20 +1477,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "shasum": "" }, "require": { @@ -1505,7 +1505,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1544,7 +1544,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" }, "funding": [ { @@ -1560,20 +1560,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", - "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", "shasum": "" }, "require": { @@ -1582,7 +1582,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1623,7 +1623,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" }, "funding": [ { @@ -1639,20 +1639,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "shasum": "" }, "require": { @@ -1661,7 +1661,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1706,7 +1706,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" }, "funding": [ { @@ -1722,20 +1722,20 @@ "type": "tidelift" } ], - "time": "2022-05-10T07:21:04+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", - "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", "shasum": "" }, "require": { @@ -1744,7 +1744,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1785,7 +1785,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" }, "funding": [ { @@ -1801,7 +1801,7 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/process", @@ -2038,16 +2038,16 @@ "packages-dev": [ { "name": "phpstan/phpstan", - "version": "1.9.0", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e08de53a5eec983de78a787a88e72518cf8fe43a" + "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e08de53a5eec983de78a787a88e72518cf8fe43a", - "reference": "e08de53a5eec983de78a787a88e72518cf8fe43a", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d6fdf01c53978b6429f1393ba4afeca39cc68afa", + "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa", "shasum": "" }, "require": { @@ -2077,7 +2077,7 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.9.0" + "source": "https://github.com/phpstan/phpstan/tree/1.9.2" }, "funding": [ { @@ -2093,7 +2093,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T07:26:48+00:00" + "time": "2022-11-10T09:56:11+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -2247,22 +2247,22 @@ }, { "name": "phpstan/phpstan-symfony", - "version": "1.2.15", + "version": "1.2.16", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "7210072b7fd83bf62eb5f889d4da70b80c07f04c" + "reference": "d6ea16206b1b645ded5b43736d8ef5ae1168eb55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/7210072b7fd83bf62eb5f889d4da70b80c07f04c", - "reference": "7210072b7fd83bf62eb5f889d4da70b80c07f04c", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/d6ea16206b1b645ded5b43736d8ef5ae1168eb55", + "reference": "d6ea16206b1b645ded5b43736d8ef5ae1168eb55", "shasum": "" }, "require": { "ext-simplexml": "*", "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.8.2" + "phpstan/phpstan": "^1.9.1" }, "conflict": { "symfony/framework-bundle": "<3.0" @@ -2312,9 +2312,9 @@ "description": "Symfony Framework extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.15" + "source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.16" }, - "time": "2022-11-03T15:03:30+00:00" + "time": "2022-11-04T13:16:15+00:00" }, { "name": "symfony/phpunit-bridge", diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index e979f6e14..952baa815 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -664,7 +664,7 @@ EOT } // handle repositories - if (Preg::isMatch('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) { + if (Preg::isMatchStrictGroups('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { $this->configSource->removeRepository($matches[1]); diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index c084feaa0..6037a9803 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -375,7 +375,7 @@ EOT if (null === $stability) { if (null === $packageVersion) { $stability = 'stable'; - } elseif (Preg::isMatch('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $packageVersion, $match)) { + } elseif (Preg::isMatchStrictGroups('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $packageVersion, $match)) { $stability = $match[1]; } else { $stability = VersionParser::parseStability($packageVersion); diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index 6024ebb9a..6f306d340 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -163,7 +163,7 @@ EOT $platformRepo = new PlatformRepository([], $platformOverrides); $phpPkg = $platformRepo->findPackage('php', '*'); $phpVersion = $phpPkg->getPrettyVersion(); - if ($phpPkg instanceof CompletePackageInterface && false !== strpos($phpPkg->getDescription(), 'overridden')) { + if ($phpPkg instanceof CompletePackageInterface && str_contains((string) $phpPkg->getDescription(), 'overridden')) { $phpVersion .= ' - ' . $phpPkg->getDescription(); } @@ -573,14 +573,14 @@ EOT ob_start(); phpinfo(INFO_GENERAL); $phpinfo = ob_get_clean(); - if (Preg::isMatch('{Configure Command(?: *| *=> *)(.*?)(?:|$)}m', $phpinfo, $match)) { + if (is_string($phpinfo) && Preg::isMatchStrictGroups('{Configure Command(?: *| *=> *)(.*?)(?:|$)}m', $phpinfo, $match)) { $configure = $match[1]; - if (false !== strpos($configure, '--enable-sigchild')) { + if (str_contains($configure, '--enable-sigchild')) { $warnings['sigchild'] = true; } - if (false !== strpos($configure, '--with-curlwrappers')) { + if (str_contains($configure, '--with-curlwrappers')) { $warnings['curlwrappers'] = true; } } diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 7cd11e666..3a61ee76a 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -465,14 +465,15 @@ EOT private function parseAuthorString(string $author): array { if (Preg::isMatch('/^(?P[- .,\p{L}\p{N}\p{Mn}\'’"()]+)(?:\s+<(?P.+?)>)?$/u', $author, $match)) { - $hasEmail = isset($match['email']) && '' !== $match['email']; - if ($hasEmail && !$this->isValidEmail($match['email'])) { + assert(is_string($match['name'])); + + if (null !== $match['email'] && !$this->isValidEmail($match['email'])) { throw new \InvalidArgumentException('Invalid email "'.$match['email'].'"'); } return [ 'name' => trim($match['name']), - 'email' => $hasEmail ? $match['email'] : null, + 'email' => $match['email'], ]; } @@ -536,7 +537,7 @@ EOT if ($cmd->isSuccessful()) { $this->gitConfig = []; - Preg::matchAll('{^([^=]+)=(.*)$}m', $cmd->getOutput(), $matches); + Preg::matchAllStrictGroups('{^([^=]+)=(.*)$}m', $cmd->getOutput(), $matches); foreach ($matches[1] as $key => $match) { $this->gitConfig[$match] = $matches[2][$key]; } diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index 8257d83d2..f81ba27e0 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -1369,7 +1369,7 @@ EOT if ($targetVersion === null) { if ($majorOnly && Preg::isMatch('{^(?P(?:0\.)+)?(?P\d+)\.}', $package->getVersion(), $match)) { - $targetVersion = '>='.$match['zero_major'].($match['first_meaningful'] + 1).',<9999999-dev'; + $targetVersion = '>='.$match['zero_major'].(((int) $match['first_meaningful']) + 1).',<9999999-dev'; } if ($minorOnly) { diff --git a/src/Composer/DependencyResolver/Problem.php b/src/Composer/DependencyResolver/Problem.php index 971db2526..0cb314401 100644 --- a/src/Composer/DependencyResolver/Problem.php +++ b/src/Composer/DependencyResolver/Problem.php @@ -114,7 +114,7 @@ class Problem $deduplicatableRuleTypes = [Rule::RULE_PACKAGE_REQUIRES, Rule::RULE_PACKAGE_CONFLICT]; foreach ($rules as $rule) { $message = $rule->getPrettyString($repositorySet, $request, $pool, $isVerbose, $installedMap, $learnedPool); - if (in_array($rule->getReason(), $deduplicatableRuleTypes, true) && Preg::isMatch('{^(?P\S+) (?P\S+) (?Prequires|conflicts)}', $message, $m)) { + if (in_array($rule->getReason(), $deduplicatableRuleTypes, true) && Preg::isMatchStrictGroups('{^(?P\S+) (?P\S+) (?Prequires|conflicts)}', $message, $m)) { $template = Preg::replace('{^\S+ \S+ }', '%s%s ', $message); $messages[] = $template; $templates[$template][$m[1]][$parser->normalize($m[2])] = $m[2]; diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index 9ba60002a..05901a9b2 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -249,13 +249,13 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface } $refs = trim($output); - if (!Preg::isMatch('{^([a-f0-9]+) HEAD$}mi', $refs, $match)) { + if (!Preg::isMatchStrictGroups('{^([a-f0-9]+) HEAD$}mi', $refs, $match)) { // could not match the HEAD for some reason return null; } $headRef = $match[1]; - if (!Preg::isMatchAll('{^'.$headRef.' refs/heads/(.+)$}mi', $refs, $matches)) { + if (!Preg::isMatchAllStrictGroups('{^'.$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 return null; } @@ -272,7 +272,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface // try to find matching branch names in remote repos foreach ($candidateBranches as $candidate) { - if (Preg::isMatchAll('{^[a-f0-9]+ refs/remotes/((?:[^/]+)/'.preg_quote($candidate).')$}mi', $refs, $matches)) { + if (Preg::isMatchAllStrictGroups('{^[a-f0-9]+ refs/remotes/((?:[^/]+)/'.preg_quote($candidate).')$}mi', $refs, $matches)) { foreach ($matches[1] as $match) { $branch = $candidate; $remoteBranches[] = $match; @@ -284,7 +284,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface // if it doesn't exist, then we assume it is an unpushed branch // this is bad as we have no reference point to do a diff so we just bail listing // the branch as being unpushed - if (!$remoteBranches) { + if (count($remoteBranches) === 0) { $unpushedChanges = 'Branch ' . $branch . ' could not be found on any remote and appears to be unpushed'; $branchNotFoundError = true; } else { diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php index 637ce8193..daa93dfe9 100644 --- a/src/Composer/Downloader/SvnDownloader.php +++ b/src/Composer/Downloader/SvnDownloader.php @@ -202,7 +202,7 @@ class SvnDownloader extends VcsDownloader } $urlPattern = '#(.*)#'; - if (Preg::isMatch($urlPattern, $output, $matches)) { + if (Preg::isMatchStrictGroups($urlPattern, $output, $matches)) { $baseUrl = $matches[1]; } else { throw new \RuntimeException( diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index 725e6468d..851e70de1 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -131,7 +131,7 @@ class ZipDownloader extends ArchiveDownloader if (!$warned7ZipLinux && !Platform::isWindows() && in_array($executable, ['7z', '7zz'], true)) { $warned7ZipLinux = true; if (0 === $this->process->execute($executable, $output)) { - if (Preg::isMatch('{^\s*7-Zip(?: \[64\])? ([0-9.]+)}', $output, $match) && version_compare($match[1], '21.01', '<')) { + if (Preg::isMatchStrictGroups('{^\s*7-Zip(?: \[64\])? ([0-9.]+)}', $output, $match) && version_compare($match[1], '21.01', '<')) { $this->io->writeError(' Unzipping using '.$executable.' '.$match[1].' may result in incorrect file permissions. Install '.$executable.' 21.01+ or unzip to ensure you get correct permissions.'); } } diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index 9a94c3bcb..95ca80d20 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -347,7 +347,7 @@ class EventDispatcher } // 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 - $matched = Preg::isMatch('{^[^\'"\s/\\\\]+}', $pathAndArgs, $match); + $matched = Preg::isMatchStrictGroups('{^[^\'"\s/\\\\]+}', $pathAndArgs, $match); if ($matched && !file_exists($match[0])) { $finder = new ExecutableFinder; if ($pathToExec = $finder->find($match[0])) { diff --git a/src/Composer/Installer/BinaryInstaller.php b/src/Composer/Installer/BinaryInstaller.php index 042986cbb..827c8178c 100644 --- a/src/Composer/Installer/BinaryInstaller.php +++ b/src/Composer/Installer/BinaryInstaller.php @@ -140,7 +140,7 @@ class BinaryInstaller $handle = fopen($bin, 'r'); $line = fgets($handle); fclose($handle); - if (Preg::isMatch('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) { + if (Preg::isMatchStrictGroups('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', (string) $line, $match)) { return trim($match[1]); } @@ -218,7 +218,7 @@ class BinaryInstaller // which allows calling the proxy with a custom php process if (Preg::isMatch('{^(#!.*\r?\n)?[\r\n\t ]*<\?php}', $binContents, $match)) { // carry over the existing shebang if present, otherwise add our own - $proxyCode = empty($match[1]) ? '#!/usr/bin/env php' : trim($match[1]); + $proxyCode = $match[1] === null ? '#!/usr/bin/env php' : trim($match[1]); $binPathExported = $this->filesystem->findShortestPathCode($link, $bin, false, true); $streamProxyCode = $streamHint = ''; $globalsCode = '$GLOBALS[\'_composer_bin_dir\'] = __DIR__;'."\n"; @@ -237,7 +237,7 @@ class BinaryInstaller $data = str_replace(\'__DIR__\', var_export(dirname($this->realpath), true), $data); $data = str_replace(\'__FILE__\', var_export($this->realpath, true), $data);'; } - if (trim($match[0]) !== ' -? (?= [1-9]|0(?!\d) ) \d++ (\.\d++)? ([eE] [+-]?+ \d++)? ) + private const DEFINES = '(?(DEFINE) + (? -? (?= [1-9]|0(?!\d) ) \d++ (?:\.\d++)? (?:[eE] [+-]?+ \d++)? ) (? true | false | null ) - (? " ([^"\\\\]*+ | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " ) + (? " (?:[^"\\\\]*+ | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9A-Fa-f]{4} )* " ) (? \[ (?: (?&json) \s*+ (?: , (?&json) \s*+ )*+ )?+ \s*+ \] ) (? \s*+ (?&string) \s*+ : (?&json) \s*+ ) (? \{ (?: (?&pair) (?: , (?&pair) )*+ )?+ \s*+ \} ) @@ -66,26 +66,30 @@ class JsonManipulator return $this->addMainKey($type, [$package => $constraint]); } - $regex = '{'.self::$DEFINES.'^(?P\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. + $regex = '{'.self::DEFINES.'^(?P\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. '(?P'.preg_quote(JsonFile::encode($type)).'\s*:\s*)(?P(?&json))(?P.*)}sx'; if (!Preg::isMatch($regex, $this->contents, $matches)) { return false; } + assert(is_string($matches['start'])); + assert(is_string($matches['value'])); + assert(is_string($matches['end'])); $links = $matches['value']; // try to find existing link $packageRegex = str_replace('/', '\\\\?/', preg_quote($package)); - $regex = '{'.self::$DEFINES.'"(?P'.$packageRegex.')"(\s*:\s*)(?&string)}ix'; + $regex = '{'.self::DEFINES.'"(?P'.$packageRegex.')"(\s*:\s*)(?&string)}ix'; if (Preg::isMatch($regex, $links, $packageMatches)) { + assert(is_string($packageMatches['package'])); // update existing link $existingPackage = $packageMatches['package']; $packageRegex = str_replace('/', '\\\\?/', preg_quote($existingPackage)); - $links = Preg::replaceCallback('{'.self::$DEFINES.'"'.$packageRegex.'"(?P\s*:\s*)(?&string)}ix', static function ($m) use ($existingPackage, $constraint): string { + $links = Preg::replaceCallback('{'.self::DEFINES.'"'.$packageRegex.'"(?P\s*:\s*)(?&string)}ix', static function ($m) use ($existingPackage, $constraint): string { return JsonFile::encode(str_replace('\\/', '/', $existingPackage)) . $m['separator'] . '"' . $constraint . '"'; }, $links); } else { - if (Preg::isMatch('#^\s*\{\s*\S+.*?(\s*\}\s*)$#s', $links, $match)) { + if (Preg::isMatchStrictGroups('#^\s*\{\s*\S+.*?(\s*\}\s*)$#s', $links, $match)) { // link missing but non empty links $links = Preg::replace( '{'.preg_quote($match[1]).'$}', @@ -237,7 +241,7 @@ class JsonManipulator } // main node content not match-able - $nodeRegex = '{'.self::$DEFINES.'^(?P \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'. + $nodeRegex = '{'.self::DEFINES.'^(?P \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'. preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P(?&object))(?P.*)}sx'; try { @@ -251,6 +255,10 @@ class JsonManipulator throw $e; } + assert(is_string($match['start'])); + assert(is_string($match['content'])); + assert(is_string($match['end'])); + $children = $match['content']; // invalid match due to un-regexable content, abort if (!@json_decode($children)) { @@ -258,7 +266,7 @@ class JsonManipulator } // child exists - $childRegex = '{'.self::$DEFINES.'(?P"'.preg_quote($name).'"\s*:\s*)(?P(?&json))(?P,?)}x'; + $childRegex = '{'.self::DEFINES.'(?P"'.preg_quote($name).'"\s*:\s*)(?P(?&json))(?P,?)}x'; if (Preg::isMatch($childRegex, $children, $matches)) { $children = Preg::replaceCallback($childRegex, function ($matches) use ($subName, $value): string { if ($subName !== null && is_string($matches['content'])) { @@ -331,7 +339,7 @@ class JsonManipulator } // no node content match-able - $nodeRegex = '{'.self::$DEFINES.'^(?P \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'. + $nodeRegex = '{'.self::DEFINES.'^(?P \s* \{ \s* (?: (?&string) \s* : (?&json) \s* , \s* )*?'. preg_quote(JsonFile::encode($mainNode)).'\s*:\s*)(?P(?&object))(?P.*)}sx'; try { if (!Preg::isMatch($nodeRegex, $this->contents, $match)) { @@ -344,6 +352,10 @@ class JsonManipulator throw $e; } + assert(is_string($match['start'])); + assert(is_string($match['content'])); + assert(is_string($match['end'])); + $children = $match['content']; // invalid match due to un-regexable content, abort @@ -365,9 +377,10 @@ class JsonManipulator $keyRegex = str_replace('/', '\\\\?/', preg_quote($name)); if (Preg::isMatch('{"'.$keyRegex.'"\s*:}i', $children)) { // find best match for the value of "name" - if (Preg::isMatchAll('{'.self::$DEFINES.'"'.$keyRegex.'"\s*:\s*(?:(?&json))}x', $children, $matches)) { + if (Preg::isMatchAll('{'.self::DEFINES.'"'.$keyRegex.'"\s*:\s*(?:(?&json))}x', $children, $matches)) { $bestMatch = ''; foreach ($matches[0] as $match) { + assert(is_string($match)); if (strlen($bestMatch) < strlen($match)) { $bestMatch = $match; } @@ -432,7 +445,7 @@ class JsonManipulator $content = $this->format($content); // key exists already - $regex = '{'.self::$DEFINES.'^(?P\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. + $regex = '{'.self::DEFINES.'^(?P\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. '(?P'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))(?P.*)}sx'; if (isset($decoded[$key]) && Preg::isMatch($regex, $this->contents, $matches)) { // invalid match due to un-regexable content, abort @@ -475,16 +488,20 @@ class JsonManipulator } // key exists already - $regex = '{'.self::$DEFINES.'^(?P\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. + $regex = '{'.self::DEFINES.'^(?P\s*\{\s*(?:(?&string)\s*:\s*(?&json)\s*,\s*)*?)'. '(?P'.preg_quote(JsonFile::encode($key)).'\s*:\s*(?&json))\s*,?\s*(?P.*)}sx'; if (Preg::isMatch($regex, $this->contents, $matches)) { + assert(is_string($matches['start'])); + assert(is_string($matches['removal'])); + assert(is_string($matches['end'])); + // invalid match due to un-regexable content, abort if (!@json_decode('{'.$matches['removal'].'}')) { return false; } // check that we are not leaving a dangling comma on the previous line if the last line was removed - if (Preg::isMatch('#,\s*$#', $matches['start']) && Preg::isMatch('#^\}$#', $matches['end'])) { + if (Preg::isMatchStrictGroups('#,\s*$#', $matches['start']) && Preg::isMatch('#^\}$#', $matches['end'])) { $matches['start'] = rtrim(Preg::replace('#,(\s*)$#', '$1', $matches['start']), $this->indent); } @@ -544,7 +561,7 @@ class JsonManipulator protected function detectIndenting(): void { - if (Preg::isMatch('{^([ \t]+)"}m', $this->contents, $match)) { + if (Preg::isMatchStrictGroups('{^([ \t]+)"}m', $this->contents, $match)) { $this->indent = $match[1]; } else { $this->indent = ' '; diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index a1df59622..7e9d386c2 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -193,7 +193,7 @@ class RootPackageLoader extends ArrayLoader private function extractAliases(array $requires, array $aliases): array { foreach ($requires as $reqName => $reqVersion) { - if (Preg::isMatch('{(?:^|\| *|, *)([^,\s#|]+)(?:#[^ ]+)? +as +([^,\s|]+)(?:$| *\|| *,)}', $reqVersion, $match)) { + if (Preg::isMatchStrictGroups('{(?:^|\| *|, *)([^,\s#|]+)(?:#[^ ]+)? +as +([^,\s|]+)(?:$| *\|| *,)}', $reqVersion, $match)) { $aliases[] = [ 'package' => strtolower($reqName), 'version' => $this->versionParser->normalize($match[1], $reqVersion), @@ -239,7 +239,7 @@ class RootPackageLoader extends ArrayLoader // parse explicit stability flags to the most unstable $matched = false; foreach ($constraints as $constraint) { - if (Preg::isMatch('{^[^@]*?@('.implode('|', array_keys($stabilities)).')$}i', $constraint, $match)) { + if (Preg::isMatchStrictGroups('{^[^@]*?@('.implode('|', array_keys($stabilities)).')$}i', $constraint, $match)) { $name = strtolower($reqName); $stability = $stabilities[VersionParser::normalizeStability($match[1])]; @@ -285,7 +285,7 @@ class RootPackageLoader extends ArrayLoader { foreach ($requires as $reqName => $reqVersion) { $reqVersion = Preg::replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion); - if (Preg::isMatch('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) && 'dev' === VersionParser::parseStability($reqVersion)) { + if (Preg::isMatchStrictGroups('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) && 'dev' === VersionParser::parseStability($reqVersion)) { $name = strtolower($reqName); $references[$name] = $match[1]; } diff --git a/src/Composer/Package/Version/VersionBumper.php b/src/Composer/Package/Version/VersionBumper.php index 76c92d4f5..a554d8c55 100644 --- a/src/Composer/Package/Version/VersionBumper.php +++ b/src/Composer/Package/Version/VersionBumper.php @@ -89,7 +89,7 @@ class VersionBumper if (Preg::isMatchAllWithOffsets($pattern, $prettyConstraint, $matches)) { $modified = $prettyConstraint; foreach (array_reverse($matches['constraint']) as $match) { - $modified = substr_replace($modified, $newPrettyConstraint, $match[1], Platform::strlen($match[0])); + $modified = substr_replace($modified, $newPrettyConstraint, $match[1], Platform::strlen((string) $match[0])); } // if it is strictly equal to the previous one then no need to change anything diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php index 54e403410..06476e7dc 100644 --- a/src/Composer/Package/Version/VersionGuesser.php +++ b/src/Composer/Package/Version/VersionGuesser.php @@ -142,7 +142,7 @@ class VersionGuesser // find current branch and collect all branch names foreach ($this->process->splitLines($output) as $branch) { - if ($branch && Preg::isMatch('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\(HEAD detached at \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) { + if ($branch && Preg::isMatchStrictGroups('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\(HEAD detached at \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) { if ( $match[1] === '(no branch)' || strpos($match[1], '(detached ') === 0 @@ -158,13 +158,11 @@ class VersionGuesser $isFeatureBranch = $this->isFeatureBranch($packageConfig, $match[1]); } - if ($match[2]) { - $commit = $match[2]; - } + $commit = $match[2]; } - if ($branch && !Preg::isMatch('{^ *.+/HEAD }', $branch)) { - if (Preg::isMatch('{^(?:\* )? *((?:remotes/(?:origin|upstream)/)?[^\s/]+) *([a-f0-9]+) .*$}', $branch, $match)) { + if ($branch && !Preg::isMatchStrictGroups('{^ *.+/HEAD }', $branch)) { + if (Preg::isMatchStrictGroups('{^(?:\* )? *((?:remotes/(?:origin|upstream)/)?[^\s/]+) *([a-f0-9]+) .*$}', $branch, $match)) { $branches[] = $match[1]; } } @@ -191,7 +189,7 @@ class VersionGuesser } } - if (!$commit) { + if (null === $commit) { $command = 'git log --pretty="%H" -n1 HEAD'.GitUtil::getNoShowSignatureFlag($this->process); if (0 === $this->process->execute($command, $output, $path)) { $commit = trim($output) ?: null; @@ -399,7 +397,7 @@ class VersionGuesser $urlPattern = '#.*/(' . $trunkPath . '|(' . $branchesPath . '|' . $tagsPath . ')/(.*))#'; - if (Preg::isMatch($urlPattern, $output, $matches)) { + if (Preg::isMatchStrictGroups($urlPattern, $output, $matches)) { if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) { // we are in a branches path $version = $this->versionParser->normalizeBranch($matches[3]); diff --git a/src/Composer/Package/Version/VersionSelector.php b/src/Composer/Package/Version/VersionSelector.php index 34f3a1f2b..138b8fabf 100644 --- a/src/Composer/Package/Version/VersionSelector.php +++ b/src/Composer/Package/Version/VersionSelector.php @@ -210,7 +210,7 @@ class VersionSelector $extra = $loader->getBranchAlias($dumper->dump($package)); if ($extra && $extra !== VersionParser::DEFAULT_BRANCH_ALIAS) { $extra = Preg::replace('{^(\d+\.\d+\.\d+)(\.9999999)-dev$}', '$1.0', $extra, -1, $count); - if ($count) { + if ($count > 0) { $extra = str_replace('.9999999', '.0', $extra); return $this->transformVersion($extra, $extra, 'dev'); diff --git a/src/Composer/Platform/Version.php b/src/Composer/Platform/Version.php index 1429ffc69..8a3f23e4a 100644 --- a/src/Composer/Platform/Version.php +++ b/src/Composer/Platform/Version.php @@ -26,7 +26,7 @@ class Version { $isFips = false; - if (!Preg::isMatch('/^(?[0-9.]+)(?[a-z]{0,2})?(?(?:-?(?:dev|pre|alpha|beta|rc|fips)[\d]*)*)?(?-\w+)?(? \(.+?\))?$/', $opensslVersion, $matches)) { + if (!Preg::isMatchStrictGroups('/^(?[0-9.]+)(?[a-z]{0,2})(?(?:-?(?:dev|pre|alpha|beta|rc|fips)[\d]*)*)(?:-\w+)?(?: \(.+?\))?$/', $opensslVersion, $matches)) { return null; } @@ -44,7 +44,7 @@ class Version public static function parseLibjpeg(string $libjpegVersion): ?string { - if (!Preg::isMatch('/^(?\d+)(?[a-z]*)$/', $libjpegVersion, $matches)) { + if (!Preg::isMatchStrictGroups('/^(?\d+)(?[a-z]*)$/', $libjpegVersion, $matches)) { return null; } @@ -53,7 +53,7 @@ class Version public static function parseZoneinfoVersion(string $zoneinfoVersion): ?string { - if (!Preg::isMatch('/^(?\d{4})(?[a-z]*)$/', $zoneinfoVersion, $matches)) { + if (!Preg::isMatchStrictGroups('/^(?\d{4})(?[a-z]*)$/', $zoneinfoVersion, $matches)) { return null; } diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 78d9e0bd9..fa9ac4c54 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -584,7 +584,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito if ($this->hasProviders() || $this->lazyProvidersUrl) { // optimize search for "^foo/bar" where at least "^foo/" is present by loading this directly from the listUrl if present - if (Preg::isMatch('{^\^(?P(?P[a-z0-9_.-]+)/[a-z0-9_.-]*)\*?$}i', $query, $match) && $this->listUrl !== null) { + if (Preg::isMatchStrictGroups('{^\^(?P(?P[a-z0-9_.-]+)/[a-z0-9_.-]*)\*?$}i', $query, $match) && $this->listUrl !== null) { $url = $this->listUrl . '?vendor='.urlencode($match['vendor']).'&filter='.urlencode($match['query'].'*'); $result = $this->httpDownloader->get($url, $this->options)->decodeJson(); diff --git a/src/Composer/Repository/PlatformRepository.php b/src/Composer/Repository/PlatformRepository.php index 4c9d76bee..116f2b2dc 100644 --- a/src/Composer/Repository/PlatformRepository.php +++ b/src/Composer/Repository/PlatformRepository.php @@ -211,7 +211,7 @@ class PlatformRepository extends ArrayRepository } // AMQP protocol version => 0-9-1 - if (Preg::isMatch('/^AMQP protocol version => (?.+)$/im', $info, $protocolMatches)) { + if (Preg::isMatchStrictGroups('/^AMQP protocol version => (?.+)$/im', $info, $protocolMatches)) { $this->addLibrary($name.'-protocol', str_replace('-', '.', $protocolMatches['version']), 'AMQP protocol version'); } break; @@ -232,7 +232,7 @@ class PlatformRepository extends ArrayRepository $info = $this->runtime->getExtensionInfo($name); // SSL Version => OpenSSL/1.0.1t - if (Preg::isMatch('{^SSL Version => (?[^/]+)/(?.+)$}im', $info, $sslMatches)) { + if (Preg::isMatchStrictGroups('{^SSL Version => (?[^/]+)/(?.+)$}im', $info, $sslMatches)) { $library = strtolower($sslMatches['library']); if ($library === 'openssl') { $parsedVersion = Version::parseOpenssl($sslMatches['version'], $isFips); @@ -243,12 +243,12 @@ class PlatformRepository extends ArrayRepository } // libSSH Version => libssh2/1.4.3 - if (Preg::isMatch('{^libSSH Version => (?[^/]+)/(?.+?)(?:/.*)?$}im', $info, $sshMatches)) { + if (Preg::isMatchStrictGroups('{^libSSH Version => (?[^/]+)/(?.+?)(?:/.*)?$}im', $info, $sshMatches)) { $this->addLibrary($name.'-'.strtolower($sshMatches['library']), $sshMatches['version'], 'curl '.$sshMatches['library'].' version'); } // ZLib Version => 1.2.8 - if (Preg::isMatch('{^ZLib Version => (?.+)$}im', $info, $zlibMatches)) { + if (Preg::isMatchStrictGroups('{^ZLib Version => (?.+)$}im', $info, $zlibMatches)) { $this->addLibrary($name.'-zlib', $zlibMatches['version'], 'curl zlib version'); } break; @@ -257,14 +257,14 @@ class PlatformRepository extends ArrayRepository $info = $this->runtime->getExtensionInfo($name); // timelib version => 2018.03 - if (Preg::isMatch('/^timelib version => (?.+)$/im', $info, $timelibMatches)) { + if (Preg::isMatchStrictGroups('/^timelib version => (?.+)$/im', $info, $timelibMatches)) { $this->addLibrary($name.'-timelib', $timelibMatches['version'], 'date timelib version'); } // Timezone Database => internal - if (Preg::isMatch('/^Timezone Database => (?internal|external)$/im', $info, $zoneinfoSourceMatches)) { + if (Preg::isMatchStrictGroups('/^Timezone Database => (?internal|external)$/im', $info, $zoneinfoSourceMatches)) { $external = $zoneinfoSourceMatches['source'] === 'external'; - if (Preg::isMatch('/^"Olson" Timezone Database Version => (?.+?)(\.system)?$/im', $info, $zoneinfoMatches)) { + if (Preg::isMatchStrictGroups('/^"Olson" Timezone Database Version => (?.+?)(?:\.system)?$/im', $info, $zoneinfoMatches)) { // If the timezonedb is provided by ext/timezonedb, register that version as a replacement if ($external && in_array('timezonedb', $loadedExtensions, true)) { $this->addLibrary('timezonedb-zoneinfo', $zoneinfoMatches['version'], 'zoneinfo ("Olson") database for date (replaced by timezonedb)', [$name.'-zoneinfo']); @@ -289,19 +289,19 @@ class PlatformRepository extends ArrayRepository $info = $this->runtime->getExtensionInfo($name); - if (Preg::isMatch('/^libJPEG Version => (?.+?)(?: compatible)?$/im', $info, $libjpegMatches)) { + if (Preg::isMatchStrictGroups('/^libJPEG Version => (?.+?)(?: compatible)?$/im', $info, $libjpegMatches)) { $this->addLibrary($name.'-libjpeg', Version::parseLibjpeg($libjpegMatches['version']), 'libjpeg version for gd'); } - if (Preg::isMatch('/^libPNG Version => (?.+)$/im', $info, $libpngMatches)) { + if (Preg::isMatchStrictGroups('/^libPNG Version => (?.+)$/im', $info, $libpngMatches)) { $this->addLibrary($name.'-libpng', $libpngMatches['version'], 'libpng version for gd'); } - if (Preg::isMatch('/^FreeType Version => (?.+)$/im', $info, $freetypeMatches)) { + if (Preg::isMatchStrictGroups('/^FreeType Version => (?.+)$/im', $info, $freetypeMatches)) { $this->addLibrary($name.'-freetype', $freetypeMatches['version'], 'freetype version for gd'); } - if (Preg::isMatch('/^libXpm Version => (?\d+)$/im', $info, $libxpmMatches)) { + if (Preg::isMatchStrictGroups('/^libXpm Version => (?\d+)$/im', $info, $libxpmMatches)) { $this->addLibrary($name.'-libxpm', Version::convertLibxpmVersionId((int) $libxpmMatches['versionId']), 'libxpm version for gd'); } @@ -327,7 +327,7 @@ class PlatformRepository extends ArrayRepository } // ICU TZData version => 2019c - if (Preg::isMatch('/^ICU TZData version => (?.*)$/im', $info, $zoneinfoMatches) && null !== ($version = Version::parseZoneinfoVersion($zoneinfoMatches['version']))) { + if (Preg::isMatchStrictGroups('/^ICU TZData version => (?.*)$/im', $info, $zoneinfoMatches) && null !== ($version = Version::parseZoneinfoVersion($zoneinfoMatches['version']))) { $this->addLibrary('icu-zoneinfo', $version, 'zoneinfo ("Olson") database for icu'); } @@ -358,7 +358,7 @@ class PlatformRepository extends ArrayRepository case 'ldap': $info = $this->runtime->getExtensionInfo($name); - if (Preg::isMatch('/^Vendor Version => (?\d+)$/im', $info, $matches) && Preg::isMatch('/^Vendor Name => (?.+)$/im', $info, $vendorMatches)) { + if (Preg::isMatchStrictGroups('/^Vendor Version => (?\d+)$/im', $info, $matches) && Preg::isMatchStrictGroups('/^Vendor Name => (?.+)$/im', $info, $vendorMatches)) { $this->addLibrary($name.'-'.strtolower($vendorMatches['vendor']), Version::convertOpenldapVersionId((int) $matches['versionId']), $vendorMatches['vendor'].' version of ldap'); } break; @@ -402,7 +402,7 @@ class PlatformRepository extends ArrayRepository case 'openssl': // OpenSSL 1.1.1g 21 Apr 2020 - if (Preg::isMatch('{^(?:OpenSSL|LibreSSL)?\s*(?\S+)}i', $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), $matches)) { + if (Preg::isMatchStrictGroups('{^(?:OpenSSL|LibreSSL)?\s*(?\S+)}i', $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), $matches)) { $parsedVersion = Version::parseOpenssl($matches['version'], $isFips); $this->addLibrary($name.($isFips ? '-fips' : ''), $parsedVersion, $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), [], $isFips ? [$name] : []); } @@ -414,7 +414,7 @@ class PlatformRepository extends ArrayRepository $info = $this->runtime->getExtensionInfo($name); // PCRE Unicode Version => 12.1.0 - if (Preg::isMatch('/^PCRE Unicode Version => (?.+)$/im', $info, $pcreUnicodeMatches)) { + if (Preg::isMatchStrictGroups('/^PCRE Unicode Version => (?.+)$/im', $info, $pcreUnicodeMatches)) { $this->addLibrary($name.'-unicode', $pcreUnicodeMatches['version'], 'PCRE Unicode version support'); } @@ -424,7 +424,7 @@ class PlatformRepository extends ArrayRepository case 'pdo_mysql': $info = $this->runtime->getExtensionInfo($name); - if (Preg::isMatch('/^(?:Client API version|Version) => mysqlnd (?.+?) /mi', $info, $matches)) { + if (Preg::isMatchStrictGroups('/^(?:Client API version|Version) => mysqlnd (?.+?) /mi', $info, $matches)) { $this->addLibrary($name.'-mysqlnd', $matches['version'], 'mysqlnd library version for '.$name); } break; @@ -432,11 +432,11 @@ class PlatformRepository extends ArrayRepository case 'mongodb': $info = $this->runtime->getExtensionInfo($name); - if (Preg::isMatch('/^libmongoc bundled version => (?.+)$/im', $info, $libmongocMatches)) { + if (Preg::isMatchStrictGroups('/^libmongoc bundled version => (?.+)$/im', $info, $libmongocMatches)) { $this->addLibrary($name.'-libmongoc', $libmongocMatches['version'], 'libmongoc version of mongodb'); } - if (Preg::isMatch('/^libbson bundled version => (?.+)$/im', $info, $libbsonMatches)) { + if (Preg::isMatchStrictGroups('/^libbson bundled version => (?.+)$/im', $info, $libbsonMatches)) { $this->addLibrary($name.'-libbson', $libbsonMatches['version'], 'libbson version of mongodb'); } break; @@ -611,7 +611,7 @@ class PlatformRepository extends ArrayRepository $version = $this->versionParser->normalize($prettyVersion); } catch (\UnexpectedValueException $e) { $extraDescription = ' (actual version: '.$prettyVersion.')'; - if (Preg::isMatch('{^(\d+\.\d+\.\d+(?:\.\d+)?)}', $prettyVersion, $match)) { + if (Preg::isMatchStrictGroups('{^(\d+\.\d+\.\d+(?:\.\d+)?)}', $prettyVersion, $match)) { $prettyVersion = $match[1]; } else { $prettyVersion = '0'; diff --git a/src/Composer/Repository/Vcs/GitBitbucketDriver.php b/src/Composer/Repository/Vcs/GitBitbucketDriver.php index 558f2d8e0..c3b8dd8c4 100644 --- a/src/Composer/Repository/Vcs/GitBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/GitBitbucketDriver.php @@ -63,7 +63,7 @@ class GitBitbucketDriver extends VcsDriver */ public function initialize(): void { - if (!Preg::isMatch('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)?$#i', $this->url, $match)) { + if (!Preg::isMatchStrictGroups('#^https?://bitbucket\.org/([^/]+)/([^/]+?)(?:\.git|/?)?$#i', $this->url, $match)) { throw new \InvalidArgumentException(sprintf('The Bitbucket repository URL %s is invalid. It must be the HTTPS URL of a Bitbucket repository.', $this->url)); } diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index 95b30f54f..75ede6910 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -106,7 +106,7 @@ class GitDriver extends VcsDriver $branches = $this->process->splitLines($output); if (!in_array('* master', $branches)) { foreach ($branches as $branch) { - if ($branch && Preg::isMatch('{^\* +(\S+)}', $branch, $match)) { + if ($branch && Preg::isMatchStrictGroups('{^\* +(\S+)}', $branch, $match)) { $this->rootIdentifier = $match[1]; break; } @@ -203,7 +203,7 @@ class GitDriver extends VcsDriver $this->process->execute('git branch --no-color --no-abbrev -v', $output, $this->repoDir); foreach ($this->process->splitLines($output) as $branch) { if ($branch && !Preg::isMatch('{^ *[^/]+/HEAD }', $branch)) { - if (Preg::isMatch('{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}', $branch, $match) && $match[1][0] !== '-') { + if (Preg::isMatchStrictGroups('{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}', $branch, $match) && $match[1][0] !== '-') { $branches[$match[1]] = $match[2]; } } diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 7ca7bde06..98dbf989a 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -63,9 +63,11 @@ class GitHubDriver extends VcsDriver throw new \InvalidArgumentException(sprintf('The GitHub repository URL %s is invalid.', $this->url)); } + assert(is_string($match[3])); + assert(is_string($match[4])); $this->owner = $match[3]; $this->repository = $match[4]; - $this->originUrl = strtolower(!empty($match[1]) ? $match[1] : $match[2]); + $this->originUrl = strtolower($match[1] ?? (string) $match[2]); if ($this->originUrl === 'www.github.com') { $this->originUrl = 'github.com'; } @@ -227,27 +229,27 @@ class GitHubDriver extends VcsDriver $key = null; foreach (Preg::split('{\r?\n}', $funding) as $line) { $line = trim($line); - if (Preg::isMatch('{^(\w+)\s*:\s*(.+)$}', $line, $match)) { + if (Preg::isMatchStrictGroups('{^(\w+)\s*:\s*(.+)$}', $line, $match)) { if ($match[2] === '[') { $key = $match[1]; continue; } - if (Preg::isMatch('{^\[(.*)\](?:\s*#.*)?$}', $match[2], $match2)) { + if (Preg::isMatchStrictGroups('{^\[(.*)\](?:\s*#.*)?$}', $match[2], $match2)) { foreach (array_map('trim', Preg::split('{[\'"]?\s*,\s*[\'"]?}', $match2[1])) as $item) { $result[] = ['type' => $match[1], 'url' => trim($item, '"\' ')]; } - } elseif (Preg::isMatch('{^([^#].*?)(\s+#.*)?$}', $match[2], $match2)) { + } elseif (Preg::isMatchStrictGroups('{^([^#].*?)(?:\s+#.*)?$}', $match[2], $match2)) { $result[] = ['type' => $match[1], 'url' => trim($match2[1], '"\' ')]; } $key = null; - } elseif (Preg::isMatch('{^(\w+)\s*:\s*#\s*$}', $line, $match)) { + } elseif (Preg::isMatchStrictGroups('{^(\w+)\s*:\s*#\s*$}', $line, $match)) { $key = $match[1]; - } elseif ($key && ( - Preg::isMatch('{^-\s*(.+)(\s+#.*)?$}', $line, $match) - || Preg::isMatch('{^(.+),(\s*#.*)?$}', $line, $match) + } elseif ($key !== null && ( + Preg::isMatchStrictGroups('{^-\s*(.+)(?:\s+#.*)?$}', $line, $match) + || Preg::isMatchStrictGroups('{^(.+),(?:\s*#.*)?$}', $line, $match) )) { $result[] = ['type' => $key, 'url' => trim($match[1], '"\' ')]; - } elseif ($key && $line === ']') { + } elseif ($key !== null && $line === ']') { $key = null; } } @@ -395,7 +397,7 @@ class GitHubDriver extends VcsDriver return false; } - $originUrl = !empty($matches[2]) ? $matches[2] : $matches[3]; + $originUrl = $matches[2] ?? (string) $matches[3]; if (!in_array(strtolower(Preg::replace('{^www\.}i', '', $originUrl)), $config->get('github-domains'))) { return false; } diff --git a/src/Composer/Repository/Vcs/GitLabDriver.php b/src/Composer/Repository/Vcs/GitLabDriver.php index 8bdea65a9..77b183e0b 100644 --- a/src/Composer/Repository/Vcs/GitLabDriver.php +++ b/src/Composer/Repository/Vcs/GitLabDriver.php @@ -97,11 +97,13 @@ class GitLabDriver extends VcsDriver throw new \InvalidArgumentException(sprintf('The GitLab repository URL %s is invalid. It must be the HTTP URL of a GitLab project.', $this->url)); } - $guessedDomain = !empty($match['domain']) ? $match['domain'] : $match['domain2']; + assert(is_string($match['parts'])); + assert(is_string($match['repo'])); + $guessedDomain = $match['domain'] ?? (string) $match['domain2']; $configuredDomains = $this->config->get('gitlab-domains'); $urlParts = explode('/', $match['parts']); - $this->scheme = !empty($match['scheme']) + $this->scheme = in_array($match['scheme'], ['https', 'http'], true) ? $match['scheme'] : (isset($this->repoConfig['secure-http']) && $this->repoConfig['secure-http'] === false ? 'http' : 'https') ; @@ -557,8 +559,10 @@ class GitLabDriver extends VcsDriver return false; } - $scheme = !empty($match['scheme']) ? $match['scheme'] : null; - $guessedDomain = !empty($match['domain']) ? $match['domain'] : $match['domain2']; + assert(is_string($match['parts'])); + assert(is_string($match['repo'])); + $scheme = $match['scheme']; + $guessedDomain = $match['domain'] ?? (string) $match['domain2']; $urlParts = explode('/', $match['parts']); if (false === self::determineOrigin($config->get('gitlab-domains'), $guessedDomain, $urlParts, $match['port'])) { @@ -580,7 +584,7 @@ class GitLabDriver extends VcsDriver $links = explode(',', $header); foreach ($links as $link) { - if (Preg::isMatch('{<(.+?)>; *rel="next"}', $link, $match)) { + if (Preg::isMatchStrictGroups('{<(.+?)>; *rel="next"}', $link, $match)) { return $match[1]; } } diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index 477dea59c..e70b9a6ac 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -167,7 +167,7 @@ class HgDriver extends VcsDriver $this->process->execute('hg tags', $output, $this->repoDir); foreach ($this->process->splitLines($output) as $tag) { - if ($tag && Preg::isMatch('(^([^\s]+)\s+\d+:(.*)$)', $tag, $match)) { + if ($tag && Preg::isMatchStrictGroups('(^([^\s]+)\s+\d+:(.*)$)', $tag, $match)) { $tags[$match[1]] = $match[2]; } } @@ -190,14 +190,14 @@ class HgDriver extends VcsDriver $this->process->execute('hg branches', $output, $this->repoDir); foreach ($this->process->splitLines($output) as $branch) { - if ($branch && Preg::isMatch('(^([^\s]+)\s+\d+:([a-f0-9]+))', $branch, $match) && $match[1][0] !== '-') { + if ($branch && Preg::isMatchStrictGroups('(^([^\s]+)\s+\d+:([a-f0-9]+))', $branch, $match) && $match[1][0] !== '-') { $branches[$match[1]] = $match[2]; } } $this->process->execute('hg bookmarks', $output, $this->repoDir); foreach ($this->process->splitLines($output) as $branch) { - if ($branch && Preg::isMatch('(^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$)', $branch, $match) && $match[1][0] !== '-') { + if ($branch && Preg::isMatchStrictGroups('(^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$)', $branch, $match) && $match[1][0] !== '-') { $bookmarks[$match[1]] = $match[2]; } } diff --git a/src/Composer/Repository/Vcs/SvnDriver.php b/src/Composer/Repository/Vcs/SvnDriver.php index d1d67a14c..f2bfad0f7 100644 --- a/src/Composer/Repository/Vcs/SvnDriver.php +++ b/src/Composer/Repository/Vcs/SvnDriver.php @@ -207,7 +207,7 @@ class SvnDriver extends VcsDriver $identifier = '/' . trim($identifier, '/') . '/'; Preg::match('{^(.+?)(@\d+)?/$}', $identifier, $match); - if (!empty($match[2])) { + if (null !== $match[2] && null !== $match[1]) { $path = $match[1]; $rev = $match[2]; } else { @@ -217,7 +217,7 @@ class SvnDriver extends VcsDriver $output = $this->execute('svn info', $this->baseUrl . $path . $rev); foreach ($this->process->splitLines($output) as $line) { - if ($line && Preg::isMatch('{^Last Changed Date: ([^(]+)}', $line, $match)) { + if ($line && Preg::isMatchStrictGroups('{^Last Changed Date: ([^(]+)}', $line, $match)) { return new \DateTimeImmutable($match[1], new \DateTimeZone('UTC')); } } diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 5bbc5a04e..e0f008d14 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -564,7 +564,7 @@ class Filesystem } // extract a prefix being a protocol://, protocol:, protocol://drive: or simply drive: - if (Preg::isMatch('{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix', $path, $match)) { + if (Preg::isMatchStrictGroups('{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix', $path, $match)) { $prefix = $match[1]; $path = substr($path, \strlen($prefix)); } diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index 80521ca3b..c1da74d42 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -62,14 +62,14 @@ class Git if (!$initialClone) { // capture username/password from URL if there is one and we have no auth configured yet $this->process->execute('git remote -v', $output, $cwd); - if (Preg::isMatch('{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im', $output, $match) && !$this->io->hasAuthentication($match[3])) { + if (Preg::isMatchStrictGroups('{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im', $output, $match) && !$this->io->hasAuthentication($match[3])) { $this->io->setAuthentication($match[3], rawurldecode($match[1]), rawurldecode($match[2])); } } $protocols = $this->config->get('github-protocols'); // public github, autoswitch protocols - if (Preg::isMatch('{^(?:https?|git)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)) { + if (Preg::isMatchStrictGroups('{^(?:https?|git)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)) { $messages = []; foreach ($protocols as $protocol) { if ('ssh' === $protocol) { @@ -104,8 +104,8 @@ class Git if ($bypassSshForGitHub || 0 !== $this->process->execute($command, $commandOutput, $cwd)) { $errorMsg = $this->process->getErrorOutput(); // private github repository without ssh key access, try https with auth - if (Preg::isMatch('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match) - || Preg::isMatch('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*?)(?:\.git)?$}i', $url, $match) + if (Preg::isMatchStrictGroups('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match) + || Preg::isMatchStrictGroups('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*?)(?:\.git)?$}i', $url, $match) ) { if (!$this->io->hasAuthentication($match[1])) { $gitHubUtil = new GitHub($this->io, $this->config, $this->process); @@ -127,7 +127,7 @@ class Git $credentials = [rawurlencode($auth['username']), rawurlencode($auth['password'])]; $errorMsg = $this->process->getErrorOutput(); } - } elseif (Preg::isMatch('{^https://(bitbucket\.org)/(.*?)(?:\.git)?$}i', $url, $match)) { //bitbucket oauth + } elseif (Preg::isMatchStrictGroups('{^https://(bitbucket\.org)/(.*?)(?:\.git)?$}i', $url, $match)) { //bitbucket oauth $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process); if (!$this->io->hasAuthentication($match[1])) { @@ -172,8 +172,8 @@ class Git $errorMsg = $this->process->getErrorOutput(); } } elseif ( - Preg::isMatch('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match) - || Preg::isMatch('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}i', $url, $match) + Preg::isMatchStrictGroups('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match) + || Preg::isMatchStrictGroups('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}i', $url, $match) ) { if ($match[1] === 'git') { $match[1] = 'https'; diff --git a/src/Composer/Util/Hg.php b/src/Composer/Util/Hg.php index f6a4275f7..0e9f6e58f 100644 --- a/src/Composer/Util/Hg.php +++ b/src/Composer/Util/Hg.php @@ -58,9 +58,9 @@ class Hg } // Try with the authentication information available - if (Preg::isMatch('{^(https?)://((.+)(?:\:(.+))?@)?([^/]+)(/.*)?}mi', $url, $match) && $this->io->hasAuthentication($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); + if (Preg::isMatch('{^(https?)://((.+)(?:\:(.+))?@)?([^/]+)(/.*)?}mi', $url, $match) && $this->io->hasAuthentication((string) $match[5])) { + $auth = $this->io->getAuthentication((string) $match[5]); + $authenticatedUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[5] . $match[6]; $command = $commandCallable($authenticatedUrl); diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 5e6e0c56b..58a64b663 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -218,7 +218,7 @@ class HttpDownloader } // capture username/password from URL if there is one - if (Preg::isMatch('{^https?://([^:/]+):([^@/]+)@([^/]+)}i', $request['url'], $match)) { + if (Preg::isMatchStrictGroups('{^https?://([^:/]+):([^@/]+)@([^/]+)}i', $request['url'], $match)) { $this->io->setAuthentication($job['origin'], rawurldecode($match[1]), rawurldecode($match[2])); } diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index e66b6cc5a..a8f69eceb 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -460,7 +460,7 @@ class ProcessExecutor // In addition to whitespace, commas need quoting to preserve paths $quote = strpbrk($argument, " \t,") !== false; $argument = Preg::replace('/(\\\\*)"/', '$1$1\\"', $argument, -1, $dquotes); - $meta = $dquotes || Preg::isMatch('/%[^%]+%|![^!]+!/', $argument); + $meta = $dquotes > 0 || Preg::isMatch('/%[^%]+%|![^!]+!/', $argument); if (!$meta && !$quote) { $quote = strpbrk($argument, '^&|<>()') !== false; diff --git a/tests/Composer/Test/AllFunctionalTest.php b/tests/Composer/Test/AllFunctionalTest.php index f006d756c..2f4cfc722 100644 --- a/tests/Composer/Test/AllFunctionalTest.php +++ b/tests/Composer/Test/AllFunctionalTest.php @@ -135,12 +135,12 @@ class AllFunctionalTest extends TestCase $line++; } if ($expected[$i] === '%') { - Preg::isMatch('{%(.+?)%}', substr($expected, $i), $match); + Preg::isMatchStrictGroups('{%(.+?)%}', substr($expected, $i), $match); $regex = $match[1]; if (Preg::isMatch('{'.$regex.'}', substr($output, $j), $match)) { $i += strlen($regex) + 2; - $j += strlen($match[0]); + $j += strlen((string) $match[0]); continue; } else { $this->fail(