# Make set_time_limit() timeout a catchable fatal error

- Thread: https://externals.io/message/51614
- Original archive: https://news-web.php.net/php.internals/51614
- Started by Sebastian Bergmann on 2011-03-08T13:05:57+00:00
- Messages: 17
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #51614 — Sebastian Bergmann — 2011-03-08T13:05:57+00:00

URL: https://externals.io/message/51614#51614

Could `set_time_limit()` be changed in such a way that it triggers a
  catchable fatal error instead of a fatal error? Thanks!

-- 
Sebastian Bergmann                    Co-Founder and Principal Consultant
http://sebastian-bergmann.de/                           http://thePHP.cc/

---

## #51615 — Pierre Joye — 2011-03-08T13:39:33+00:00

URL: https://externals.io/message/51614#51615 · In reply to: #51614

hi,

is not the goal of this setting to prevent that a script runs longer
than a given time? A catchable error will prevent that to happen.


>  Could `set_time_limit()` be changed in such a way that it triggers a
>  catchable fatal error instead of a fatal error? Thanks!
>
> --
> Sebastian Bergmann                    Co-Founder and Principal Consultant
> http://sebastian-bergmann.de/                           http://thePHP.cc/
>
> --
> 
> 
>
>



-- 
Pierre

@pierrejoye | http://blog.thepimp.net | http://www.libgd.org

---

## #51616 — Jared Williams — 2011-03-08T14:02:37+00:00

URL: https://externals.io/message/51614#51616 · In reply to: #51614

Hi,

Would `pcntl_alarm()` work?

Jared 

> -----Original Message-----
> From: Sebastian Bergmann [mailto:sebastian@php.net] 
> Sent: 08 March 2011 13:06
> To: internals@lists.php.net
> Subject: [PHP-DEV] Make `set_time_limit()` timeout a catchable 
> fatal error
> 
>   Could `set_time_limit()` be changed in such a way that it triggers a
>   catchable fatal error instead of a fatal error? Thanks!
> 
> -- 
> Sebastian Bergmann                    Co-Founder and 
> Principal Consultant
> http://sebastian-bergmann.de/                           
> http://thePHP.cc/
> 
> --
>  To 
> unsubscribe, visit: http://www.php.net/unsub.php

---

## #51629 — David Muir — 2011-03-09T01:30:49+00:00

URL: https://externals.io/message/51614#51629 · In reply to: #51615

Although it doesn't let you recover from a timeout, you could use
register_shutdown_function to gracefully exit after a fatal error.

register_shutdown_function(function(){
    $error = `error_get_last()`;
    if($error && $error['type'] === E_ERROR){
        echo 'PHAIL! Oh noes, something went wrong!';
        // do whatever else you need to do before quitting
    }
});

Cheers,
David


> hi,
>
> is not the goal of this setting to prevent that a script runs longer
> than a given time? A catchable error will prevent that to happen.
>
> 
> > […]

---

## #51630 — Hannes Landeholm — 2011-03-09T13:56:46+00:00

URL: https://externals.io/message/51614#51630 · In reply to: #51629

I second making time limit reached catchable. All non catchable fatal errors
are a problem for me. I need to handle problems gracefully to ensure the
stability of production systems instead of PHP just killing itself without
warning. I just reported a similar issue:
http://bugs.php.net/bug.php?id=54195

A simple way to implement this would be to register a function that would be
called N seconds before the script would timeout.

register_timeout_handler(2, function() { die("PHP timed out."); });

It would be called just as a shutdown function - in fact I'd like to use the
same function as my shutdown function and get the error with
 `error_get_last()`. Of course set_time_limit(0) could be used in this function
to prevent the timeout of the timeout handler. This does not "prevent"
timeout since set_time_limit could have been called by the script before the
timeout anyway.

On that note I also miss a function which returns the time the script can
keep running for. If that calculate needs to be calculated to implemented to
implement this, why not make the value available to the PHP script?

~Hannes



> Although it doesn't let you recover from a timeout, you could use
> register_shutdown_function to gracefully exit after a fatal error.
>
> register_shutdown_function(function(){
>    $error = `error_get_last()`;
>    if($error && $error['type'] === E_ERROR){
>        echo 'PHAIL! Oh noes, something went wrong!';
>        // do whatever else you need to do before quitting
>    }
> });
>
> Cheers,
> David
>
> 
> > […]
> wrote:
> > […]
> Consultant
> > […]
> http://thePHP.cc/

