Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

ajax

php

The problem is that for a long process the PHP script keeps on executing whether or not the client browser is currently connected or not. Is there any possibility that if the client has terminated the Ajax call to a script then the script also terminates on server?

like image 391
asim-ishaq Avatar asked May 13 '13 14:05

asim-ishaq


1 Answers

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; }

like image 109
asim-ishaq Avatar answered Oct 12 '22 22:10

asim-ishaq