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.
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With