Skip to content

Commit c8476ee

Browse files
committed
bug symfony#10929 [2.3][Process] Add validation on Process input (romainneutron)
This PR was merged into the 2.3 branch. Discussion ---------- [2.3][Process] Add validation on Process input | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT This adds validation on Process input. For the moment, passing a stream would result in a PHP error. I propose to deprecate values that are not strictly string in 2.6 (see upcoming PR) Commits ------- 583092b [Process] Add validation on Process input
2 parents c505a63 + 583092b commit c8476ee

File tree

5 files changed

+95
-4
lines changed

5 files changed

+95
-4
lines changed

src/Symfony/Component/Process/Process.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -880,15 +880,16 @@ public function getStdin()
880880
*
881881
* @return self The current Process instance
882882
*
883-
* @throws LogicException In case the process is running
883+
* @throws LogicException In case the process is running
884+
* @throws InvalidArgumentException In case the argument is invalid
884885
*/
885886
public function setStdin($stdin)
886887
{
887888
if ($this->isRunning()) {
888889
throw new LogicException('STDIN can not be set while the process is running.');
889890
}
890891

891-
$this->stdin = $stdin;
892+
$this->stdin = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $stdin);
892893

893894
return $this;
894895
}

src/Symfony/Component/Process/ProcessBuilder.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,15 @@ public function setEnv($name, $value)
148148
/**
149149
* Sets the input of the process.
150150
*
151-
* @param string $stdin The input as a string
151+
* @param string|null $stdin The input as a string
152152
*
153153
* @return ProcessBuilder
154+
*
155+
* @throws InvalidArgumentException In case the argument is invalid
154156
*/
155157
public function setInput($stdin)
156158
{
157-
$this->stdin = $stdin;
159+
$this->stdin = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $stdin);
158160

159161
return $this;
160162
}

src/Symfony/Component/Process/ProcessUtils.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Process;
1313

14+
use Symfony\Component\Process\Exception\InvalidArgumentException;
15+
1416
/**
1517
* ProcessUtils is a bunch of utility methods.
1618
*
@@ -72,6 +74,29 @@ public static function escapeArgument($argument)
7274
return escapeshellarg($argument);
7375
}
7476

77+
/**
78+
* Validates and normalized a Process input
79+
*
80+
* @param string $caller The name of method call that validates the input
81+
* @param mixed $input The input to validate
82+
*
83+
* @return string The validated input
84+
*
85+
* @throws InvalidArgumentException In case the input is not valid
86+
*/
87+
public static function validateInput($caller, $input)
88+
{
89+
if (null !== $input) {
90+
if (is_scalar($input) || (is_object($input) && method_exists($input, '__toString'))) {
91+
return (string) $input;
92+
}
93+
94+
throw new InvalidArgumentException(sprintf('%s only accepts strings.', $caller));
95+
}
96+
97+
return $input;
98+
}
99+
75100
private static function isSurroundedBy($arg, $char)
76101
{
77102
return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];

src/Symfony/Component/Process/Tests/AbstractProcessTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,47 @@ public function testSetStdinWhileRunningThrowsAnException()
171171
$process->stop();
172172
}
173173

174+
/**
175+
* @dataProvider provideInvalidStdinValues
176+
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
177+
* @expectedExceptionMessage Symfony\Component\Process\Process::setStdin only accepts strings.
178+
*/
179+
public function testInvalidStdin($value)
180+
{
181+
$process = $this->getProcess('php -v');
182+
$process->setStdin($value);
183+
}
184+
185+
public function provideInvalidStdinValues()
186+
{
187+
return array(
188+
array(array()),
189+
array(new NonStringifiable()),
190+
array(fopen('php://temporary', 'w')),
191+
);
192+
}
193+
194+
/**
195+
* @dataProvider provideStdinValues
196+
*/
197+
public function testValidStdin($expected, $value)
198+
{
199+
$process = $this->getProcess('php -v');
200+
$process->setStdin($value);
201+
$this->assertSame($expected, $process->getStdin());
202+
}
203+
204+
public function provideStdinValues()
205+
{
206+
return array(
207+
array(null, null),
208+
array('24.5', 24.5),
209+
array('input data', 'input data'),
210+
// to maintain BC, supposed to be removed in 3.0
211+
array('stringifiable', new Stringifiable()),
212+
);
213+
}
214+
174215
public function chainedCommandsOutputProvider()
175216
{
176217
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
@@ -813,3 +854,15 @@ public function methodProvider()
813854
*/
814855
abstract protected function getProcess($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array());
815856
}
857+
858+
class Stringifiable
859+
{
860+
public function __toString()
861+
{
862+
return 'stringifiable';
863+
}
864+
}
865+
866+
class NonStringifiable
867+
{
868+
}

src/Symfony/Component/Process/Tests/ProcessBuilderTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,14 @@ public function testShouldNotThrowALogicExceptionIfNoPrefix()
197197
$this->assertEquals("'/usr/bin/php'", $process->getCommandLine());
198198
}
199199
}
200+
201+
/**
202+
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
203+
* @expectedExceptionMessage Symfony\Component\Process\ProcessBuilder::setInput only accepts strings.
204+
*/
205+
public function testInvalidInput()
206+
{
207+
$builder = ProcessBuilder::create();
208+
$builder->setInput(array());
209+
}
200210
}

0 commit comments

Comments
 (0)