Hudzilla.org - the homepage of Paul Hudson
Contents > Functions Wish List | Report Bug | About Me ]

4.13     Connection-related functions: ignore_user_abort(), register_shutdown_function(), and connection_status()

This is NOT the latest copy of this book; click here for the latest version.

int ignore_user_abort ( [bool setting])

void register_shutdown_function ( callback function)

int connection_status ( )

For the most part, your PHP scripts will produce output destined for a client somewhere, usually a web browser. But what happens if that web browser is closed halfway through your script's execution - do you finish processing and hope for the best? Furthermore, how you can always be sure a certain clean up function will be called when your script ends? The answer involves two functions, which are ignore_user_abort() and register_shutdown_function(), which allow you to carry on processing after the user has cancelled their request and you to specify the name of a function to use when the script ends, respectively.

Passing true to ignore_user_abort() as its only parameter will instruct PHP that the script is not to be terminated even if your end-user closes their browser, has navigated away to another site, or has clicked Stop. This is useful if you have some important processing to do and you do not want to stop it even if your users click cancel, such as running a payment through on a credit card. You can of course also pass false to ignore_user_abort(), thereby making PHP exit when the user closes the connection.

For handling shutdown tasks, register_shutdown_function() is perfect, as it allows you to register with PHP a function to be run when script execution ends. Take a look at this example:

<?php
    
function say_goodbye() {
        echo
"Goodbye!\n";
    }

    
register_shutdown_function("say_goodbye");
    echo
"Hello!\n";
?>

Save that code and try it out - you should get the following in output:

Hello!
Bye!

As you can see, say_goodbye() is called when the script ends, as planned. You can call register_shutdown_function() several times passing in different functions, and PHP will call all of the functions in the order you registered them when the script ends. If any of your shutdown functions call "exit", the script will terminate without running the rest of the functions.

One very helpful use for shutdown functions is to handle unexpected script termination - i.e. script timeout. If your script times out, you have just lost control over whatever you were doing, so you either need to back up and undo whatever you have just done, or you need to clean up and terminate cleanly. Either way, shutdown functions are perfect: register a clean up function near the start of the script, and, when script timeout happens, the clean up function will automatically run.

For example, the following script will print out "Sleeping...Goodbye!":

<?php
    
function say_goodbye() {
        print
"Goodbye!\n";
    }

    
register_shutdown_function("say_goodbye");
    
set_time_limit(1);
    print
"Sleeping...\n";
    
sleep(2);
    print
"Done!\n";
?>

The "Done!" print line will never be executed, because the time limit is set to 1, and the sleep() function is called with 2 as its parameter, so the script will sleep for 2 seconds. As a result, "Sleeping..." gets printed, followed probably by a warning about the script going over its time limit, then the shutdown function gets called.

Of course, the problem with this thinking is that shutdown functions execute irrespective of there having been a timeout or not, therefore it is not wise to set a cleanup function as a shutdown function - it will always execute! However, PHP comes to the rescue with the connection_status() function, which takes no parameters and returns 0 if the connection is live and execution is still taking place, 1 if the connection is aborted (connection_timeout() will also return true), 2 if the connection has been aborted (connection_aborted() will also return true), and 3 if the connection has been aborted and subsequently timed out.

The last situation is only possible if ignore_user_abort(true) has been used, and the script subsequently timed out. Note that the values 0, 1, 2, and 3 evaluate to the constants CONNECTION_NORMAL, CONNECTION_ABORTED, CONNECTION_TIMEOUT, and CONNECTION_ABORTED | CONNECTION_TIMEOUT (a bit-wise OR of the previous two).

So, with this new function in mind, here is our script rewritten to take notice of whether shutdown occurred because the script finished or because script timeout was reached:

<?php
    
function say_goodbye() {
        if (
connection_status() == CONNECTION_TIMEOUT) {
            print
"Script timeout!\n";
        } else {
            print
"Goodbye!\n";
        }
    }

    
register_shutdown_function("say_goodbye");
    
set_time_limit(1);
    print
"Sleeping...\n";
    
sleep(2);
    print
"Done!\n";
?>

This time, although "Done!" will still not get printed out, the script is at least able to detect a simple script timeout.





