diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php
index 9148d9f34..0f45f8717 100644
--- a/src/Composer/Command/SelfUpdateCommand.php
+++ b/src/Composer/Command/SelfUpdateCommand.php
@@ -100,7 +100,7 @@ EOT
// switch channel if requested
$requestedChannel = null;
- foreach (Versions::$channels as $channel) {
+ foreach (Versions::CHANNELS as $channel) {
if ($input->getOption($channel)) {
$requestedChannel = $channel;
$versionsUtil->setChannel($channel);
@@ -115,7 +115,10 @@ EOT
$cacheDir = $config->get('cache-dir');
$rollbackDir = $config->get('data-dir');
$home = $config->get('home');
- $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
+ $localFilename = realpath($_SERVER['argv'][0]);
+ if (false === $localFilename) {
+ $localFilename = $_SERVER['argv'][0];
+ }
if ($input->getOption('update-keys')) {
$this->fetchKeys($io, $config);
@@ -138,10 +141,13 @@ EOT
// check if composer is running as the same user that owns the directory root, only if POSIX is defined and callable
if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) {
- $composeUser = posix_getpwuid(posix_geteuid());
- $homeOwner = posix_getpwuid(fileowner($home));
- if (isset($composeUser['name'], $homeOwner['name']) && $composeUser['name'] !== $homeOwner['name']) {
- $io->writeError('You are running Composer as "'.$composeUser['name'].'", while "'.$home.'" is owned by "'.$homeOwner['name'].'"');
+ $composerUser = posix_getpwuid(posix_geteuid());
+ $homeDirOwnerId = fileowner($home);
+ if (is_array($composerUser) && $homeDirOwnerId !== false) {
+ $homeOwner = posix_getpwuid($homeDirOwnerId);
+ if (is_array($homeOwner) && isset($composerUser['name'], $homeOwner['name']) && $composerUser['name'] !== $homeOwner['name']) {
+ $io->writeError('You are running Composer as "'.$composerUser['name'].'", while "'.$home.'" is owned by "'.$homeOwner['name'].'"');
+ }
}
}
@@ -157,12 +163,12 @@ EOT
$latestPreview = $latestStable;
}
$latestVersion = $latest['version'];
- $updateVersion = $input->getArgument('version') ?: $latestVersion;
+ $updateVersion = $input->getArgument('version') ?? $latestVersion;
$currentMajorVersion = Preg::replace('{^(\d+).*}', '$1', Composer::getVersion());
$updateMajorVersion = Preg::replace('{^(\d+).*}', '$1', $updateVersion);
$previewMajorVersion = Preg::replace('{^(\d+).*}', '$1', $latestPreview['version']);
- if ($versionsUtil->getChannel() === 'stable' && !$input->getArgument('version')) {
+ if ($versionsUtil->getChannel() === 'stable' && null === $input->getArgument('version')) {
// if requesting stable channel and no specific version, avoid automatically upgrading to the next major
// simply output a warning that the next major stable is available and let users upgrade to it manually
if ($currentMajorVersion < $updateMajorVersion) {
@@ -243,7 +249,7 @@ EOT
$httpDownloader->copy($remoteFilename, $tempFilename);
$io->writeError('');
- if (!file_exists($tempFilename) || !$signature) {
+ if (!file_exists($tempFilename) || null === $signature || '' === $signature) {
$io->writeError('The download of the new composer version failed for an unexpected reason');
return 1;
@@ -306,12 +312,15 @@ TAGSPUBKEY
throw new \RuntimeException('Failed loading the public key from '.$sigFile);
}
$algo = defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'SHA384';
- if (!in_array('sha384', array_map('strtolower', openssl_get_md_methods()))) {
+ if (!in_array('sha384', array_map('strtolower', openssl_get_md_methods()), true)) {
throw new \RuntimeException('SHA384 is not supported by your openssl extension, could not verify the phar file integrity');
}
- $signature = json_decode($signature, true);
- $signature = base64_decode($signature['sha384']);
- $verified = 1 === openssl_verify(file_get_contents($tempFilename), $signature, $pubkeyid, $algo);
+ $signatureData = json_decode($signature, true);
+ $signatureSha384 = base64_decode($signatureData['sha384'], true);
+ if (false === $signatureSha384) {
+ throw new \RuntimeException('Failed loading the phar signature from '.$remoteFilename.'.sig, got '.$signature);
+ }
+ $verified = 1 === openssl_verify((string) file_get_contents($tempFilename), $signatureSha384, $pubkeyid, $algo);
// PHP 8 automatically frees the key instance and deprecates the function
if (PHP_VERSION_ID < 80000) {
@@ -405,7 +414,7 @@ TAGSPUBKEY
protected function rollback(OutputInterface $output, string $rollbackDir, string $localFilename): int
{
$rollbackVersion = $this->getLastBackupVersion($rollbackDir);
- if (!$rollbackVersion) {
+ if (null === $rollbackVersion) {
throw new \UnexpectedValueException('Composer rollback failed: no installation to roll back to in "'.$rollbackDir.'"');
}
@@ -439,13 +448,16 @@ TAGSPUBKEY
protected function setLocalPhar(string $localFilename, string $newFilename, string $backupTarget = null): bool
{
$io = $this->getIO();
- @chmod($newFilename, fileperms($localFilename));
+ $perms = @fileperms($localFilename);
+ if ($perms !== false) {
+ @chmod($newFilename, $perms);
+ }
// check phar validity
if (!$this->validatePhar($newFilename, $error)) {
- $io->writeError('The '.($backupTarget ? 'update' : 'backup').' file is corrupted ('.$error.')');
+ $io->writeError('The '.($backupTarget !== null ? 'update' : 'backup').' file is corrupted ('.$error.')');
- if ($backupTarget) {
+ if ($backupTarget !== null) {
$io->writeError('Please re-run the self-update command to try again.');
}
@@ -453,7 +465,7 @@ TAGSPUBKEY
}
// copy current file into backups dir
- if ($backupTarget) {
+ if ($backupTarget !== null) {
@copy($localFilename, $backupTarget);
}
@@ -477,7 +489,7 @@ TAGSPUBKEY
}
@unlink($newFilename);
- $action = 'Composer '.($backupTarget ? 'update' : 'rollback');
+ $action = 'Composer '.($backupTarget !== null ? 'update' : 'rollback');
throw new FilesystemException($action.' failed: "'.$localFilename.'" could not be written.'.PHP_EOL.$e->getMessage());
}
}
@@ -495,7 +507,7 @@ TAGSPUBKEY
$fs = new Filesystem;
foreach ($finder as $file) {
- if ($except && $file->getBasename(self::OLD_INSTALL_EXT) === $except) {
+ if ($file->getBasename(self::OLD_INSTALL_EXT) === $except) {
continue;
}
$file = (string) $file;
@@ -504,21 +516,17 @@ TAGSPUBKEY
}
}
- /**
- * @param string $rollbackDir
- * @return string|false
- */
- protected function getLastBackupVersion(string $rollbackDir)
+ protected function getLastBackupVersion(string $rollbackDir): ?string
{
$finder = $this->getOldInstallationFinder($rollbackDir);
$finder->sortByName();
$files = iterator_to_array($finder);
- if (count($files)) {
+ if (count($files) > 0) {
return end($files)->getBasename(self::OLD_INSTALL_EXT);
}
- return false;
+ return null;
}
/**
@@ -548,7 +556,7 @@ TAGSPUBKEY
*/
protected function validatePhar(string $pharFile, ?string &$error): bool
{
- if (ini_get('phar.readonly')) {
+ if ((bool) ini_get('phar.readonly')) {
return true;
}
@@ -610,6 +618,11 @@ TAGSPUBKEY
}
$tmpFile = tempnam(sys_get_temp_dir(), '');
+ if (false === $tmpFile) {
+ $io->writeError('Operation failed.'.$helpMessage.'');
+
+ return false;
+ }
$script = $tmpFile.'.vbs';
rename($tmpFile, $script);
diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php
index 5b03b8faf..ba140a149 100644
--- a/src/Composer/Console/Application.php
+++ b/src/Composer/Console/Application.php
@@ -548,7 +548,7 @@ class Application extends BaseApplication
new Command\ReinstallCommand(),
));
- if (strpos(__FILE__, 'phar:') === 0) {
+ if (strpos(__FILE__, 'phar:') === 0 || '1' === Platform::getEnv('COMPOSER_TESTS_ARE_RUNNING')) {
$commands[] = new Command\SelfUpdateCommand();
}
diff --git a/src/Composer/SelfUpdate/Versions.php b/src/Composer/SelfUpdate/Versions.php
index 0390cc08d..6a9c90120 100644
--- a/src/Composer/SelfUpdate/Versions.php
+++ b/src/Composer/SelfUpdate/Versions.php
@@ -21,8 +21,13 @@ use Composer\Config;
*/
class Versions
{
- /** @var string[] */
- public static $channels = array('stable', 'preview', 'snapshot', '1', '2', '2.2');
+ /**
+ * @var string[]
+ * @deprecated use Versions::CHANNELS
+ */
+ public static $channels = self::CHANNELS;
+
+ public const CHANNELS = ['stable', 'preview', 'snapshot', '1', '2', '2.2'];
/** @var HttpDownloader */
private $httpDownloader;
diff --git a/tests/console-application.php b/tests/console-application.php
index 9a8b9750a..f0b740c84 100644
--- a/tests/console-application.php
+++ b/tests/console-application.php
@@ -12,4 +12,6 @@
require __DIR__ . '/../vendor/autoload.php';
+\Composer\Util\Platform::putEnv('COMPOSER_TESTS_ARE_RUNNING', '1');
+
return new \Composer\Console\Application();