PHP auto-kill a script if the HTTP request is cancelled/closed

This is what you're looking for: http://php.net/manual/en/function.ignore-user-abort.php

Stopping a script in the middle of execution can lead to unexpected results, so caveat emptor


As pointed out by @metadings php does have a function to check for connection abort named connection_aborted(). It will return 1 if connection is terminated otherwise 0.

In a long server side process the user may need to know if the client is disconnected from the server or he has closed the browser then the server can safely shutdown the process.

Especially in a case where the application uses php sessions then if we left the long process running even after the client is disconnected then the server will get unresponsive for this session. And any other request from the same client will wait until the earlier process executes completely. The reason for this situation is that the session file is locked when the process is running. You can however intentioanlly call session_write_close() method to unlock it. But this is not feasible in all scenarios, may be one need to write something to session at the end of the process.

Now if we only call connection_aborted() in a loop then it will always return 0 whether the connection is closed or not.

0 means that the connection is not aborted. It is misleading. However, after re-search and experiments if have discovered that the output buffer in php is the reason.

First of all in order to check for aborts the developer in a loop must send some output to the client by echoing some text. For example:

print " ";

As the process is still running, the output will not be sent to the client. Now to send output we then need to flush the output buffer.

flush ();
ob_flush ();

And then if we check for aborts then it will give correct results.

if (connection_aborted () != 0) {
  die();
}

Following is the working example, this will work even if you are using PHP session:

session_start ();
ignore_user_abort ( TRUE );

file_put_contents ( "con-status.txt", "Process started..\n\n" );

for($i = 1; $i <= 15; $i ++) {

    print " ";

    file_put_contents ( "con-status.txt", "Running process unit $i \n", FILE_APPEND );
    sleep ( 1 );

    // Send output to client
    flush ();
    ob_flush ();

    // Check for connection abort
    if (connection_aborted () != 0) {
        file_put_contents ( "con-status.txt", "\nUser terminated the process", FILE_APPEND );
        die ();
    }

}

file_put_contents ( "con-status.txt", "\nAll units completed.",  FILE_APPEND );

EDIT 07-APR-2017

If someone is using Fast-Cgi on Windows then he can actually terminate the CGI thread from memory when the connection is aborted using following code:

if (connection_aborted () != 0) { apache_child_terminate(); exit; }


One way I've found which is the easiest way to handle this time-out issue is as such:

1: set a value on the server as 'processing'. Start an independent thread to do the processing.
2: The initial ajax call returns a success
3: The javascript on the page goes into 'waiting mode' which sends a new ajax request every 10 or 30 or 60 seconds or five or ten minutes or whatever (depending on your situation) to find out whether the value on the server is still set to 'processing'.
4: The independent thread completes. It sets the value on the server to 'done'.
5: The javascript on the page makes its next waiting-mode query, and returns 'done' and the appropriate data.

4b: If an obscene amount of time goes by without a 'done', it registers as a failure. How much time is obscene depends upon your situation. Send an ajax call updating the value from 'processing' to 'cancel'. 5b: The independent thread periodically checks the status to make sure it's still set to 'processing'. If it sees a mode-shift to 'cancel' it cancels itself.


Check out PHP connection_aborted() function. While doing your processing, you can sometimes check for the aborted connection to gracefully cancel the progress, as one would do in an interactive threading model.

Tags:

Php

Ajax