<< 4.12 Executing external programs: exec(), passthru(), and virtual()   4.14 Altering the execution environment: ini_get(), ini_set(), and set_time_limit() >>
Table of Contents
Want to see this stuff in print? PHP in a Nutshell takes the core topics covered here, adds in thousands of edits from the editorial team and myself, and combines them to make an unbeatable reference for PHP programmers at all levels.



My latest book has hundreds more tips on how to use PHP, Apache, and MySQL, plus Perl, Python, shell scripts, performance tuning, and more!



Top-right shadow
 
Bottom-left shadow Bottom shadow

Comments from other readers
A PHP User - 06 Sep 2008

Sorry for the previous post, I just tested and noticed that PHP wont increase the execution time already used during sleep() or usleep(), so it wont "waste" max_execution_time during the sleep.

It seems that sleep() and usleep() do increase the execution time already if set_time_limit() is used...

A PHP User - 06 Sep 2008

cast3r:

PHP will not terminate the script execution during sleep() or usleep() even if the max_execution_time was reached, it does it immediantly after the sleep function has ended.

chima/chytons@yahoo.com - 06 Sep 2008

For handling shutdown tasks, register_shutdown_function() is perfect, as it allows you to register with PHP a function to be run when script execution ends. Take a look at this example:
<?php
function say_goodbye() {
echo "Goodbye!\n";
}

register_shutdown_function("say_goodbye");
echo "Hello!\n";
?>

Save that code and try it out - you should get the following in output:
Hello!
Bye!

The output should read:
Hello!
Goodbye!

Not:
Hello!
Bye!

cast3r - 06 Sep 2008

4.11:
" Note that the default maximum script execution time is 30 seconds, but you can use sleep() and usleep() to make your scripts go on for longer than that because technically PHP does not have control during the sleep operation."

4.13 (here):
" The "Done!" print line will never be executed, because the time limit is set to 1, and the sleep() function is called with 2 as its parameter, so the script will sleep for 2 seconds. As a result, "Sleeping..." gets printed, followed probably by a warning about the script going over its time limit, then the shutdown function gets called."

so, does it have control?

TxtEdMacs - 06 Sep 2008

Rach, I got the same result, however, I am running the 4.3.10 cli version. In the very next section, I modified the code a bit and found an unexpected result. First the code:

<?php
print "Display_errors is turned on: ";
print (int) ini_get("display_errors") . "\n";

print "How long is execution limit? ";
print (string) ini_get("max_execution_time") . "\n"
?>

which gave:

Display_errors is turned on: 1
How long is execution limit? 0

Check this link: http://us3.php.net/features.commandline

To summarize, the "0" means an unlimited execution time. In the table, it is spelled out:

max_execution_time 0 (unlimited)

Due to endless possibilities of using PHP in shell environments, the maximum execution time has been set to unlimited. Whereas applications written for the web are often executed very quickly, shell application tend to have a much longer execution time.

Even if you are not using version 5 run the those couple lines of code to see the output for max_execution_time. I was initially perplexed, because I had been spending time in the php.ini file where max_execution_time was clearly set:

max_execution_time = 30 ; Maximum execution time of each script, in seconds

Well when php5-cli is ready for Debian I can try this code again. Sorry, I am not certain whether the same logic on execution times holds for version 5.

Mrman - 06 Sep 2008

I spotted that to Zameer

Rach - 06 Sep 2008

When I ran this code:-

<?php
function say_goodbye() {
print "Goodbye!\n";
}

register_shutdown_function("say_goodbye");
set_time_limit(1);
print "Sleeping...\n";
sleep(2);
print "Done!\n";
?>

it printed out 'Done' before 'Goodbye'.

Zameer - 06 Sep 2008

error in the output of the first example code, that is
the output must be
"Goodbye!"
not
"Bye!"



Add comment
Please note that by posting a comment here you are committing it to the public domain. This is important so that others can make use of your code themselves, and also so that I can incorporate helpful notes directly into the main text. Comments are limited to 2000 characters in length.

If you are reporting an error in the content, please tell me directly.

Your name/email address:
Your comment:
 
Now, in order to verify that you're a real person, please answer this simple question: what is ten plus ten?
The answer is:
(please write in
numbers, eg 19)


Top-right shadow
 
Bottom-left shadow Bottom shadow