php exec中的重定向在apache + windows 7中被破坏,正在使用Windows XP

i have been using PHP to execute a legacy script in an Apache server. the legacy script writes debug data to STDERR and i have been redirecting that to a black-hole or STDOUT depending on the debug-settings.

the PHP looks a bit like this:

exec('perl -e "print 10; print STDERR 20" 2>&1', $output);

that was reliably working in XP. i got new hardware which now runs windows7 and coming back to this code it is broken. zero output. return-code 255. no idea why.

the only way i was able to get it going again was to remove the redirection. oh, redirection still works perfectly in a terminal-box.

now i have to retrieve my debug-data from the apache-error-log (where every STDERR output goes by default) which is inconvenient but not a problem.

i just want to understand why the redirect stopped working all of a sudden (and maybe help others running into the same problem). the apache is the same, in fact i just copied the XAMPP dir over from the old box. a bug? system-limitation? forbidden by OS-policy?

Instead of using exec and using filehandle redirection, use proc_open and actually capture the output of stdout and stderr. Unlike some of the process-related functions, the proc_ family is built in to all versions of PHP and work fine on Windows.

A c&p of their example for completeness:

$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("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
);

$cwd = '/tmp';
$env = array('some_option' => 'aeiou');

$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {
    // $pipes now looks like this:
    // 0 => writeable handle connected to child stdin
    // 1 => readable handle connected to child stdout
    // Any error output will be appended to /tmp/error-output.txt

    fwrite($pipes[0], '<?php print_r($_ENV); ?>');
    fclose($pipes[0]);

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

    // It is important that you close any pipes before calling
    // proc_close in order to avoid a deadlock
    $return_value = proc_close($process);

    echo "command returned $return_value
";
}

Be sure to browse the upvoted user-contributed notes on the documentation page for possible caveats.

Okay, i got the (well maybe at least my) solution:

  1. use proc_open as Charles suggested
  2. go back to the original principle of io_redirection

dumping stuff directly to STDERR and retrieving it from there via pipes does apparently not work under (my) windows7+PHP with my code. simple examples work, but that was it for me.

so while using 2>&1 broke my exec() - the initial problem - it works wonderfully with proc_open(). problem solved.

i wonder if i will now find something broken on our linux servers running the new code.

small caveat: if you don't want your code to print to STDERR and you use redirect-to-null e.g. for production, in windows it's 2>nul