diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 822671467b..2ccad53d77 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -880,7 +880,8 @@ class Process * * @return self The current Process instance * - * @throws LogicException In case the process is running + * @throws LogicException In case the process is running + * @throws InvalidArgumentException In case the argument is invalid */ public function setStdin($stdin) { @@ -888,7 +889,7 @@ class Process throw new LogicException('STDIN can not be set while the process is running.'); } - $this->stdin = $stdin; + $this->stdin = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $stdin); return $this; } diff --git a/src/Symfony/Component/Process/ProcessBuilder.php b/src/Symfony/Component/Process/ProcessBuilder.php index 3e3eed8920..ef1fefc3d9 100644 --- a/src/Symfony/Component/Process/ProcessBuilder.php +++ b/src/Symfony/Component/Process/ProcessBuilder.php @@ -148,13 +148,15 @@ class ProcessBuilder /** * Sets the input of the process. * - * @param string $stdin The input as a string + * @param string|null $stdin The input as a string * * @return ProcessBuilder + * + * @throws InvalidArgumentException In case the argument is invalid */ public function setInput($stdin) { - $this->stdin = $stdin; + $this->stdin = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $stdin); return $this; } diff --git a/src/Symfony/Component/Process/ProcessUtils.php b/src/Symfony/Component/Process/ProcessUtils.php index 5317cd0883..441522d388 100644 --- a/src/Symfony/Component/Process/ProcessUtils.php +++ b/src/Symfony/Component/Process/ProcessUtils.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Process; +use Symfony\Component\Process\Exception\InvalidArgumentException; + /** * ProcessUtils is a bunch of utility methods. * @@ -72,6 +74,29 @@ class ProcessUtils return escapeshellarg($argument); } + /** + * Validates and normalized a Process input + * + * @param string $caller The name of method call that validates the input + * @param mixed $input The input to validate + * + * @return string The validated input + * + * @throws InvalidArgumentException In case the input is not valid + */ + public static function validateInput($caller, $input) + { + if (null !== $input) { + if (is_scalar($input) || (is_object($input) && method_exists($input, '__toString'))) { + return (string) $input; + } + + throw new InvalidArgumentException(sprintf('%s only accepts strings.', $caller)); + } + + return $input; + } + private static function isSurroundedBy($arg, $char) { return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1]; diff --git a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php index 50d80cae77..91b8aca20d 100644 --- a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php +++ b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php @@ -171,6 +171,47 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $process->stop(); } + /** + * @dataProvider provideInvalidStdinValues + * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException + * @expectedExceptionMessage Symfony\Component\Process\Process::setStdin only accepts strings. + */ + public function testInvalidStdin($value) + { + $process = $this->getProcess('php -v'); + $process->setStdin($value); + } + + public function provideInvalidStdinValues() + { + return array( + array(array()), + array(new NonStringifiable()), + array(fopen('php://temporary', 'w')), + ); + } + + /** + * @dataProvider provideStdinValues + */ + public function testValidStdin($expected, $value) + { + $process = $this->getProcess('php -v'); + $process->setStdin($value); + $this->assertSame($expected, $process->getStdin()); + } + + public function provideStdinValues() + { + return array( + array(null, null), + array('24.5', 24.5), + array('input data', 'input data'), + // to maintain BC, supposed to be removed in 3.0 + array('stringifiable', new Stringifiable()), + ); + } + public function chainedCommandsOutputProvider() { if (defined('PHP_WINDOWS_VERSION_BUILD')) { @@ -813,3 +854,15 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase */ abstract protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array()); } + +class Stringifiable +{ + public function __toString() + { + return 'stringifiable'; + } +} + +class NonStringifiable +{ +} diff --git a/src/Symfony/Component/Process/Tests/ProcessBuilderTest.php b/src/Symfony/Component/Process/Tests/ProcessBuilderTest.php index d0611f0b41..70245e0a42 100644 --- a/src/Symfony/Component/Process/Tests/ProcessBuilderTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessBuilderTest.php @@ -197,4 +197,14 @@ class ProcessBuilderTest extends \PHPUnit_Framework_TestCase $this->assertEquals("'/usr/bin/php'", $process->getCommandLine()); } } + + /** + * @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException + * @expectedExceptionMessage Symfony\Component\Process\ProcessBuilder::setInput only accepts strings. + */ + public function testInvalidInput() + { + $builder = ProcessBuilder::create(); + $builder->setInput(array()); + } }