Around 2017 I wrote a SSE (PHP) script and the JavaScript code. It worked fine with PHP-5 + HTTP/1 and the Firefox of that era.
The same code now does not work with Firefox-140 esr or latest Chrome with PHP-8.2 + HTTP/2. I have a time-out after 60 seconds.
Also tried the simplest SSE example from lucidar.me, zip. If I remove the while
loop something that I think it's bad, it's working. In that case the JavaScript makes requests every 5 seconds. I think this defeats the purpose of SSE.
The code with while
works fine with curl but not with browsers.
My implementation and the rationale of SSE is that the server decides when to send the data, not the client. Right?
It changed something in JavaScript I guess, in browsers, or did I miss something? It's the HTTP/2 the problem?
The code works with curl like that (while
version)
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache, no-transform');
header('X-Accel-Buffering: no');
header('Access-Control-Allow-Origin: *');
set_time_limit(0);
@ini_set('zlib.output_compression', 0);
@ob_implicit_flush(true);
// Loop until the client close the stream
while (true) {
// Echo time
$time = date('r');
echo "data: The server time is: {$time}\n\n";
// Flush buffer (force sending data to client)
@ob_flush();
flush();
// Wait 2 seconds for the next message / event
sleep(2);
}
?>
Added info after @Hybrid gave me an idea.
Forgot to mention that I use apache. I switched to HTTP/1 and the result is bizarre. curl
now responds after 2 minutes. With HTTP/2 the response was instant. Now Firefox responds like curl.
Testing with HTTP/1 only server
export LC_ALL=C; date; curl https://XXX/sse.php
Fri Jul 25 23:17:48 EEST 2025 <-- date invoked
data: The server time is: Sat, 26 Jul 2025 00:19:18 +0300 <-- received after 1 minute and 30 seconds.
data: The server time is: Sat, 26 Jul 2025 00:19:20 +0300
data: The server time is: Sat, 26 Jul 2025 00:19:22 +0300
... total 58 lines of data: received.
Here testing with HTTP/2 again. Only curl works, not browsers.
curl -v URL
by-default uses HTTP/2:
* ALPN: curl offers h2,http/1.1
* ALPN: server accepted h2
So browsers, can't handle SSE with HTTP/2?
It helps if you get sleep :) The solution was to disable buffering but since I use php-fpm
with apache mod_proxy_fcgi
I cannot disable output buffering script wise (maybe I am wrong here?).
So one solution is for apache conf is here: stackoverflow link
Flush packets every 10ms.
# max=10 = 10ms
<Proxy "fcgi://localhost/" enablereuse=on flushpackets=on max=10>
</Proxy>
I don't know the implications of that. But for SSE it works both for http://
and https://
.
So maybe a better solution is here
echo 'SetEnv no-gzip 1' > .htaccess
Problem is that works only with https://
not with http://
It seems that those in .php
script are useless
@ini_set('zlib.output_compression', 0);
@ini_set('output_buffering', 'off');
because they run AFTER apache?
Now it works with HTTP/2 and HTTP/1.
Thanks @hybrid for the inspiration.