From 91dd175f748bf45da10699101eff429a7f444784 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 3 Jun 2021 10:17:54 +0200 Subject: [PATCH] Fix env var handling when variables_order includes E and symfony/console 3.3.15+ is used, fixes #9930 --- bin/composer | 4 +-- src/Composer/Autoload/AutoloadGenerator.php | 4 +-- src/Composer/Command/CreateProjectCommand.php | 4 +-- src/Composer/Command/GlobalCommand.php | 4 +-- src/Composer/Command/RunScriptCommand.php | 4 +-- src/Composer/Console/Application.php | 3 +-- .../EventDispatcher/EventDispatcher.php | 15 ++++++----- src/Composer/Installer.php | 4 +-- src/Composer/Util/Git.php | 15 ++++------- src/Composer/Util/Platform.php | 27 +++++++++++++++++++ src/Composer/Util/Svn.php | 3 +-- tests/Composer/Test/ApplicationTest.php | 7 +++++ 12 files changed, 61 insertions(+), 33 deletions(-) diff --git a/bin/composer b/bin/composer index ca6ecc6b5..385508e75 100755 --- a/bin/composer +++ b/bin/composer @@ -10,6 +10,7 @@ require __DIR__.'/../src/bootstrap.php'; use Composer\Console\Application; use Composer\XdebugHandler\XdebugHandler; +use Composer\Util\Platform; error_reporting(-1); @@ -57,8 +58,7 @@ if (function_exists('ini_set')) { unset($memoryLimit); } -$_SERVER['COMPOSER_BINARY'] = realpath($_SERVER['argv'][0]); -putenv('COMPOSER_BINARY='.$_SERVER['COMPOSER_BINARY']); +Platform::setEnv('COMPOSER_BINARY', realpath($_SERVER['argv'][0])); // run the command application $application = new Application(); diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 8d7bd73a4..474efcbd5 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -24,6 +24,7 @@ use Composer\Repository\PlatformRepository; use Composer\Semver\Constraint\Bound; use Composer\Semver\Constraint\MatchAllConstraint; use Composer\Util\Filesystem; +use Composer\Util\Platform; use Composer\Script\ScriptEvents; use Composer\Util\PackageSorter; use Composer\Json\JsonFile; @@ -158,8 +159,7 @@ class AutoloadGenerator // set COMPOSER_DEV_MODE in case not set yet so it is available in the dump-autoload autoload if (!isset($_SERVER['COMPOSER_DEV_MODE'])) { - $_SERVER['COMPOSER_DEV_MODE'] = $this->devMode ? '1' : '0'; - putenv('COMPOSER_DEV_MODE='.$_SERVER['COMPOSER_DEV_MODE']); + Platform::putEnv('COMPOSER_DEV_MODE', $this->devMode ? '1' : '0'); } $this->eventDispatcher->dispatchScript(ScriptEvents::PRE_AUTOLOAD_DUMP, $this->devMode, array(), array( diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index 4734f9cab..9bdd33ae3 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -37,6 +37,7 @@ use Symfony\Component\Finder\Finder; use Composer\Json\JsonFile; use Composer\Config\JsonConfigSource; use Composer\Util\Filesystem; +use Composer\Util\Platform; use Composer\Util\ProcessExecutor; use Composer\Package\Version\VersionParser; @@ -453,8 +454,7 @@ EOT $io->writeError('Created project in ' . $directory . ''); chdir($directory); - $_SERVER['COMPOSER_ROOT_VERSION'] = $package->getPrettyVersion(); - putenv('COMPOSER_ROOT_VERSION='.$_SERVER['COMPOSER_ROOT_VERSION']); + Platform::putEnv('COMPOSER_ROOT_VERSION', $package->getPrettyVersion()); return $installedFromVcs; } diff --git a/src/Composer/Command/GlobalCommand.php b/src/Composer/Command/GlobalCommand.php index 96a6b5f5e..c78ea7109 100644 --- a/src/Composer/Command/GlobalCommand.php +++ b/src/Composer/Command/GlobalCommand.php @@ -14,6 +14,7 @@ namespace Composer\Command; use Composer\Factory; use Composer\Util\Filesystem; +use Composer\Util\Platform; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\StringInput; @@ -81,8 +82,7 @@ EOT // The COMPOSER env var should not apply to the global execution scope if (getenv('COMPOSER')) { - putenv('COMPOSER'); - unset($_SERVER['COMPOSER']); + Platform::clearEnv('COMPOSER'); } // change to global dir diff --git a/src/Composer/Command/RunScriptCommand.php b/src/Composer/Command/RunScriptCommand.php index c45507b1f..1ecf1e0c1 100644 --- a/src/Composer/Command/RunScriptCommand.php +++ b/src/Composer/Command/RunScriptCommand.php @@ -15,6 +15,7 @@ namespace Composer\Command; use Composer\Script\Event as ScriptEvent; use Composer\Script\ScriptEvents; use Composer\Util\ProcessExecutor; +use Composer\Util\Platform; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; @@ -103,8 +104,7 @@ EOT ProcessExecutor::setTimeout((int) $timeout); } - $_SERVER['COMPOSER_DEV_MODE'] = $devMode ? '1' : '0'; - putenv('COMPOSER_DEV_MODE='.$_SERVER['COMPOSER_DEV_MODE']); + Platform::putEnv('COMPOSER_DEV_MODE', $devMode ? '1' : '0'); return $composer->getEventDispatcher()->dispatchScript($script, $devMode, $args); } diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index bdb8700aa..177f7220a 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -143,8 +143,7 @@ class Application extends BaseApplication if ($input->hasParameterOption('--no-cache')) { $io->writeError('Disabling cache usage', true, IOInterface::DEBUG); - $_SERVER['COMPOSER_CACHE_DIR'] = Platform::isWindows() ? 'nul' : '/dev/null'; - putenv('COMPOSER_CACHE_DIR='.$_SERVER['COMPOSER_CACHE_DIR']); + Platform::putEnv('COMPOSER_CACHE_DIR', Platform::isWindows() ? 'nul' : '/dev/null'); } // switch working dir diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index a18112c4b..5a06314d8 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -247,9 +247,12 @@ class EventDispatcher } if (strpos($exec, '@putenv ') === 0) { - putenv(substr($exec, 8)); - list($var, $value) = explode('=', substr($exec, 8), 2); - $_SERVER[$var] = $value; + if (false === strpos($exec, '=')) { + Platform::clearEnv(substr($exec, 8)); + } else { + list($var, $value) = explode('=', substr($exec, 8), 2); + Platform::putEnv($var, $value); + } continue; } @@ -274,8 +277,7 @@ class EventDispatcher $finder = new PhpExecutableFinder(); $phpPath = $finder->find(false); if ($phpPath) { - $_SERVER['PHP_BINARY'] = $phpPath; - putenv('PHP_BINARY=' . $_SERVER['PHP_BINARY']); + Platform::putEnv('PHP_BINARY', $phpPath); } if (Platform::isWindows()) { @@ -539,8 +541,7 @@ class EventDispatcher if (is_dir($binDir)) { $binDir = realpath($binDir); if (isset($_SERVER[$pathStr]) && !preg_match('{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', $_SERVER[$pathStr])) { - $_SERVER[$pathStr] = $binDir.PATH_SEPARATOR.getenv($pathStr); - putenv($pathStr.'='.$_SERVER[$pathStr]); + Platform::putEnv($pathStr, $binDir.PATH_SEPARATOR.getenv($pathStr)); } } } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 8e2a49367..c803edfdf 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -56,6 +56,7 @@ use Composer\Repository\RepositoryInterface; use Composer\Repository\RepositoryManager; use Composer\Repository\LockArrayRepository; use Composer\Script\ScriptEvents; +use Composer\Util\Platform; /** * @author Jordi Boggiano @@ -224,8 +225,7 @@ class Installer } if ($this->runScripts) { - $_SERVER['COMPOSER_DEV_MODE'] = $this->devMode ? '1' : '0'; - putenv('COMPOSER_DEV_MODE='.$_SERVER['COMPOSER_DEV_MODE']); + Platform::putEnv('COMPOSER_DEV_MODE', $this->devMode ? '1' : '0'); // dispatch pre event // should we treat this more strictly as running an update and then running an install, triggering events multiple times? diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index 3290c6d85..67d42b7c2 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -353,29 +353,24 @@ class Git // added in git 1.7.1, prevents prompting the user for username/password if (getenv('GIT_ASKPASS') !== 'echo') { - putenv('GIT_ASKPASS=echo'); - $_SERVER['GIT_ASKPASS'] = 'echo'; + Platform::putEnv('GIT_ASKPASS', 'echo'); } // clean up rogue git env vars in case this is running in a git hook if (getenv('GIT_DIR')) { - putenv('GIT_DIR'); - unset($_SERVER['GIT_DIR']); + Platform::clearEnv('GIT_DIR'); } if (getenv('GIT_WORK_TREE')) { - putenv('GIT_WORK_TREE'); - unset($_SERVER['GIT_WORK_TREE']); + Platform::clearEnv('GIT_WORK_TREE'); } // Run processes with predictable LANGUAGE if (getenv('LANGUAGE') !== 'C') { - putenv('LANGUAGE=C'); - $_SERVER['LANGUAGE'] = 'C'; + Platform::putEnv('LANGUAGE', 'C'); } // clean up env for OSX, see https://github.com/composer/composer/issues/2146#issuecomment-35478940 - putenv("DYLD_LIBRARY_PATH"); - unset($_SERVER['DYLD_LIBRARY_PATH']); + Platform::clearEnv('DYLD_LIBRARY_PATH'); } public static function getGitHubDomainsRegex(Config $config) diff --git a/src/Composer/Util/Platform.php b/src/Composer/Util/Platform.php index 5693247c8..deca14db2 100644 --- a/src/Composer/Util/Platform.php +++ b/src/Composer/Util/Platform.php @@ -24,6 +24,33 @@ class Platform /** @var ?bool */ private static $isWindowsSubsystemForLinux = null; + /** + * putenv() equivalent but updates the runtime global variables too + * + * @param string $name + * @param string $value + * @return void + */ + public function putEnv($name, $value) + { + $value = (string) $value; + putenv($name . '=' . $value); + $_SERVER[$name] = $_ENV[$name] = $value; + } + + /** + * putenv('X') equivalent but updates the runtime global variables too + * + * @param string $name + * @param string $value + * @return void + */ + public function clearEnv($name) + { + putenv($name); + unset($_SERVER[$name], $_ENV[$name]); + } + /** * Parses tildes and environment variables in paths. * diff --git a/src/Composer/Util/Svn.php b/src/Composer/Util/Svn.php index da934c161..2f7d070ab 100644 --- a/src/Composer/Util/Svn.php +++ b/src/Composer/Util/Svn.php @@ -85,8 +85,7 @@ class Svn public static function cleanEnv() { // clean up env for OSX, see https://github.com/composer/composer/issues/2146#issuecomment-35478940 - putenv("DYLD_LIBRARY_PATH"); - unset($_SERVER['DYLD_LIBRARY_PATH']); + Platform::clearEnv('DYLD_LIBRARY_PATH'); } /** diff --git a/tests/Composer/Test/ApplicationTest.php b/tests/Composer/Test/ApplicationTest.php index 31fdcd1ec..f3fb28ab2 100644 --- a/tests/Composer/Test/ApplicationTest.php +++ b/tests/Composer/Test/ApplicationTest.php @@ -18,6 +18,13 @@ use Symfony\Component\Console\Output\OutputInterface; class ApplicationTest extends TestCase { + public function tearDown() + { + parent::tearDown(); + + putenv('COMPOSER_NO_INTERACTION'); + } + public function testDevWarning() { $application = new Application;