Search code examples
phpapacheflushproc-open

Refresh output of long process in PHP page


I have a "long" script I want to execute in a PHP page, and I want its output to be 'refreshed' as soon as the script outputs something. I've read plenty of solutions like questions 4706525, 9182094, 8882383, PHP Flush Manual but it's not working as expected in my case!

My test script:

#!/bin/bash

echo "This is a test script"
echo "Sleeping"
sleep 30
echo "Done"

Executable permission is set for www-data.

My PHP page:

<?php
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
@ini_set('output_buffering', 0);
@apache_setenv('output_buffering', 0);

echo "Here<br>";
flush();
$cmd = "../test.sh";
$pipes = array();
$descriptors = array(
             0 => array("pipe", "r"),
             1 => array("pipe", "w"),
             2 => array("pipe", "w"),
             );
echo "Starting process<br>";
flush();
$process = proc_open($cmd, $descriptors, $pipes, realpath('./'), array());
echo "<pre>";
if (is_resource($process)) {
    while ($s = fgets($pipes[1])) {
        print $s;
        flush();
    }
} else {
    print "Cannot create process\n";
}
echo "</pre>";
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
?>

NB. My test script, test.sh, is in a directory above the PHP page, thus ../test.sh. Not that that changes anything. But it's not a typo.

My php.ini has those (although, I wasn't too keen at changing that server wide, but I wanted to test if that was the issue):

zlib.output_compression = Off
output_buffering = Off

I use LAMPP.

If I run the PHP page in a terminal,

$ php test.php

It works fine: I immediately get "This is a test script" and "Sleeping", and after a while, "Done".

If I load the page in my browser, it does not work: it waits until test.sh has completed before outputting anything.

Edited: If I add echo str_pad('',4096)."\n" in the loop, then it works. However, this fix suggests that for a reason I do not understand, output buffering is still set to its default value (4096) and not off as I tried to configure.

while ($s = fgets($pipes[1])) {
  print $s;
  echo str_pad('',4096)."\n";    
  flush();
}

Furthermore, this solution is not perfect because , in reality, it adds spaces to the output.

I am looking for a solution that

  • refreshes output of the PHP page
  • does not modify php.ini
  • does not modify the output

Thanks!


Solution

  •     ob_flush();
        flush();
    

    Flushes the output to the web server/browser