diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 3d9a3374f904c..fc6e8a06b0a16 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -258,6 +258,10 @@ public function start(callable $callback = null, array $env = array()) $this->hasCallback = null !== $callback; $descriptors = $this->getDescriptors(); + if ($this->env) { + $env += $this->env; + } + if (is_array($commandline = $this->commandline)) { $commandline = implode(' ', array_map(array($this, 'escapeArgument'), $commandline)); @@ -265,11 +269,10 @@ public function start(callable $callback = null, array $env = array()) // exec is mandatory to deal with sending a signal to the process $commandline = 'exec '.$commandline; } + } else { + $commandline = $this->replacePlaceholders($commandline, $env); } - if ($this->env) { - $env += $this->env; - } $env += $this->getDefaultEnv(); $options = array('suppress_errors' => true); @@ -1549,6 +1552,29 @@ private function escapeArgument(string $argument): string return '"'.str_replace(array('"', '^', '%', '!', "\n"), array('""', '"^^"', '"^%"', '"^!"', '!LF!'), $argument).'"'; } + private function replacePlaceholders(string $commandline, array $env) + { + $pattern = '\\' === DIRECTORY_SEPARATOR ? '!%s!' : '${%s}'; + + return preg_replace_callback('/\{\{ ?([_a-zA-Z0-9]++) ?\}\}/', function ($m) use ($pattern, $commandline, $env) { + if (!isset($env[$m[1]]) || false === $env[$m[1]]) { + foreach ($env as $k => $v) { + if (false === $v) { + unset($env[$k]); + } + } + if (!$env) { + throw new InvalidArgumentException(sprintf('Invalid command line "%s": no values provided for any placeholders.', $commandline)); + } + $env = implode('", "', array_keys($env)); + + throw new InvalidArgumentException(sprintf('Invalid command line "%s": no value provided for placeholder "%s", did you mean "%s"?', $commandline, $m[1], $env)); + } + + return sprintf($pattern, $m[1]); + }, $commandline); + } + private function getDefaultEnv() { $env = array(); diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 9d36d247c5dfa..2acf3fadecabe 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1474,6 +1474,34 @@ public function provideEscapeArgument() yield array('éÉèÈàÀöä'); } + public function testPreparedCommand() + { + $p = new Process('echo {{ abc }}DEF'); + $p->run(null, array('abc' => 'ABC')); + + $this->assertSame('ABCDEF', rtrim($p->getOutput())); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException + * @expectedExceptionMessage Invalid command line "echo {{ abc }}": no value provided for placeholder "abc", did you mean "bcd"? + */ + public function testPreparedCommandWithMissingValue() + { + $p = new Process('echo {{ abc }}'); + $p->run(null, array('bcd' => 'BCD')); + } + + /** + * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException + * @expectedExceptionMessage Invalid command line "echo {{ abc }}": no values provided for any placeholders. + */ + public function testPreparedCommandWithNoValues() + { + $p = new Process('echo {{ abc }}'); + $p->run(); + } + public function testEnvArgument() { $env = array('FOO' => 'Foo', 'BAR' => 'Bar');
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: