When running PHP, and you want it to immediately return HTML to the browser, close the connection (ish), and then continue processing...
The following works when the connection is HTTP/1.1, but does not when using Apache 2.4.25
, with mod_http2
enabled, and you have a browser that supports HTTP/2 (e.g. Firefox 52 or Chrome 57).
What happens is the Connection: close
header is not sent.
<?php
function http_connection_close($output_html = '') {
apache_setenv('no-gzip', 1); // Disable mod_gzip or mod_deflate
ignore_user_abort(true);
// Close session (if open)
while (ob_get_level() > 0) {
$output_html = ob_get_clean() . $output_html;
}
$output_html = str_pad($output_html, 1023); // Prompt server to send packet.
$output_html .= "\n"; // For when the client is using fgets()
header('Connection: close');
header('Content-Length: ' . strlen($output_html));
echo $output_html;
flush();
}
http_connection_close('<html>...</html>');
// Do stuff...
?>
For similar approaches to this problem, see:
And as to why the connection
header is removed, the documentation for the nghttp2
library (as used by Apache) states:
https://github.com/nghttp2/nghttp2/blob/master/doc/programmers-guide.rst
HTTP/2 prohibits connection-specific header fields. The
following header fields must not appear: "Connection"...
So if we cannot tell the browser to close the connection via this header, how do we get this to work?
Or is there another way of telling the browser that it has everything for the HTML response, and that it shouldn't keep waiting for more data to arrive.
This answer works only when web server communicates to PHP over FastCGI
protocol.
To send the reply to user (web server) and resume processing in the background, without involving OS calls, invoke the fastcgi_finish_request()
function.
<?php
echo '<h1>This is a heading</h1>'; // Output sent
fastcgi_finish_request(); // "Hang up" with web-server, the user receives what was echoed
while(true)
{
// Do a long task here
// while(true) is used to indicate this might be a long-running piece of code
}
php-fpm
child process will be busy and unable to accept new requests until they're done with processing this long running task.If all available php-fpm
child processes are busy, then your users will experience hanging page. Use with caution.
nginx
and apache
servers both know how to deal with FastCGI
protocol so there should be no requirement to swap out apache
server for nginx
.