[Process] Dont rely on putenv(), it fails on ZTS PHP

This commit is contained in:
Nicolas Grekas 2017-12-10 10:47:05 +01:00
parent 50644d0d58
commit ef632ec721
3 changed files with 43 additions and 20 deletions

View File

@ -343,6 +343,7 @@ abstract class Client
{
$deprecationsFile = tempnam(sys_get_temp_dir(), 'deprec');
putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$deprecationsFile);
$_ENV['SYMFONY_DEPRECATIONS_SERIALIZE'] = $deprecationsFile;
$process = new PhpProcess($this->getScript($request), null, null);
$process->run();

View File

@ -304,19 +304,16 @@ class Process implements \IteratorAggregate
$inheritEnv = true;
}
$envBackup = array();
if (null !== $env && $inheritEnv) {
foreach ($env as $k => $v) {
$envBackup[$k] = getenv($k);
putenv(false === $v || null === $v ? $k : "$k=$v");
}
$env = null;
$env += $this->getDefaultEnv();
} elseif (null !== $env) {
@trigger_error('Not inheriting environment variables is deprecated since Symfony 3.3 and will always happen in 4.0. Set "Process::inheritEnvironmentVariables()" to true instead.', E_USER_DEPRECATED);
} else {
$env = $this->getDefaultEnv();
}
if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
$this->options['bypass_shell'] = true;
$commandline = $this->prepareWindowsCommandLine($commandline, $envBackup, $env);
$commandline = $this->prepareWindowsCommandLine($commandline, $env);
} elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
$descriptors[3] = array('pipe', 'w');
@ -332,10 +329,6 @@ class Process implements \IteratorAggregate
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $env, $this->options);
foreach ($envBackup as $k => $v) {
putenv(false === $v ? $k : "$k=$v");
}
if (!is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new process.');
}
@ -1623,7 +1616,7 @@ class Process implements \IteratorAggregate
return true;
}
private function prepareWindowsCommandLine($cmd, array &$envBackup, array &$env = null)
private function prepareWindowsCommandLine($cmd, array &$env)
{
$uid = uniqid('', true);
$varCount = 0;
@ -1636,7 +1629,7 @@ class Process implements \IteratorAggregate
[^"%!^]*+
)++
) | [^"]*+ )"/x',
function ($m) use (&$envBackup, &$env, &$varCache, &$varCount, $uid) {
function ($m) use (&$env, &$varCache, &$varCount, $uid) {
if (!isset($m[1])) {
return $m[0];
}
@ -1654,13 +1647,7 @@ class Process implements \IteratorAggregate
$value = '"'.preg_replace('/(\\\\*)"/', '$1$1\\"', $value).'"';
$var = $uid.++$varCount;
if (null === $env) {
putenv("$var=$value");
} else {
$env[$var] = $value;
}
$envBackup[$var] = false;
$env[$var] = $value;
return $varCache[$m[0]] = '!'.$var.'!';
},
@ -1728,4 +1715,27 @@ class Process implements \IteratorAggregate
return '"'.str_replace(array('"', '^', '%', '!', "\n"), array('""', '"^^"', '"^%"', '"^!"', '!LF!'), $argument).'"';
}
private function getDefaultEnv()
{
if (\PHP_VERSION_ID >= 70100) {
$env = getenv();
} else {
$env = array();
foreach ($_SERVER as $k => $v) {
if (is_string($v) && false !== $v = getenv($k)) {
$env[$k] = $v;
}
}
}
foreach ($_ENV as $k => $v) {
if (is_string($v)) {
$env[$k] = $v;
}
}
return $env;
}
}

View File

@ -1406,6 +1406,7 @@ class ProcessTest extends TestCase
public function testEnvBackupDoesNotDeleteExistingVars()
{
putenv('existing_var=foo');
$_ENV['existing_var'] = 'foo';
$process = $this->getProcess('php -r "echo getenv(\'new_test_var\');"');
$process->setEnv(array('existing_var' => 'bar', 'new_test_var' => 'foo'));
$process->inheritEnvironmentVariables();
@ -1415,6 +1416,9 @@ class ProcessTest extends TestCase
$this->assertSame('foo', $process->getOutput());
$this->assertSame('foo', getenv('existing_var'));
$this->assertFalse(getenv('new_test_var'));
putenv('existing_var');
unset($_ENV['existing_var']);
}
public function testEnvIsInherited()
@ -1422,6 +1426,7 @@ class ProcessTest extends TestCase
$process = $this->getProcessForCode('echo serialize($_SERVER);', null, array('BAR' => 'BAZ'));
putenv('FOO=BAR');
$_ENV['FOO'] = 'BAR';
$process->run();
@ -1429,6 +1434,9 @@ class ProcessTest extends TestCase
$env = array_intersect_key(unserialize($process->getOutput()), $expected);
$this->assertEquals($expected, $env);
putenv('FOO');
unset($_ENV['FOO']);
}
/**
@ -1439,6 +1447,7 @@ class ProcessTest extends TestCase
$process = $this->getProcessForCode('echo serialize($_SERVER);', null, array('BAR' => 'BAZ'));
putenv('FOO=BAR');
$_ENV['FOO'] = 'BAR';
$this->assertSame($process, $process->inheritEnvironmentVariables(false));
$this->assertFalse($process->areEnvironmentVariablesInherited());
@ -1450,6 +1459,9 @@ class ProcessTest extends TestCase
unset($expected['FOO']);
$this->assertSame($expected, $env);
putenv('FOO');
unset($_ENV['FOO']);
}
public function testGetCommandLine()