How do I close a connection early? How do I close a connection early? ajax ajax

How do I close a connection early?


The following PHP manual page (incl. user-notes) suggests multiple instructions on how to close the TCP connection to the browser without ending the PHP script:

Supposedly it requires a bit more than sending a close header.


OP then confirms: yup, this did the trick: pointing to user-note #71172 (Nov 2006) copied here:

Closing the users browser connection whilst keeping your php script running has been an issue since [PHP] 4.1, when the behaviour of register_shutdown_function() was modified so that it would not automatically close the users connection.

sts at mail dot xubion dot hu Posted the original solution:

<?phpheader("Connection: close");ob_start();phpinfo();$size = ob_get_length();header("Content-Length: $size");ob_end_flush();flush();sleep(13);error_log("do something in the background");?>

Which works fine until you substitute phpinfo() for echo('text I want user to see'); in which case the headers are never sent!

The solution is to explicitly turn off output buffering and clear the buffer prior to sending your header information. Example:

<?phpob_end_clean();header("Connection: close");ignore_user_abort(true); // just to be safeob_start();echo('Text the user will see');$size = ob_get_length();header("Content-Length: $size");ob_end_flush(); // Strange behaviour, will not workflush(); // Unless both are called !// Do processing here sleep(30);echo('Text user will never see');?>

Just spent 3 hours trying to figure this one out, hope it helps someone :)

Tested in:

  • IE 7.5730.11
  • Mozilla Firefox 1.81

Later on in July 2010 in a related answer Arctic Fire then linked two further user-notes that were-follow-ups to the one above:


It's necessary to send these 2 headers:

Connection: closeContent-Length: n (n = size of output in bytes )

Since you need know the size of your output, you'll need to buffer your output, then flush it to the browser:

// buffer all upcoming outputob_start();echo "We'll email you as soon as this is done.";// get the size of the output$size = ob_get_length();// send headers to tell the browser to close the connectionheader("Content-Length: $size");header('Connection: close');// flush all outputob_end_flush();ob_flush();flush();// if you're using sessions, this prevents subsequent requests// from hanging while the background process executesif (session_id()) session_write_close();/******** background process starts here ********/

Also, if your web server is using automatic gzip compression on the output (ie. Apache with mod_deflate), this won't work because actual size of the output is changed, and the Content-Length is no longer accurate. Disable gzip compression the particular script.

For more details, visit http://www.zulius.com/how-to/close-browser-connection-continue-execution


You can use Fast-CGI with PHP-FPM to use the fastcgi_end_request() function. In this way, you can continue to do some processing while the response has already been sent to the client.

You find this in the PHP manual here: FastCGI Process Manager (FPM); But that function specifically is not further documented in the manual. Here the excerpt from the PHP-FPM: PHP FastCGI Process Manager Wiki:


fastcgi_finish_request()

Scope: php function

Category: Optimization

This feature allows you to speed up implementation of some php queries. Acceleration is possible when there are actions in the process of script execution that do not affect server response. For example, saving the session in memcached can occur after the page has been formed and passed to a web server. fastcgi_finish_request() is a php feature, that stops the response output. Web server immediately starts to transfer response "slowly and sadly" to the client, and php at the same time can do a lot of useful things in the context of a query, such as saving the session, converting the downloaded video, handling all kinds of statistics, etc.

fastcgi_finish_request() can invoke executing shutdown function.


Note: fastcgi_finish_request() has a quirk where calls to flush, print, or echo will terminate the script early.

To avoid that issue, you can call ignore_user_abort(true) right before or after the fastcgi_finish_request call:

ignore_user_abort(true);fastcgi_finish_request();