how to get output of proc_open()
Asked Answered
V

3

17

I've tried to get output from proc_open method in php, but, when I print it, I got empty.

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

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

as long as I know, I can get the output with stream_get_contents()

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

But I can't do that.. any suggestion?

Thx before...

Vaporize answered 16/5, 2011 at 8:34 Comment(1)
Haha, your code actually made me understand how proc_open works.Hazy
L
13

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
Leibniz answered 16/5, 2011 at 11:34 Comment(1)
Thx for your help... I don't check my stderr... finally, I checked it, and found the output... thanks..Vaporize
R
12

this is another example with proc_open(). I am using Win32 ping.exe command in this example. CMIIW

set_time_limit(1800);
ob_implicit_flush(true);

$exe_command = 'C:\\Windows\\System32\\ping.exe -t google.com';

$descriptorspec = array(
    0 => array("pipe", "r"),  // stdin
    1 => array("pipe", "w"),  // stdout -> we use this
    2 => array("pipe", "w")   // stderr 
);

$process = proc_open($exe_command, $descriptorspec, $pipes);

if (is_resource($process))
{

    while( ! feof($pipes[1]))
    {
        $return_message = fgets($pipes[1], 1024);
        if (strlen($return_message) == 0) break;

        echo $return_message.'<br />';
        ob_flush();
        flush();
    }
}

Hope this helps =)

Revenant answered 25/3, 2013 at 4:44 Comment(2)
Why do you need ob_flush and flush in this?Komatik
To summarize: "flush() may not be able to override the buffering scheme of your web server and it has no effect on any client-side buffering in the browser. It also doesn't affect PHP's userspace output buffering mechanism. This means you will have to call both ob_flush() and flush() to flush the ob output buffers if you are using those. " Source: php.net/manual/en/function.flush.phpRevenant
P
0

Here is a complete functions which reads stdout and stderr.

/**
 * Executes process
 *
 * @param string $command
 * @param string $cwd
 * @param bool $exitOnError
 * @return void
 */
function exec(string $command, string $cwd, bool $exitOnError = true): void
{
    $descriptorSpec = array(
        0 => array('pipe', 'r'), // stdin is a pipe that the child will read from
        1 => array('pipe', 'w'), // stdout is a pipe that the child will write to
        2 => array("pipe", "w"), // stderr is a pipe that the child will write to
    );

    $process = proc_open($command, $descriptorSpec, $pipes, $cwd);

    if (is_resource($process)) {
        do {
            $read = array($pipes[1], $pipes[2]);
            $write = null;
            $except = null;

            if (stream_select($read, $write, $except, 5)) {
                foreach ($read as $c) {
                    if (feof($c)) {
                        continue;
                    }
                    $read = fread($c, 1024);

                    if ($read === false) {
                        continue;
                    }

                    echo $read;
                }
            }
        } while (!feof($pipes[1]) | !feof($pipes[2]));

        fclose($pipes[0]);
        fclose($pipes[1]);
        fclose($pipes[2]);

        // It is important to close any pipes before calling
        // proc_close to avoid a deadlock
        $returnValue = proc_close($process);

        if ($returnValue != 0) {
            if ($exitOnError) {
                exit(1);
            }
        }

    } else {
        echo "Couldn't open $command";
        if ($exitOnError) {
            exit(1);
        }
    }
}
Polymyxin answered 6/12, 2023 at 8:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.