Search code examples
phpbrowserinfinite-loopabort

PHP abort infinite loop on user disconnect


I am doing a minor experiment with PHP. I have a file named 'infinity.txt', and in that file, I write an incrementing number every 0.25 seconds.

while(true){

    file_put_contents('infinity.txt', ++$i.PHP_EOL, FILE_APPEND);
    usleep(250 * 1000);

}

This works fine and well, but when I close the tab in my browser, the script continues running. A browser request abort is no Ctrl. + C, so there's no surprise in that, but I was still wondering whether it is possible to abort an infinite loop when the user disconnects, or if there is any method to see if the user is still connected.

Calling register_shutdown_function beforehand is completely useless, by the way, even when the linked function has a die() within.

UPDATE: It seems to me that something might be done using the connection_aborted() function.

UPDATE 2: I have changed my code to look like this, but alas, the infinite loop does not cancel:

while(true){

    if(connection_aborted()){

        file_put_contents('infinity.txt', 'CONNECTION ABORTED.', FILE_APPEND);
        die();

    }

    file_put_contents('infinity.txt', ++$i.PHP_EOL, FILE_APPEND);
    usleep(250 * 1000);

}

UPDATE 3: I am now echoing and flushing some text in every iteration, yet still to no avail:

while(true){

    echo '0';
    ob_flush();
    flush(); // necessary for proper checking

    if(connection_aborted()){

        file_put_contents('infinity.txt', 'CONNECTION ABORTED.', FILE_APPEND);
        die();

    }

    file_put_contents('infinity.txt', ++$i.PHP_EOL, FILE_APPEND);
    usleep(250 * 1000);

}

UPDATE 4: The code shown in the previous update started working for some weird reason upon restarting Apache, without me changing any settings in the php.ini. What ultimately helped was adding an ignore_user_abort(true); at the very beginning.


Solution

  • Do this way (I left explanation in comments):

    ignore_user_abort(1); //we'll handle it by ourselves
    header('Transfer-Encoding:chunked'); //HTTP 1.1: do not capture immediately (bin)
    flush();
    ob_flush();
    
    $i = 0;
    set_time_limit(0);
    while(1)
    {
        echo "0"; //do this: sending data to dead TCP connection will fail
        flush();
        ob_flush();
        if(connection_status()!=0)
        {
    
            file_put_contents('infinity.txt', 'CONNECTION ABORTED.', FILE_APPEND);
            echo "0\r\n\r\n"; //stream termination packet (double \r\n according to proto)
            flush();
            ob_flush();
            exit();
    
        }
    
        file_put_contents('infinity.txt', ++$i.PHP_EOL, FILE_APPEND);
        usleep(250 * 1000);
    
    }