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
ob_flush()
is for PHP’s own buffer (which is why it comes first), andflush()
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:
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.I dont know why people use while loop in SSE codes.
Doesnt it hang your browsers?.