[Process] Allow writing portable "prepared" command lines
This commit is contained in:
parent
dca9325e61
commit
3f8354f58f
@ -291,6 +291,12 @@ class Process implements \IteratorAggregate
|
|||||||
$this->hasCallback = null !== $callback;
|
$this->hasCallback = null !== $callback;
|
||||||
$descriptors = $this->getDescriptors();
|
$descriptors = $this->getDescriptors();
|
||||||
|
|
||||||
|
if ($this->env) {
|
||||||
|
$env += $this->env;
|
||||||
|
}
|
||||||
|
|
||||||
|
$env += $this->getDefaultEnv();
|
||||||
|
|
||||||
if (\is_array($commandline = $this->commandline)) {
|
if (\is_array($commandline = $this->commandline)) {
|
||||||
$commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline));
|
$commandline = implode(' ', array_map([$this, 'escapeArgument'], $commandline));
|
||||||
|
|
||||||
@ -298,13 +304,10 @@ class Process implements \IteratorAggregate
|
|||||||
// exec is mandatory to deal with sending a signal to the process
|
// exec is mandatory to deal with sending a signal to the process
|
||||||
$commandline = 'exec '.$commandline;
|
$commandline = 'exec '.$commandline;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$commandline = $this->replacePlaceholders($commandline, $env);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->env) {
|
|
||||||
$env += $this->env;
|
|
||||||
}
|
|
||||||
$env += $this->getDefaultEnv();
|
|
||||||
|
|
||||||
$options = ['suppress_errors' => true];
|
$options = ['suppress_errors' => true];
|
||||||
|
|
||||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||||
@ -1632,6 +1635,17 @@ class Process implements \IteratorAggregate
|
|||||||
return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
|
return '"'.str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument).'"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function replacePlaceholders(string $commandline, array $env)
|
||||||
|
{
|
||||||
|
return preg_replace_callback('/"\$([_a-zA-Z]++[_a-zA-Z0-9]*+)"/', function ($matches) use ($commandline, $env) {
|
||||||
|
if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) {
|
||||||
|
throw new InvalidArgumentException(sprintf('Command line is missing a value for key %s: %s.', $matches[0], $commandline));
|
||||||
|
}
|
||||||
|
|
||||||
|
return '\\' === \DIRECTORY_SEPARATOR ? $this->escapeArgument($env[$matches[1]]) : $matches[0];
|
||||||
|
}, $commandline);
|
||||||
|
}
|
||||||
|
|
||||||
private function getDefaultEnv()
|
private function getDefaultEnv()
|
||||||
{
|
{
|
||||||
$env = [];
|
$env = [];
|
||||||
|
@ -1500,6 +1500,50 @@ EOTXT;
|
|||||||
yield [1.1];
|
yield [1.1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testPreparedCommand()
|
||||||
|
{
|
||||||
|
$p = Process::fromShellCommandline('echo "$abc"DEF');
|
||||||
|
$p->run(null, ['abc' => 'ABC']);
|
||||||
|
|
||||||
|
$this->assertSame('ABCDEF', rtrim($p->getOutput()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPreparedCommandMulti()
|
||||||
|
{
|
||||||
|
$p = Process::fromShellCommandline('echo "$abc""$def"');
|
||||||
|
$p->run(null, ['abc' => 'ABC', 'def' => 'DEF']);
|
||||||
|
|
||||||
|
$this->assertSame('ABCDEF', rtrim($p->getOutput()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPreparedCommandWithQuoteInIt()
|
||||||
|
{
|
||||||
|
$p = Process::fromShellCommandline('php -r "$code" "$def"');
|
||||||
|
$p->run(null, ['code' => 'echo $argv[1];', 'def' => '"DEF"']);
|
||||||
|
|
||||||
|
$this->assertSame('"DEF"', rtrim($p->getOutput()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Command line is missing a value for key "$abc": echo "$abc".
|
||||||
|
*/
|
||||||
|
public function testPreparedCommandWithMissingValue()
|
||||||
|
{
|
||||||
|
$p = Process::fromShellCommandline('echo "$abc"');
|
||||||
|
$p->run(null, ['bcd' => 'BCD']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Command line is missing a value for key "$abc": echo "$abc".
|
||||||
|
*/
|
||||||
|
public function testPreparedCommandWithNoValues()
|
||||||
|
{
|
||||||
|
$p = Process::fromShellCommandline('echo "$abc"');
|
||||||
|
$p->run(null, []);
|
||||||
|
}
|
||||||
|
|
||||||
public function testEnvArgument()
|
public function testEnvArgument()
|
||||||
{
|
{
|
||||||
$env = ['FOO' => 'Foo', 'BAR' => 'Bar'];
|
$env = ['FOO' => 'Foo', 'BAR' => 'Bar'];
|
||||||
|
Reference in New Issue
Block a user