Call a function before the page is timeout in PHP - php

I have a PHP script that will run for a long time. I have set the execution time limit to 5 minutes by using set_time_limit() function. I would like to ask whether I can set the script to call a function when timeout limit is reached? like the page unload script in JavaScript or viewDidUnload function in NSViewController, in iPhone SDK ?

You can use register_shutdown_function() to register a callback, that is called, when the execution finishes. You should also have a look at connection handling.

You can do it by using register_shutdown_function() But this isn't good practice, remeber that you will catch also fatal error, parse errors etc.

Related

Timeout a PHP function after 5 seconds

I am making an API call to a service and need to timeout the call after 5 seconds and consider it a "fail" then proceed with the code. If it times out I want to save this to a $timeoutResult variable and then pass that all the way back to the javascript (I can do this part).
I'm just not sure how to do a timed function in PHP. I've seen the documentation on set_time_limit(5) but I'm not sure how to do it?
For example:
$response = $api_calls->apiCall($endpoint, $data); If this takes >5 seconds I want it to quit/consider the call a "fail" and then proceed onto my error handling further down the code.
I'm not sure how to stop the execution of THIS function by considering it a fail and proceeding.
Would something like this work?
set_time_limit(5);
$response = $api_calls->apiCall($endpoint, $data);
set_time_limit(0);
This way I set a timeout (which begins when this function inside a function is being called), it tries to execute, and if it finishes it then sets the time out back to infinity?
My cURL settings in apiCall() has a standard timeout of 10 seconds, but for this one particular call I need it to timeout after 5 seconds and then display an error if it times out.
You've not shown the code which actually makes the api call!
While its possible to to set a watchdog timer (SIGALRM) this is only an option on a POSIX system and only when running in the CLI sapi.
You mention that the code uses curl. This has lots of options for controlling timeouts - _CONNECTTIMEOUT[_MS], _LOW_SPED_LIMIT, _LOW_SPEED_TIME and _TIMEOUT[_MS] all documented in the manual.
I added an additional parameter to my apiCall() function which accepts an array.
I then looped through this array using
if(isset($extra_curl_options) && $extra_curl_options.length > 0){
foreach($extra_curl_options AS $k => $v) {
$http_request->setOption(constant($k), $v);
}
}
This will allow me to pass in multiple curl options to the apiCall for the future.

Setting a socket timeout in PHP

I'm writing a script in PHP that uses PEAR's Net_Socket. I want to query servers to see if they have any current information. I send in a command and then use $socket->readLine() to get the response. However, if there is not a response, my script just waits forever. Is there anyway to either tell the socket to close after a specific amount of time or to wrap the whole function in a timeout, that if it hasn't returned by the timeout, it halts its execution?
On the same page you linked is a link to setTimeout(): https://pear.php.net/manual/en/package.networking.net-socket.settimeout.php
Trying calling $socket->setTimeout( $seconds, $milliseconds ); just before calling readLine()

Can I set a time limit for a code block?

Is it possible to start a block of code (maybe just call a function) and if it doesn't execute within a certain time skip it.
//give this function 10 seconds to execute
$value = mega_function();// could take anything from 1-1000 seconds
//if 10 seconds have passed and the value is still not set, abort it and set $value = false;
No. You would have to either
Call the function inside an external file using curl or file_get_contents() - you can set a timeout there
Keep track of the time inside mega_function() and return() if necessary.
What does mega_function() do?
Try looking into threads, but it might be awkward to do something like this in PHP:)
Look at http://php.net/manual/en/function.pcntl-fork.php and all pnctl related functions for creating childs, sending signals between them, waiting for child to finish or killing threads.

Can a PHP script abort itself or detect abortion?

