Search the blog

If I user hits the x button in their browser or the network connection drops does your PHP script keep running? It’s a good question. If it doesn’t then you could, in theory, end up with corrupt data (if you’re partway through taking a card payment and then adding an invoice to the database, for example). Of course, if you are using a database you should make use of transactions for this purpose but there are other things like logging that you may wish to run, even if the user aborts.

First off, PHP uses the ignore_user_abort value to determine whether it should carry on or not. This is set to Off by default. However, there is one important caveat. The notes on the subject say:

PHP will not detect that the user has aborted the connection until an attempt is made to send information to the client.

It is generally accepted among developers to follow some kind of MVC pattern where your HTML is contained in views and outputted at the end. If you follow such a pattern it will likely make no difference to you in terms of data integrity, logging, etc what the value of ignore_user_abort is.

The code below demonstrates how this works.

Here we switch output buffering on so we have control over what and when PHP sends to the browser. By default, with output buffering off, HTML is sent to the browser in pieces as the script is processed. With output buffering on the HTML is stored in memory and sent at the end unless, as the script below does, content is “flushed” from the buffer.

You will need to toggle $output between true and false when testing this.

// ignore_user_abort should be set to Off, the default

// There are three outcomes:

// 1. If not aborted the file will be written either way
// 2. If output is set to false and it is abandoned, the file is still written after ~10 seconds
// 3. If output is set to true and it is abandoned, the file is not written

// Turn output buffering on and make it implicit so we don't need to call ob_flush() and flush()
ob_start();
ob_implicit_flush(true);
ob_end_flush();

// Allow a generous amount of time for the script to run
set_time_limit(60);

// Whether to putput or not
$output = true;

// To keep track of when the log was generated
$log = date('Y-m-d H:i:s') . PHP_EOL;

for ($counter = 1; $counter <= 5; $counter ++) {

    // The output buffer won't work with tiny amounts of text so adding on some white space makes the flush work
    $line = 'Iteration ' . $counter . ' ' .  str_repeat(' ', 1024 * 50) . PHP_EOL;

    $log .= $line;

    if ($output === true) {

        echo $line . '
';

    }

    sleep(2);

}

// We know the script finished
file_put_contents('aborted.txt', $log);
Tim Bennett is a Leeds-based web designer from Yorkshire. He has a First Class Honours degree in Computing from Leeds Metropolitan University and currently runs his own one-man web design company, Texelate.