---

## #51631 — Martin Scotta — 2011-03-09T14:18:41+00:00

URL: https://externals.io/message/51614#51631 · In reply to: #51630

Fatal error are most dumb feature in the language.
The are lot of "blind" areas where you don't know if you will ever return...

include "file.php";
new  Class();
call_func();

All fatal errors should be changed to "catchable fatal errors" so
applications will be able to recover themselves... and if they don't catch
the error... then die.

it would be nice if all errors could be changed into exceptions.

 Martin Scotta


On Wed, Mar 9, 2011 at 10:56 AM, Hannes Landeholm <landeholm@gmail.com>wrote:

> I second making time limit reached catchable. All non catchable fatal
> errors
> are a problem for me. I need to handle problems gracefully to ensure the
> stability of production systems instead of PHP just killing itself without
> warning. I just reported a similar issue:
> http://bugs.php.net/bug.php?id=54195
>
> A simple way to implement this would be to register a function that would
> be
> called N seconds before the script would timeout.
>
> register_timeout_handler(2, function() { die("PHP timed out."); });
>
> It would be called just as a shutdown function - in fact I'd like to use
> the
> same function as my shutdown function and get the error with
> `error_get_last()`. Of course set_time_limit(0) could be used in this
> function
> to prevent the timeout of the timeout handler. This does not "prevent"
> timeout since set_time_limit could have been called by the script before
> the
> timeout anyway.
>
> On that note I also miss a function which returns the time the script can
> keep running for. If that calculate needs to be calculated to implemented
> to
> implement this, why not make the value available to the PHP script?
>
> ~Hannes
>
> 
>
> > […]

---

## #51632 — David Muir — 2011-03-09T14:27:47+00:00

URL: https://externals.io/message/51614#51632 · In reply to: #51630

Hmm, I think I worded that poorly.
A function registered with register_shutdown_function does execute when
the max_execution_time is exceeded.
What it doesn't let you do is to recover in the same way an error
handler would let you.

David


> I second making time limit reached catchable. All non catchable fatal errors
> are a problem for me. I need to handle problems gracefully to ensure the
> stability of production systems instead of PHP just killing itself without
> warning. I just reported a similar issue:
> http://bugs.php.net/bug.php?id=54195
>
> A simple way to implement this would be to register a function that would be
> called N seconds before the script would timeout.
>
> register_timeout_handler(2, function() { die("PHP timed out."); });
>
> It would be called just as a shutdown function - in fact I'd like to use the
> same function as my shutdown function and get the error with
> `error_get_last()`. Of course set_time_limit(0) could be used in this function
> to prevent the timeout of the timeout handler. This does not "prevent"
> timeout since set_time_limit could have been called by the script before the
> timeout anyway.
>
> On that note I also miss a function which returns the time the script can
> keep running for. If that calculate needs to be calculated to implemented to
> implement this, why not make the value available to the PHP script?
>
> ~Hannes
>
> 
>
> > […]

---

## #51633 — Hannes Landeholm — 2011-03-09T14:27:55+00:00

URL: https://externals.io/message/51614#51633 · In reply to: #51631

I'm personally a fan of errors and well defined return values. Exceptions
doesn't solve any problem unless your problem is that your code is not
enough spaghetti-ish. But I agree with "All fatal errors should be changed
to catchable fatal errors".

~Hannes




> Fatal error are most dumb feature in the language.
> The are lot of "blind" areas where you don't know if you will ever
> return...
>
> include "file.php";
> new  Class();
> call_func();
>
> All fatal errors should be changed to "catchable fatal errors" so
> applications will be able to recover themselves... and if they don't catch
> the error... then die.
>
> it would be nice if all errors could be changed into exceptions.
>
>  Martin Scotta
>
>
>
> On Wed, Mar 9, 2011 at 10:56 AM, Hannes Landeholm <landeholm@gmail.com>wrote:
>
> > […]

---

## #51634 — Hannes Landeholm — 2011-03-09T14:30:14+00:00

