Skip to content

Commit 5be4e4a

Browse files
author
Adam Scarr
committed
[Process] Redirect output without a shell
Currently processes that output large amounts of data will block. If the output is not important then this becomes an issue. It can be worked around by redirecting the output to > /dev/null but this requires an instance of /bin/sh to do the work. This patch adds the ability to set the processPipes, and a new processPipe that redirects to /dev/null. | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | symfony#9007 | License | MIT | Doc PR | symfony/symfony-docs#3303
1 parent 5e37fc8 commit 5be4e4a

File tree

4 files changed

+85
-1
lines changed

4 files changed

+85
-1
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Process;
13+
14+
use Symfony\Component\Process\Exception\RuntimeException;
15+
16+
/**
17+
* NullProcessPipes allow redirecting output to dev/null without a subshell. Useful for processes that communicate
18+
* over other means.
19+
*/
20+
class NullProcessPipes extends ProcessPipes
21+
{
22+
/**
23+
* Returns an array of descriptors for the use of proc_open.
24+
*
25+
* @return array
26+
*/
27+
public function getDescriptors()
28+
{
29+
$nullfile = defined('PHP_WINDOWS_VERSION_BUILD') ? 'NUL' : '/dev/null';
30+
return array(
31+
32+
array('pipe', 'r'), // stdin
33+
array('file', $nullfile, 'a+'), // stdout
34+
array('file', $nullfile, 'a+'), //stderr
35+
);
36+
}
37+
}
38+

src/Symfony/Component/Process/Process.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -991,14 +991,25 @@ public function checkTimeout()
991991
}
992992
}
993993

994+
/**
995+
* Sets the process pipes to use.
996+
*
997+
* @param ProcessPipes $pipes
998+
*/
999+
public function setProcessPipes(ProcessPipes $pipes) {
1000+
$this->processPipes = $pipes;
1001+
}
1002+
9941003
/**
9951004
* Creates the descriptors needed by the proc_open.
9961005
*
9971006
* @return array
9981007
*/
9991008
private function getDescriptors()
10001009
{
1001-
$this->processPipes = new ProcessPipes($this->useFileHandles);
1010+
if (!$this->processPipes) {
1011+
$this->processPipes = new ProcessPipes($this->useFileHandles);
1012+
}
10021013
$descriptors = $this->processPipes->getDescriptors();
10031014

10041015
if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
/**
4+
* Runs a php script that will dump a large amount of output and then quit.
5+
*/
6+
7+
for ($i = 0; $i < 100000; $i++) {
8+
echo "Lorem ipsum dolor sit amet\n";
9+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
4+
namespace Symfony\Component\Process\Tests;
5+
6+
use Symfony\Component\Process\NullProcessPipes;
7+
use Symfony\Component\Process\Process;
8+
9+
class NullProcessPipesTest extends \PHPUnit_Framework_TestCase {
10+
public function testProcessCompletesWithNullPipes() {
11+
// Without null pipes the pipe would fill and the process will never complete
12+
$process = new Process('php ' . __DIR__ . '/HeavyOutputtingProcess.php');
13+
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
14+
$this->markTestSkipped('Windows does not support NullProcessPipes');
15+
}
16+
$process->setProcessPipes(new NullProcessPipes());
17+
$process->start();
18+
19+
while($process->isRunning()) {
20+
usleep(100e3);
21+
}
22+
23+
// No output!
24+
$this->assertEquals('', $process->getOutput());
25+
}
26+
}

0 commit comments

Comments
 (0)