How to Get Output of Proc_Open()

how to get output of proc_open()

Your code more or less works for me. time prints its output to stderr so if you're looking for that output, look in your file files/temp/error-output.txt. The stdout pipe $pipes[1] will only contain the output of the program ./a.

My repro:

[edan@edan tmp]$ cat proc.php 

<?php

$cwd='/tmp';
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "/tmp/error-output.txt", "a") );

$process = proc_open("time ./a a.out", $descriptorspec, $pipes, $cwd);

echo stream_get_contents($pipes[1]);
fclose($pipes[1]);

?>

[edan@edan tmp]$ php proc.php

a.out here.

[edan@edan tmp]$ cat /tmp/error-output.txt

real 0m0.001s
user 0m0.000s
sys 0m0.002s

PHP Use proc_open and capture stdout of 'echo' command

You're reading from $pipes[0]. This is stdin. You want to read from $pipes[1] which is mapped to stdout (and has the w flag for being written to):

$descriptors = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']];
$handle = proc_open('echo Hello world, $USER!', $descriptors, $pipes, null, ['USER' => 'guest']);
$world = stream_get_contents($pipes[1]);
var_dump($world);

Outputs

string(20) "Hello world, guest!
"

output problems with proc_open()

When using the CLI version of PHP, the output is still buffered - so the usual time that a page is sent to the user is at the end of the script.

As with any version of PHP - using flush() will force the output to be sent to the user.

Also - you should use PHP_EOL, it outputs the correct new lines for whatever platform your on (linux and Windows use different chars - \r\n or \n). PHP_EOL is a safe way of creating a new line.

Is there a way to make proc_open read input from a file if the file is dynamic?

Wait for the file to be created before using it.

while !file_exists("input.txt") {
sleep(5)
// code that uses input.txt
}
...
unlink("input.txt") # Remove file to prepare for next iteration

To avoid seeing a partial file, the process that creates the file should write to a temporary name, then rename it to input.txt when it's done.

Redirect pipe acquired by proc_open() to file for remainder of process duration

What I ended up doing, having reached the point where the service had been initialized correctly, was to redirect the pipes from the already opened process as the standard input to a cat process per-pipe, also opened by proc_open() (helped by this answer).

This wasn't the whole story, as I got to this point and realised that the async process was hanging after a while due to the stream buffer filling up.

The key part that I needed (having set the streams to non-blocking previously) was to revert the streams to blocking mode, so that the buffer would drain into the receiving cat processes correctly.

To complete the code from my question:

// Iterate over the streams that are stil open
foreach(array_reverse($readables) as $stream) {
// Revert the blocking mode
stream_set_blocking($stream, true);
$cmd = 'cat';

// Receive input from an output stream for the previous process,
// Send output into the internal unified output buffer
$pipes = [
0 => $stream,
1 => $this->temp,
2 => array("file", "/dev/null", 'w'),
];

// Launch the process
$this->cats[] = proc_open($cmd, $pipes, $outputPipes = []);
}


Related Topics



Leave a reply



Submit