Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirecting STDERR in PHP exec

I'm writing a PHP script that needs to make some calls to external command line utilities, which I am using exec() for. Had it all working fine locally, but when I moved it over to a live server it no longer works.

After some debugging I believe the problem is down to the STDERR redirection - if I attempt anything to do with redirection (redirect to STDIN, redirect to file) the command completely fails.

I wrote a simple bat script to simplify the test:

@echo off
echo STDOUT test
echo STDERR test 1>&2

And then in PHP:

<?php
$cmd = "_test.bat 2>&1";
exec($cmd, $output, $status);
var_dump($output);
var_dump($status);
?>

On the local server the result is $status=0, $output=array("STDOUT test", "STDERR test") as I would expect, but on the live server the result is $status=1, and output is an empty array!

If I remove the 1>&2 part, I get the same result for both (just the STDOUT part), so the command itself is clearly working as expected.

Is there something simple I am missing here? If it helps, the server is running Windows Server 2008 R2.

like image 567
tom1990 Avatar asked Aug 29 '14 08:08

tom1990


1 Answers

Update and answer for the benefit of anyone who comes here with a similar issue.

After spending a lot of time on this I gave up with exec() and gave proc_open() a try instead.

Doing it this way now works locally and on the server:

<?php
$cmd = "__test.bat";

$descriptorspec = array(
    0 => array("pipe", "r"), // STDIN
    1 => array("pipe", "w"), // STDOUT
    2 => array("pipe", "w"), // STDERR
);
$cwd = getcwd();
$env = null;

$proc = proc_open($cmd, $descriptorspec, $pipes, $cwd, $env);
if (is_resource($proc)) {
    // Output test:
    echo "STDOUT:<br />";
    echo "<pre>".stream_get_contents($pipes[1])."</pre>";
    echo "STDERR:<br />";
    echo "<pre>".stream_get_contents($pipes[2])."</pre>";
    $return_value = proc_close($proc);
    echo "Exited with status: {$return_value}";
}
?>

For some reason, missing out the getcwd() part causes the command to fail on the server unless I specify the complete path, whereas locally that is not an issue.

With this method I can append 2>&1 to redirect all output to STDIN. To output to a file, the manual shows that the $descriptorspec array can be modified e.g: 2 => array("file", "stderr.log", "a") (I have not yet tested this though)

One difference here is that if I want to retrieve the output in PHP, rather than getting all of the lines in an array, I need to read from the streams using stream_get_contents().

I still don't understand why there was an issue with using exec(), but this method seems to work both locally and on the server - If anyone knows why this could be, please let me know!

like image 134
tom1990 Avatar answered Oct 17 '22 11:10

tom1990