2

I'm currently trying to use Server-Sent Events using PHP, but they are not firing instantly on the browser.

Here is my code:


<?php
    
    // Headers must be processed line by line.
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    header('X-Accel-Buffering: no');
    while(true)
    {
    
        // Set data line
        echo "event: server-time";
        echo "data: " . date( 'G:H:s', time() );
        //echo str_repeat(" ", 4096);
    
        ob_end_flush();     // Strange behaviour, will not work
        flush();            // Unless both are called !
    
        // Wait one second.
        sleep(1);

}

While it works, it seems like there is a minimum size for the buffer to flush and send data to the browser. In fact, if I uncomment the str_repeat line, I get almost instantaneous events (as in, one every second). However, if I keep it commented, the browser keeps loading for around 2 minutes, before sending all the data from the past 2 minutes.

I've looked around on Stack Overflow but I couldn't find an answer that works within all of them.

Here are some infos from phpinfo() that I find useful in this context, don't hesitate to ask for more:

PHPINFO

Name Value
Server API FPM/FastCGI
PHP Version  7.4.30
BZip2 Support  Enabled
Registered PHP Streams https, ftps, compress.zlib, compress.bzip2, php, file, glob, data, http, ftp, phar, ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp, zip
Registered Stream Socket Transports  tcp, udp, unix, udg, ssl, tls, tlsv1.0, tlsv1.1, tlsv1.2, tlsv1.3
Registered Stream Filters zlib., bzip2., convert.iconv., string.rot13, string.toupper, string.tolower, string.strip_tags, convert., consumed, dechunk, mcrypt., mdecrypt., http.*
 Stream Wrapper support compress.bzip2://
 Stream Filter support  bzip2.decompress, bzip2.compress
BZip2 Version 1.0.6, 6-Sept-2010
output_buffering  no value
output_encoding no value
output_handler no value
zlib.output_compression Off
zlib.output_compression_level  -1
zlib.output_handler no value
Chris Haas
  • 53,986
  • 12
  • 141
  • 274
Gugu72
  • 2,052
  • 13
  • 35

2 Answers2

2

ob_flush() is for PHP's own buffer (which is why it comes first), and flush() is supposed to flush the web server cache. So your code is correct. I think the problem you are having is due to you using "FPM/FastCGI"

I found this comment in the manual:

If you want to make flush work when using php-fpm from Apache httpd with mod_proxy_fcgi, since 2.4.31 you can append flushpackets=on to enable flushing,

This page has a few suggestions: https://serverfault.com/q/488767 (Note that they are all older than the above manual comment.)

Or, if not bound to FastCGI, another solution would be to switch to Apache's PHP module, where flush() definitely works.

Darren Cook
  • 27,837
  • 13
  • 117
  • 217
-2

I dont know why people use while loop in SSE codes. Doesnt it hang your browsers?.

<?php
    // Headers must be processed line by line.
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    header('X-Accel-Buffering: no');
    // Set data line
    $events = "";
    $events .= "event: server-time\ndata: " . date('G:H:s', time()) . "\n\n"

    //Append other events with logic

    echo $event;
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 26 '22 at 13:25
  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. - [From Review](/review/late-answers/32545666) – Nico Haase Aug 28 '22 at 13:07