URL: https://externals.io/message/51614#51634 · In reply to: #51632

You mean the shutdown function is called and 1 nanosecond later PHP crashes
so you don't have time to do anything?

~Hannes



> Hmm, I think I worded that poorly.
> A function registered with register_shutdown_function does execute when
> the max_execution_time is exceeded.
> What it doesn't let you do is to recover in the same way an error
> handler would let you.
>
> David
>
> 
> > […]
> errors
> > […]
> without
> > […]
> be
> > […]
> the
> > […]
> function
> > […]
> the
> > […]
> to
> > […]

---

## #51635 — Ferenc Kovacs — 2011-03-09T14:39:54+00:00

URL: https://externals.io/message/51614#51635 · In reply to: #51634

no, it only means that you cant return to the original scope and continue
the execution of your script.
as you can't throw exceptions also, because your code is running without a
stack frame.
you can check out the https://github.com/Tyrael/php-error-handler its a
little class which operates with register_shutdown_function to allow
handling non-recoverable errors before halting.
there are too many case in the php src where non-recoverable errors are
triggered for non fatal problems.
that should be changed, so open a bugreport if you think you found one,
where isn't neccessary to halt the execution.

Tyrael

On Wed, Mar 9, 2011 at 3:30 PM, Hannes Landeholm <landeholm@gmail.com>wrote:

> You mean the shutdown function is called and 1 nanosecond later PHP crashes
> so you don't have time to do anything?
>
> ~Hannes
>
> 
>
> > […]
> the
> > […]
> would
> > […]
> use
> > […]
> before
> > […]
> can
> > […]
> implemented
> > […]
> sebastian@php.net>
> > […]

---

## #51636 — Thomas Hruska — 2011-03-09T14:52:31+00:00

URL: https://externals.io/message/51614#51636 · In reply to: #51630

> A simple way to implement this would be to register a function that would be
> called N seconds before the script would timeout.
>
> register_timeout_handler(2, function() { die("PHP timed out."); });
>
> It would be called just as a shutdown function - in fact I'd like to use the
> same function as my shutdown function and get the error with
> `error_get_last()`. Of course set_time_limit(0) could be used in this function
> to prevent the timeout of the timeout handler. This does not "prevent"
> timeout since set_time_limit could have been called by the script before the
> timeout anyway.

I like this.  Although, I'd rather the first parameter were in 
milliseconds instead of seconds.  This would tell PHP 'x' milliseconds 
before script termination to call the specified function.  That function 
would then have the remainder of the time slice to execute cleanup 
routines and send any errors to the user.  This approach also doesn't 
require a whole new configuration option in php.ini.


> On that note I also miss a function which returns the time the script can
> keep running for. If that calculate needs to be calculated to implemented to
> implement this, why not make the value available to the PHP script?

This is already possible to do.  I do this in WebCron by setting a 
variable with the value of `microtime()` at the start of execution and 
figuring out how long the script can actually run for.  Then, I stop 
executing a task if there are less than a few seconds left on the clock 
so that there is ample time to clean up gracefully.  For more information:

http://barebonescms.com/documentation/webcron/

Then I expose a convenience function called WC_GetTimeLeft() to modules 
and tasks that can use it to test to see how much time is left on the 
clock to execute the script.  The approach works quite well.  As an 
example, I use WC_GetTimeLeft() extensively in my WebCron Site Backup 
module that can backup websites of any size over HTTP/HTTPS.

http://barebonescms.com/documentation/webcron_site_backup/

So, while it can and has been done, it does require a little extra work 
at the start of the script and obviously isn't as accurate as a 
dedicated function in PHP itself would be.

-- 
Thomas Hruska
CubicleSoft President

Barebones CMS is a high-performance, open source content management 
system for web developers operating in a team environment.

An open source CubicleSoft initiative.
Your choice of a MIT or LGPL license.

http://barebonescms.com/

---

## #51637 — Hannes Landeholm — 2011-03-09T14:53:06+00:00

URL: https://externals.io/message/51614#51637 · In reply to: #51635

That's not a problem. Timeouts should be non-recoverable IMO as it's a
serious problem and I think most PHP developers would agree with this.
Making errors "recoverable" is difficult to implement, could have
performance penalties and be conceptually wrong when the state is defined as
"never allowed to happen".

