1
0
Fork 0

Read first from $_SERVER and $_ENV before using getenv (#10218)

pull/10248/head
Jordi Boggiano 2021-11-09 16:31:27 +01:00 committed by GitHub
parent 1900f0e6e0
commit bd4d624cc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 90 additions and 63 deletions

View File

@ -14,6 +14,7 @@ namespace Composer;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
use Composer\Util\Platform;
use Composer\Util\Silencer;
use Symfony\Component\Finder\Finder;
@ -242,7 +243,7 @@ class Cache
}
self::$cacheCollected = true;
if (getenv('COMPOSER_TEST_SUITE')) {
if (Platform::getEnv('COMPOSER_TEST_SUITE')) {
return false;
}

View File

@ -213,7 +213,7 @@ EOT
{
// Open file in editor
if ($input->getOption('editor')) {
$editor = escapeshellcmd(getenv('EDITOR'));
$editor = escapeshellcmd(Platform::getEnv('EDITOR'));
if (!$editor) {
if (Platform::isWindows()) {
$editor = 'notepad';

View File

@ -88,7 +88,7 @@ EOT
}
// The COMPOSER env var should not apply to the global execution scope
if (getenv('COMPOSER')) {
if (Platform::getEnv('COMPOSER')) {
Platform::clearEnv('COMPOSER');
}

View File

@ -330,7 +330,7 @@ class Config
return (int) $this->config['cache-ttl'];
case 'home':
$val = preg_replace('#^(\$HOME|~)(/|$)#', rtrim(getenv('HOME') ?: 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), '/\\');
@ -462,7 +462,7 @@ class Config
return $path;
}
return $this->baseDir . '/' . $path;
return $this->baseDir ? $this->baseDir . '/' . $path : $path;
}
/**
@ -477,7 +477,7 @@ class Config
private function getComposerEnv($var)
{
if ($this->useEnvironment) {
return getenv($var);
return Platform::getEnv($var);
}
return false;

View File

@ -135,7 +135,7 @@ class Application extends BaseApplication
{
$this->disablePluginsByDefault = $input->hasParameterOption('--no-plugins');
if (getenv('COMPOSER_NO_INTERACTION') || !Platform::isTty(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'))) {
if (Platform::getEnv('COMPOSER_NO_INTERACTION') || !Platform::isTty(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'))) {
$input->setInteractive(false);
}
@ -174,7 +174,7 @@ class Application extends BaseApplication
// prompt user for dir change if no composer.json is present in current dir
if ($io->isInteractive() && !$newWorkDir && !in_array($commandName, array('', 'list', 'init', 'about', 'help', 'diagnose', 'self-update', 'global', 'create-project', 'outdated'), true) && !file_exists(Factory::getComposerFile())) {
$dir = dirname(getcwd());
$home = realpath(getenv('HOME') ?: getenv('USERPROFILE') ?: '/');
$home = realpath(Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE') ?: '/');
// abort when we reach the home dir or top of the filesystem
while (dirname($dir) !== $dir && $dir !== $home) {
@ -253,7 +253,7 @@ class Application extends BaseApplication
$io->writeError('<warning>Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.</warning>');
}
if (XdebugHandler::isXdebugActive() && !getenv('COMPOSER_DISABLE_XDEBUG_WARN')) {
if (XdebugHandler::isXdebugActive() && !Platform::getEnv('COMPOSER_DISABLE_XDEBUG_WARN')) {
$io->writeError('<warning>Composer is operating slower than normal because you have Xdebug enabled. See https://getcomposer.org/xdebug</warning>');
}
@ -264,7 +264,7 @@ class Application extends BaseApplication
if (
!Platform::isWindows()
&& function_exists('exec')
&& !getenv('COMPOSER_ALLOW_SUPERUSER')
&& !Platform::getEnv('COMPOSER_ALLOW_SUPERUSER')
&& (ini_get('open_basedir') || !file_exists('/.dockerenv'))
) {
if (function_exists('posix_getuid') && posix_getuid() === 0) {
@ -277,7 +277,7 @@ class Application extends BaseApplication
}
}
}
if ($uid = (int) getenv('SUDO_UID')) {
if ($uid = (int) Platform::getEnv('SUDO_UID')) {
// Silently clobber any sudo credentials on the invoking user to avoid privilege escalations later on
// ref. https://github.com/composer/composer/issues/5119
Silencer::call('exec', "sudo -u \\#{$uid} sudo -K > /dev/null 2>&1");

View File

@ -13,6 +13,7 @@
namespace Composer\Console;
use Composer\IO\IOInterface;
use Composer\Util\Platform;
final class GithubActionError
{
@ -35,7 +36,7 @@ final class GithubActionError
*/
public function emit($message, $file = null, $line = null)
{
if (getenv('GITHUB_ACTIONS') && !getenv('COMPOSER_TESTS_ARE_RUNNING')) {
if (Platform::getEnv('GITHUB_ACTIONS') && !Platform::getEnv('COMPOSER_TESTS_ARE_RUNNING')) {
$message = $this->escapeData($message);
if ($file && $line) {

View File

@ -99,7 +99,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
} else {
$msg = "Cloning ".$this->getShortHash($ref);
$command = 'git clone --no-checkout -- %url% %path% && cd '.$flag.'%path% && git remote add composer -- %url% && git fetch composer && git remote set-url origin -- %sanitizedUrl% && git remote set-url composer -- %sanitizedUrl%';
if (getenv('COMPOSER_DISABLE_NETWORK')) {
if (Platform::getEnv('COMPOSER_DISABLE_NETWORK')) {
throw new \RuntimeException('The required git reference for '.$package->getName().' is not in cache and network is disabled, aborting');
}
}
@ -157,7 +157,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
} else {
$msg = "Checking out ".$this->getShortHash($ref);
$command = '(git remote set-url composer -- %url% && git rev-parse --quiet --verify %ref% || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- %sanitizedUrl%';
if (getenv('COMPOSER_DISABLE_NETWORK')) {
if (Platform::getEnv('COMPOSER_DISABLE_NETWORK')) {
throw new \RuntimeException('The required git reference for '.$target->getName().' is not in cache and network is disabled, aborting');
}
}

View File

@ -255,7 +255,7 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
$currentStrategy = self::STRATEGY_SYMLINK;
$allowedStrategies = array(self::STRATEGY_SYMLINK, self::STRATEGY_MIRROR);
$mirrorPathRepos = getenv('COMPOSER_MIRROR_PATH_REPOS');
$mirrorPathRepos = Platform::getEnv('COMPOSER_MIRROR_PATH_REPOS');
if ($mirrorPathRepos) {
$currentStrategy = self::STRATEGY_MIRROR;
}

View File

@ -161,7 +161,7 @@ class EventDispatcher
*/
protected function doDispatch(Event $event)
{
if (getenv('COMPOSER_DEBUG_EVENTS')) {
if (Platform::getEnv('COMPOSER_DEBUG_EVENTS')) {
$details = null;
if ($event instanceof PackageEvent) {
$details = (string) $event->getOperation();
@ -199,7 +199,7 @@ class EventDispatcher
$args = array_merge($script, $event->getArguments());
$flags = $event->getFlags();
if (strpos($callable, '@composer ') === 0) {
$exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . ' ' . implode(' ', $args);
$exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(Platform::getEnv('COMPOSER_BINARY')) . ' ' . implode(' ', $args);
if (0 !== ($exitCode = $this->executeTty($exec))) {
$this->io->writeError(sprintf('<error>Script %s handling the %s event returned with error code '.$exitCode.'</error>', $callable, $event->getName()), true, IOInterface::QUIET);
@ -306,7 +306,7 @@ class EventDispatcher
// resolution, even if bin-dir contains composer too because the project requires composer/composer
// see https://github.com/composer/composer/issues/8748
if (strpos($exec, 'composer ') === 0) {
$exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . substr($exec, 8);
$exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(Platform::getEnv('COMPOSER_BINARY')) . substr($exec, 8);
}
if (0 !== ($exitCode = $this->executeTty($exec))) {
@ -565,17 +565,18 @@ class EventDispatcher
*/
private function ensureBinDirIsInPath()
{
$pathStr = 'PATH';
if (!isset($_SERVER[$pathStr]) && isset($_SERVER['Path'])) {
$pathStr = 'Path';
$pathEnv = 'PATH';
if (false === Platform::getEnv('PATH') && false !== Platform::getEnv('Path')) {
$pathEnv = 'Path';
}
// add the bin dir to the PATH to make local binaries of deps usable in scripts
$binDir = $this->composer->getConfig()->get('bin-dir');
if (is_dir($binDir)) {
$binDir = realpath($binDir);
if (isset($_SERVER[$pathStr]) && !preg_match('{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', $_SERVER[$pathStr])) {
Platform::putEnv($pathStr, $binDir.PATH_SEPARATOR.getenv($pathStr));
$pathValue = Platform::getEnv($pathEnv);
if (!preg_match('{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', $pathValue)) {
Platform::putEnv($pathEnv, $binDir.PATH_SEPARATOR.$pathValue);
}
}
}

View File

@ -56,17 +56,17 @@ class Factory
*/
protected static function getHomeDir()
{
$home = getenv('COMPOSER_HOME');
$home = Platform::getEnv('COMPOSER_HOME');
if ($home) {
return $home;
}
if (Platform::isWindows()) {
if (!getenv('APPDATA')) {
if (!Platform::getEnv('APPDATA')) {
throw new \RuntimeException('The APPDATA or COMPOSER_HOME environment variable must be set for composer to run correctly');
}
return rtrim(strtr(getenv('APPDATA'), '\\', '/'), '/') . '/Composer';
return rtrim(strtr(Platform::getEnv('APPDATA'), '\\', '/'), '/') . '/Composer';
}
$userDir = self::getUserDir();
@ -74,7 +74,7 @@ class Factory
if (self::useXdg()) {
// XDG Base Directory Specifications
$xdgConfig = getenv('XDG_CONFIG_HOME');
$xdgConfig = Platform::getEnv('XDG_CONFIG_HOME');
if (!$xdgConfig) {
$xdgConfig = $userDir . '/.config';
}
@ -101,18 +101,18 @@ class Factory
*/
protected static function getCacheDir($home)
{
$cacheDir = getenv('COMPOSER_CACHE_DIR');
$cacheDir = Platform::getEnv('COMPOSER_CACHE_DIR');
if ($cacheDir) {
return $cacheDir;
}
$homeEnv = getenv('COMPOSER_HOME');
$homeEnv = Platform::getEnv('COMPOSER_HOME');
if ($homeEnv) {
return $homeEnv . '/cache';
}
if (Platform::isWindows()) {
if ($cacheDir = getenv('LOCALAPPDATA')) {
if ($cacheDir = Platform::getEnv('LOCALAPPDATA')) {
$cacheDir .= '/Composer';
} else {
$cacheDir = $home . '/cache';
@ -136,7 +136,7 @@ class Factory
}
if (self::useXdg()) {
$xdgCache = getenv('XDG_CACHE_HOME') ?: $userDir . '/.cache';
$xdgCache = Platform::getEnv('XDG_CACHE_HOME') ?: $userDir . '/.cache';
return $xdgCache . '/composer';
}
@ -150,7 +150,7 @@ class Factory
*/
protected static function getDataDir($home)
{
$homeEnv = getenv('COMPOSER_HOME');
$homeEnv = Platform::getEnv('COMPOSER_HOME');
if ($homeEnv) {
return $homeEnv;
}
@ -161,7 +161,7 @@ class Factory
$userDir = self::getUserDir();
if ($home !== $userDir . '/.composer' && self::useXdg()) {
$xdgData = getenv('XDG_DATA_HOME') ?: $userDir . '/.local/share';
$xdgData = Platform::getEnv('XDG_DATA_HOME') ?: $userDir . '/.local/share';
return $xdgData . '/composer';
}
@ -225,7 +225,7 @@ class Factory
$config->setAuthConfigSource(new JsonConfigSource($file, true));
// load COMPOSER_AUTH environment variable if set
if ($composerAuthEnv = getenv('COMPOSER_AUTH')) {
if ($composerAuthEnv = Platform::getEnv('COMPOSER_AUTH')) {
$authData = json_decode($composerAuthEnv, true);
if (null === $authData) {
@ -248,7 +248,7 @@ class Factory
*/
public static function getComposerFile()
{
return trim(getenv('COMPOSER')) ?: './composer.json';
return trim(Platform::getEnv('COMPOSER')) ?: './composer.json';
}
/**
@ -713,7 +713,7 @@ class Factory
*/
private static function getUserDir()
{
$home = getenv('HOME');
$home = Platform::getEnv('HOME');
if (!$home) {
throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly');
}

View File

@ -488,7 +488,7 @@ class InstallationManager
if (
$this->outputProgress
&& $this->io instanceof ConsoleIO
&& !getenv('CI')
&& !Platform::getEnv('CI')
&& !$this->io->isDebug()
&& count($promises) > 1
) {

View File

@ -21,6 +21,7 @@ use Composer\Package\Version\VersionGuesser;
use Composer\Package\Version\VersionParser;
use Composer\Package\RootPackage;
use Composer\Repository\RepositoryManager;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
/**
@ -83,8 +84,8 @@ class RootPackageLoader extends ArrayLoader
$commit = null;
// override with env var if available
if (getenv('COMPOSER_ROOT_VERSION')) {
$config['version'] = getenv('COMPOSER_ROOT_VERSION');
if (Platform::getEnv('COMPOSER_ROOT_VERSION')) {
$config['version'] = Platform::getEnv('COMPOSER_ROOT_VERSION');
} else {
$versionData = $this->versionGuesser->guessVersion($config, $cwd ?: getcwd());
if ($versionData) {

View File

@ -179,7 +179,7 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn
}
// carry over the root package version if this path repo is in the same git repository as root package
if (!isset($package['version']) && ($rootVersion = getenv('COMPOSER_ROOT_VERSION'))) {
if (!isset($package['version']) && ($rootVersion = Platform::getEnv('COMPOSER_ROOT_VERSION'))) {
if (
0 === $this->process->execute('git rev-parse HEAD', $ref1, $path)
&& 0 === $this->process->execute('git rev-parse HEAD', $ref2)

View File

@ -273,7 +273,7 @@ class Git
*/
public function syncMirror($url, $dir)
{
if (getenv('COMPOSER_DISABLE_NETWORK') && getenv('COMPOSER_DISABLE_NETWORK') !== 'prime') {
if (Platform::getEnv('COMPOSER_DISABLE_NETWORK') && Platform::getEnv('COMPOSER_DISABLE_NETWORK') !== 'prime') {
$this->io->writeError('<warning>Aborting git mirror sync of '.$url.' as network is disabled</warning>');
return false;
@ -401,20 +401,20 @@ class Git
}
// added in git 1.7.1, prevents prompting the user for username/password
if (getenv('GIT_ASKPASS') !== 'echo') {
if (Platform::getEnv('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')) {
if (Platform::getEnv('GIT_DIR')) {
Platform::clearEnv('GIT_DIR');
}
if (getenv('GIT_WORK_TREE')) {
if (Platform::getEnv('GIT_WORK_TREE')) {
Platform::clearEnv('GIT_WORK_TREE');
}
// Run processes with predictable LANGUAGE
if (getenv('LANGUAGE') !== 'C') {
if (Platform::getEnv('LANGUAGE') !== 'C') {
Platform::putEnv('LANGUAGE', 'C');
}

View File

@ -70,7 +70,7 @@ class HttpDownloader
{
$this->io = $io;
$this->disabled = (bool) getenv('COMPOSER_DISABLE_NETWORK');
$this->disabled = (bool) Platform::getEnv('COMPOSER_DISABLE_NETWORK');
// Setup TLS options
// The cafile option can be set via config.json
@ -88,7 +88,7 @@ class HttpDownloader
$this->rfs = new RemoteFilesystem($io, $config, $options, $disableTls);
if (is_numeric($maxJobs = getenv('COMPOSER_MAX_PARALLEL_HTTP'))) {
if (is_numeric($maxJobs = Platform::getEnv('COMPOSER_MAX_PARALLEL_HTTP'))) {
$this->maxJobs = max(1, min(50, (int) $maxJobs));
}
}

View File

@ -24,6 +24,24 @@ class Platform
/** @var ?bool */
private static $isWindowsSubsystemForLinux = null;
/**
* getenv() equivalent but reads from the runtime global variables first
*
* @param string $name
* @return string|false
*/
public static function getEnv($name)
{
if (array_key_exists($name, $_SERVER)) {
return (string) $_SERVER[$name];
}
if (array_key_exists($name, $_ENV)) {
return (string) $_ENV[$name];
}
return getenv($name);
}
/**
* putenv() equivalent but updates the runtime global variables too
*
@ -65,10 +83,10 @@ class Platform
return preg_replace_callback('#^(\$|(?P<percent>%))(?P<var>\w++)(?(percent)%)(?P<path>.*)#', function ($matches) {
// Treat HOME as an alias for USERPROFILE on Windows for legacy reasons
if (Platform::isWindows() && $matches['var'] == 'HOME') {
return (getenv('HOME') ?: getenv('USERPROFILE')) . $matches['path'];
return (Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE')) . $matches['path'];
}
return getenv($matches['var']) . $matches['path'];
return Platform::getEnv($matches['var']) . $matches['path'];
}, $path);
}
@ -78,11 +96,11 @@ class Platform
*/
public static function getUserDirectory()
{
if (false !== ($home = getenv('HOME'))) {
if (false !== ($home = self::getEnv('HOME'))) {
return $home;
}
if (self::isWindows() && false !== ($home = getenv('USERPROFILE'))) {
if (self::isWindows() && false !== ($home = self::getEnv('USERPROFILE'))) {
return $home;
}
@ -159,7 +177,7 @@ class Platform
// detect msysgit/mingw and assume this is a tty because detection
// does not work correctly, see https://github.com/composer/composer/issues/9690
if (in_array(strtoupper(getenv('MSYSTEM') ?: ''), array('MINGW32', 'MINGW64'), true)) {
if (in_array(strtoupper(self::getEnv('MSYSTEM') ?: ''), array('MINGW32', 'MINGW64'), true)) {
return true;
}
@ -211,7 +229,7 @@ class Platform
}
}
if (getenv('COMPOSER_RUNTIME_ENV') === 'virtualbox') {
if (self::getEnv('COMPOSER_RUNTIME_ENV') === 'virtualbox') {
return self::$isVirtualBoxGuest = true;
}

View File

@ -122,7 +122,7 @@ final class StreamContextFactory
$phpVersion,
$httpVersion,
$platformPhpVersion ? '; Platform-PHP '.$platformPhpVersion : '',
getenv('CI') ? '; CI' : ''
Platform::getEnv('CI') ? '; CI' : ''
);
}

View File

@ -24,6 +24,7 @@ use Composer\Script\ScriptEvents;
use Composer\Script\Event as ScriptEvent;
use Composer\Util\ProcessExecutor;
use Composer\Test\Mock\ProcessExecutorMock;
use Composer\Util\Platform;
use Symfony\Component\Console\Output\OutputInterface;
class EventDispatcherTest extends TestCase
@ -294,9 +295,9 @@ class EventDispatcherTest extends TestCase
public function testDispatcherAppendsDirBinOnPathForEveryListener()
{
$currentDirectoryBkp = getcwd();
$composerBinDirBkp = getenv('COMPOSER_BIN_DIR');
$composerBinDirBkp = Platform::getEnv('COMPOSER_BIN_DIR');
chdir(__DIR__);
putenv('COMPOSER_BIN_DIR=' . __DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR));
Platform::putEnv('COMPOSER_BIN_DIR', __DIR__ . '/vendor/bin');
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->setConstructorArgs(array(
$this->createComposerInstance(),
@ -314,11 +315,15 @@ class EventDispatcherTest extends TestCase
$dispatcher->expects($this->atLeastOnce())->method('getListeners')->will($this->returnValue($listeners));
$dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
rmdir(__DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR));
rmdir(__DIR__ . sprintf('%svendor', DIRECTORY_SEPARATOR));
rmdir(__DIR__ . '/vendor/bin');
rmdir(__DIR__ . '/vendor');
chdir($currentDirectoryBkp);
putenv('COMPOSER_BIN_DIR' . ($composerBinDirBkp === false ? '' : '=' . $composerBinDirBkp));
if ($composerBinDirBkp) {
Platform::putEnv('COMPOSER_BIN_DIR', $composerBinDirBkp);
} else {
Platform::clearEnv('COMPOSER_BIN_DIR');
}
}
/**
@ -326,14 +331,14 @@ class EventDispatcherTest extends TestCase
*/
public static function createsVendorBinFolderChecksEnvDoesNotContainsBin()
{
mkdir(__DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), 0700, true);
mkdir(__DIR__ . '/vendor/bin', 0700, true);
$val = getenv('PATH');
if (!$val) {
$val = getenv('Path');
}
self::assertFalse(strpos($val, __DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
self::assertStringNotContainsString(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'bin', $val);
}
/**
@ -347,7 +352,7 @@ class EventDispatcherTest extends TestCase
$val = getenv('Path');
}
self::assertNotFalse(strpos($val, __DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)));
self::assertStringContainsString(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'bin', $val);
}
/**
@ -628,7 +633,7 @@ class EventDispatcherTest extends TestCase
private function createComposerInstance()
{
$composer = new Composer;
$config = new Config;
$config = new Config();
$composer->setConfig($config);
$package = $this->getMockBuilder('Composer\Package\RootPackageInterface')->getMock();
$composer->setPackage($package);