3

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!

8
  • The behaviour you're trying to achieve depends on many factors. I assume you read php.net/flush page. What browser are you using? Try adding newlines after print $s in the loop so it'd be print $s . "\n", see if that helps. Commented Aug 28, 2015 at 9:59
  • There is one caveat that you should be aware of. PHP’s output_buffering setting has two possible values. One is to indicate whether it is On and the second is it to indicate the maximum size of the buffer. If output_buffering is set to 1, then you might not be able to see your content or browser loading indicator rotating until PHP code execution is finished. This is because having output_buffering on 1 means that we have enabled it but haven’t specified a maximum size, so in this case PHP buffers can hold data up to the number in the memory_limit setting. Source:sitepoint.com Commented Aug 28, 2015 at 10:04
  • @marekful no, that does not change anything (and honestly, I don't think why it should, as it's only modifying the display). Commented Aug 28, 2015 at 11:19
  • @sanderbee well output_buffering is Off in my case. So there's no buffer size. So, that doesn't solve my issue either, unless I misunderstand your point. Commented Aug 28, 2015 at 11:24
  • 1
    Regardless of server side buffering or compression, the browser/agent may employ some buffering strategy. I proposed the newline based on PHP's flush documentation, which mentions it could help (though somewhat seem outdated as it refers to Netscape). Also, look at the first entry under 'User Contributed Notes'. It claims to have a tested solution which sends content line by line to the browser which displays it line by line as they are being sent. In that solution 4K of newlines are sent to achieve the desired result. Maybe you should give it a try. (str_pad('',4096)."\n";) Commented Aug 28, 2015 at 11:26

1 Answer 1

0
    ob_flush();
    flush();

Flushes the output to the web server/browser

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.