What I'm concerned about is that all problems should be able to be handled
gracefully from the register_shutdown_function like showing an informative
page, setting HTTP status, logging the problem, sending an error report,
etc. Not all fatal errors can be caught this way, including script timeout.

~Hannes



> no, it only means that you cant return to the original scope and continue
> the execution of your script.
> as you can't throw exceptions also, because your code is running without a
> stack frame.
> you can check out the https://github.com/Tyrael/php-error-handler its a
> little class which operates with register_shutdown_function to allow
> handling non-recoverable errors before halting.
> there are too many case in the php src where non-recoverable errors are
> triggered for non fatal problems.
> that should be changed, so open a bugreport if you think you found one,
> where isn't neccessary to halt the execution.
>
> Tyrael
>
>
> On Wed, Mar 9, 2011 at 3:30 PM, Hannes Landeholm <landeholm@gmail.com>wrote:
>
> > […]

---

## #51638 — Hannes Landeholm — 2011-03-09T15:03:46+00:00

URL: https://externals.io/message/51614#51638 · In reply to: #51636

Yes, it's possible to measure the "time left" yourself. However
set_time_limit documentation states that not all time are accounted for when
measuring how long the script can run for. If it's a UNIX system and you're
using system operations/database queries etc there will be a difference
between the time you measure the script has run for and the time PHP has
measured.

And this is only a suitable solution in controlled code like when you're
doing something defined in a loop and can measure the time with regular
intervals. I need it for my framework which can contain any kind of logic,
even logic that uses set_time_limit by itself.

~Hannes



> 
>
> > […]
>
> I like this.  Although, I'd rather the first parameter were in milliseconds
> instead of seconds.  This would tell PHP 'x' milliseconds before script
> termination to call the specified function.  That function would then have
> the remainder of the time slice to execute cleanup routines and send any
> errors to the user.  This approach also doesn't require a whole new
> configuration option in php.ini.
>
>
>
>  On that note I also miss a function which returns the time the script can
> > […]
>
> This is already possible to do.  I do this in WebCron by setting a variable
> with the value of `microtime()` at the start of execution and figuring out how
> long the script can actually run for.  Then, I stop executing a task if
> there are less than a few seconds left on the clock so that there is ample
> time to clean up gracefully.  For more information:
>
> http://barebonescms.com/documentation/webcron/
>
> Then I expose a convenience function called WC_GetTimeLeft() to modules and
> tasks that can use it to test to see how much time is left on the clock to
> execute the script.  The approach works quite well.  As an example, I use
> WC_GetTimeLeft() extensively in my WebCron Site Backup module that can
> backup websites of any size over HTTP/HTTPS.
>
> http://barebonescms.com/documentation/webcron_site_backup/
>
> So, while it can and has been done, it does require a little extra work at
> the start of the script and obviously isn't as accurate as a dedicated
> function in PHP itself would be.
>
> --
> Thomas Hruska
> CubicleSoft President
>
> Barebones CMS is a high-performance, open source content management system
> for web developers operating in a team environment.
>
> An open source CubicleSoft initiative.
> Your choice of a MIT or LGPL license.
>
> http://barebonescms.com/

---

## #51640 — Ferenc Kovacs — 2011-03-09T15:12:07+00:00

URL: https://externals.io/message/51614#51640 · In reply to: #51637

FYI you can gracefully handle every error. even the non-recoverable ones.
if you check my library you can test it also, I have an example file for
every non recoverable error (E_PARSE, E_CORE_ERROR, etc.).

from my point of view, every userland error should be catchable from
userland.
the max execution time servers two purpose:
- it saves you from shooting you in the leg (will abort an infinite loop for
example)
- it could be used as a tool by the sysadmin to restrict the cpu usage in a
shared hosting environment.
the ability to execute code via register_shutdown_function after the
"Maximum execution time exceeded" fatal error thrown by the engine makes the
second point void (except if you disable the register_shutdown_function,
which you would do of course in a shared environment).

so I think that it should be only used for the first problem, in which case
it could be catchable IMO, because it doesn't leave the engine in an
unstable state.

Tyrael