PHP scripts can continue executing after the HTTP page request, so how do I finally stop it executing when I'm done with it?
Also, is there an event to detect when the OS is going to forcibly abort the script? or how do I keep an internal timer to predict max_execution_time?
exit()/die() will stop a php script.
To know when to stop the script, you'll just have to use microtime as a timer and save as a constant (or fetch from the php.ini file) the maximum execution time.
You can also look at the Connection handling information. Where we have things like connection_aborted() and connection_status()
But what is the problem you're trying to solve?
You can use register_shutdown_function to register a function to be called at the end of script execution. You can use this to detect when the script has been terminated and perform a certain set of actions.
To have a callback at the moment your request is shutting down, use register_shutdown_function( myfunction ).
Much like most POSIX environments, PHP also supports signal handlers. You can register your own handler for the SIGTERM event.
function my_abort_handler( $signo ) {
echo "Aborted";
}
pcntl_signal( SIGTERM, "my_abort_handler" );
You may want to take a look at pcntl-alarm which allows a script to send a signal to itself. Also contains some sample on how to catch the kill signals which can be send by the OS. And die() indeed.
Well, you could start a $start=microtime(true) which will return a timestamp. Then you can just keep checking microtime(true) and subtract that from your start time to get the number of seconds since executing.
But no, you can't "catch" the script as its terminating for the reason of the request being too long. You could try to do some last minute stuff in the shutdown handler, but I'm not sure if PHP will honor that.
It looks like there used to be a function that does exactly what you want, connection_timeout(), but it was deprecated and removed. Don't know if there is any kind of replacement for this, however.

Fatal error php

Is there a way to make the code continue (not exit) when you get a fatal error in PHP?
For example I get a timeout fatal error and I want whenever it happens to skip this task and the continue with others.
In this case the script exits.
There is a hack using output buffering that will let you log certain fatal errors, but there's no way to continue a script after a fatal error occurs - that's what makes it fatal!
If your script is timing out you can use set_time_limit() to give it more time to execute.
"Fatal Error", as it's name indicates, is Fatal : it stop the execution of the script / program.
If you are using PHP to generate web pages and get a Fatal error related to max_execution_time which, by defaults, equals 30 seconds, you are certainly doing something that really takes too mych time : users won't probably wait for so long to get the page.
If you are using PHP to do some heavy calculations, not in a webpage (but via CLI, or a cron, or stuff like that), you can set another (greater) value for max_execution_time.
You have two ways of doing that :
First is to modify php.ini, to set this value (it's already in the file ; just edit the property's value). Problem is it'll modify it also for the web server, which is bad (this is a security measure, after all).
Better way is to create a copy of php.ini, called, for instance, phpcli.ini, and modify this file. Then, use it when invoking php :
php -c phpcli.ini myscript.php
This'll work great if you have many properties you need to configure for CLI execution. (Like memory_limit, which often has to be set to a higher value for long-running batches)
The other way is to define a different value for max_execution_time when you invoke php, like this :
php -d max_execution_time=60 myscript.php
This is great if you launch this via the crontab, for instance.
It depends on the exact error type. You can catch errors by creating your own error handler. See the documentation on set_error_handler(), but not all types of errors can be caught. Look at the timeout error you get and see what type it is. If it is one of E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR or E_COMPILE_WARNING then you cannot catch it with an error handler. If it another type then you can. Catch it with the error handler and simply return.
If you have a suitable PHP version (PHP>=5.2 for error_get_last) you can try the technique described here which uses register_shutdown_function and error_get_last.
This won't allow you to "continue" when you get a fatal error, but it at least allows you to log the error (and perhaps send a warning email) before displaying a custom error page to the user.
It works something like this:
function fatalErrorHandler()
{
$lastError = error_get_last();
if (isset($lastError["type"]) && $lastError["type"]==E_ERROR) {
// do something with the fatal error
}
}
...
register_shutdown_function('fatalErrorHandler');
A few points:
you can use ob_clean() to remove any content that was generated prior to the fatal error.
it's a really bad idea to do anything to intensive in the shutdown handler, this technique is about graceful failure rather than recovery.
whatever you do, don't try to log the error to a database ... what if it was a database timeout that caused the fatal error?
for some reason I've had problems getting this technique to work 100% of the time when developing in Windows using WAMP.
The most simple answer I can give you is this function: http://php.net/manual/en/function.pcntl-fork.php
In more detail, what you can do is:
Fork the part of the process you think might or might not cause a fatal error (i.e. the bulk of your code)
The script that forks the process should be a very simple script.
For example this is something that I would do with a job queue that I have:
<?php
// ... load stuff regarding the job queue
while ($job = $queue->getJob()) {
$pid = pcntl_fork();
switch ($pid) {
case -1:
echo "Fork failed";
break;
case 0:
// do your stuff here
echo "Child finished working";
break;
default:
echo "Waiting for child...";
pcntl_wait($status);
// check the status using other pcntl* functions if you want
break;
}
}
Is there a way then to limit the execution time of an function but not all script?
For example
function blabla()
{
return "yes";
}
to make it so that if it is not executed in 25 seconds to return no;

Categories