skip to Main Content

I have a time-consuming php script, so I’d like to give the user some feedback. Simplified it to get to the core problem. This script works perfectly fine in Firefox (flushing the output instantly), but Safari waits until all the content is generated. Why? And how could I fix that?

<?php
ini_set('max_execution_time', 0);
header('Content-Encoding: none;'); 
header('Content-type: text/html; charset=utf-8');

$j = 8;
$k = pow(2, 10);

echo "One moment please...".str_pad('', $k)."<br />n<br />n";
flush();

$i = 0;
while ($i < $j) { 
    $i++;
    echo "Test ".$i.str_pad('',$k)."<br />n";
    flush();
    sleep(1);
} 
?>

And by the way: Chrome won’t load this page at all, it gives me ERR_CONTENT_DECODING_FAILED.

Furthermore I tried to put

<IfModule mod_env.c>
    SetEnv no-gzip 1
</IfModule>

in .htaccess but no luck. Also tried SetEnv no-gzip dont-vary. Any clues how to get Safari (and Chrome) do the same as Firefox?

EDIT: I see this question got voted down because of "lack of research". I wanted to keep the question as simple as possible, but I’d like you to know I spent a whole day trying to get this to work. I read everything on php.net about flush(), ob_flush(), ob_start(), etc. and I read almost every question about flush + all comments on Stackoverflow from the past 20+ years.
I tried to add ini_set('output_buffering', 'On'); or ini_set('output_buffering', 'Off');, added ob_start(null, 4096);, ini_set('zlib.output_compression', 'Off');, header('Cache-Control: no-cache');, header('X-Content-Type-Options: nosniff'); and/or header('X-Accel-Buffering: no');. I put @ob_flush(); before or after my flush();, tried to raise the value in str_pad up to 2^16 (65,536) but nothing helped.
Unfortunately I don’t seem to have any control over the Apache server at my hosting provider (which runs PHP 8.1 with FastCGI). Since it works on Firefox I must have done something right, I thought.

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to hareth py I found the answer!

    <?php 
    ini_set('max_execution_time', 0);
    header('Content-Encoding: none;');
    header('Content-type: text/html; charset=utf-8;');
    ob_start("ob_gzhandler");
    $j = 200;
    $k = pow(2, 10);
    
    echo "One moment please...".str_pad('', $k)."<br />n<br />n";
    
    
    $i = 0;
    while ($i < $j) {
        $i++;
        echo "Test ".$i.str_pad('',$k)."<br />n";
        ob_flush();
        usleep(100000);
    } 
    ?>
    

    I raised $j to 200 and lowered the sleep to 0.1 second. Safari is indeed a little slow to respond, but it will display line by line eventually. Just like Firefox and Chrome.


  2. Edit:
    ob_start("ob_gzhandler") is intended to be used as a callback function for ob_start() to help facilitate sending gz-encoded data to web browsers that support compressed web pages. source

    <?php
    ini_set('max_execution_time', 0);
    header('Content-Encoding: none;');
    header('Content-type: text/html; charset=utf-8');
    ob_start("ob_gzhandler");
    $j = 8;
    $k = pow(2, 10);
    
    echo "One moment please...".str_pad('', $k)."<br />n<br />n";
    
    
    $i = 0;
    while ($i < $j) {
        $i++;
        echo "Test ".$i.str_pad('',$k)."<br />n";
        ob_flush();
        sleep(1);
    }
    ?>
    

    Outputs (on Chrome):

    One moment please…

    Test 1 Test 2 Test 3 Test 4 Test 5 Test 6 Test 7 Test 8

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search