On Wed, Mar 9, 2011 at 3:53 PM, Hannes Landeholm <landeholm@gmail.com>wrote:

> That's not a problem. Timeouts should be non-recoverable IMO as it's a
> serious problem and I think most PHP developers would agree with this.
> Making errors "recoverable" is difficult to implement, could have
> performance penalties and be conceptually wrong when the state is defined as
> "never allowed to happen".
>
> What I'm concerned about is that all problems should be able to be handled
> gracefully from the register_shutdown_function like showing an informative
> page, setting HTTP status, logging the problem, sending an error report,
> etc. Not all fatal errors can be caught this way, including script timeout.
>
> ~Hannes
>
>
> 
>
> > […]

---

## #51643 — Hannes Landeholm — 2011-03-09T15:59:02+00:00

URL: https://externals.io/message/51614#51643 · In reply to: #51640

No you can't gracefully handle all fatal errors. The shutdown function will
be called after *some* fatal errors but not all of them. See the bug I
reported here for more information: http://bugs.php.net/bug.php?id=54195

~Hannes



> FYI you can gracefully handle every error. even the non-recoverable ones.
> if you check my library you can test it also, I have an example file for
> every non recoverable error (E_PARSE, E_CORE_ERROR, etc.).
>
> from my point of view, every userland error should be catchable from
> userland.
> the max execution time servers two purpose:
> - it saves you from shooting you in the leg (will abort an infinite loop
> for example)
> - it could be used as a tool by the sysadmin to restrict the cpu usage in a
> shared hosting environment.
> the ability to execute code via register_shutdown_function after the
> "Maximum execution time exceeded" fatal error thrown by the engine makes the
> second point void (except if you disable the register_shutdown_function,
> which you would do of course in a shared environment).
>
> so I think that it should be only used for the first problem, in which case
> it could be catchable IMO, because it doesn't leave the engine in an
> unstable state.
>
> Tyrael
>
> On Wed, Mar 9, 2011 at 3:53 PM, Hannes Landeholm <landeholm@gmail.com>wrote:
>
> > […]

---

## #51644 — Ferenc Kovacs — 2011-03-09T16:01:10+00:00

URL: https://externals.io/message/51614#51644 · In reply to: #51643

tyrael@devel-tyrael:~/c$ php -f fatal.php
PHP Fatal error:  Call to a member function bar() on a non-object in
/home/tyrael/c/fatal.php on line 9
PHP Stack trace:
PHP   1. {main}() /home/tyrael/c/fatal.php:0
Houston we have a problem: Array
(
    [type] => 1
    [message] => Call to a member function bar() on a non-object
    [file] => /home/tyrael/c/fatal.php
    [line] => 9
)

as I mentioned, it works.

Tyrael

On Wed, Mar 9, 2011 at 4:59 PM, Hannes Landeholm <landeholm@gmail.com>wrote:

> No you can't gracefully handle all fatal errors. The shutdown function will
> be called after *some* fatal errors but not all of them. See the bug I
> reported here for more information: http://bugs.php.net/bug.php?id=54195
>
> ~Hannes
>
>
> 
>
> > […]

---

## #51645 — Hannes Landeholm — 2011-03-09T16:13:24+00:00

URL: https://externals.io/message/51614#51645 · In reply to: #51644

Yes.. apparently it works. My mistake. I accidentally tested it in a context
with error suppression enabled.

Apparently there where some other reason for it not being gracefully caught
in production then. Going to have an extra look at it. Closing the bug in
the meantime.

~ Hannes



> tyrael@devel-tyrael:~/c$ php -f fatal.php
> PHP Fatal error:  Call to a member function bar() on a non-object in
> /home/tyrael/c/fatal.php on line 9
> PHP Stack trace:
> PHP   1. {main}() /home/tyrael/c/fatal.php:0
> Houston we have a problem: Array
> (
>     [type] => 1
>     [message] => Call to a member function bar() on a non-object
>     [file] => /home/tyrael/c/fatal.php
>     [line] => 9
> )
>
> as I mentioned, it works.
>
> Tyrael
>
>
> On Wed, Mar 9, 2011 at 4:59 PM, Hannes Landeholm <landeholm@gmail.com>wrote:
>
> > […]
