skip to Main Content

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

2

Answers


  1. 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.

    Login or Signup to reply.
  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-timendata: " . date('G:H:s', time()) . "nn"
    
        //Append other events with logic
    
        echo $event;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search