How does PHP max_execution_time work?
The rules on max_execution_time
are relatively simple.
Execution time starts to count when the file is interpreted. Time needed before to prepare the request, prepare uploaded files, the web server doing its thing etc. does not count towards the execution time.
The execution time is the total time the script runs, including database queries, regardless whether it's running in loops or not. So in the first and second case, the script will terminate with a timeout error because that's the defined behaviour of
max_execution_time
.External system calls using
exec()
and such do not count towards the execution time except on Windows. (Source) That means that you could run a external program that takes longer thanmax_execution_time
.When called from the command line,
max_execution_time
defaults to0
. (Source) So in the third case, your script should run without errors.Execution time and memory usage have nothing to do with each other. A script can run for hours without reaching the memory limit. If it does, then often due to a loop where variables are not unset, and previously reserved memory not freed properly.
Does PHP max_execution time resets on each function call?
The max_execution_time
is counted from request start to end. It does not reset when calling a new function.
However, reading the documentation over at https://www.php.net/manual/en/info.configuration.php#ini.max-execution-time
will tell you
So I guess your calls out to the mailing service don't count towards the total execution time, hence your script can run for 7-8 minutes before finally hitting the PHP runtime limitation.The maximum execution time is not affected by system calls, stream operations etc. Please see the set_time_limit() function for more details.
So, to circumwent your problem with the script running into timeouts when sending emails,
you could either increase the max_execution_time
if you have access to the php.ini
file or if your PHP Configuration allows ini_set
, you can increase the limit manually for this specific script.
Maybe you could even use set_time_limit
to increase your maximum runtime every time you've successfully sent out one email.
Another, more complex but also more robust, solution would be to implement some kind of email queue, which is then perpetually processed by a cli script via cron.
This way, you don't have to worry about exceeding the script runtime.
You could put all information about the mails you need to send into a file, or database table, and your cron script could read those jobs and execute them.
What does setting max_execution_time to -1 do?
It sets the maximum execution time for a script to 2**32-1 (or perhaps 2**64-1) seconds, which is a reasonable approximation of "forever". Note that the actual value to make a script run forever is 0.
Tracking the script execution time in PHP
On unixoid systems (and in php 7+ on Windows as well), you can use getrusage, like:
// Script start
$rustart = getrusage();
// Code ...
// Script end
function rutime($ru, $rus, $index) {
return ($ru["ru_$index.tv_sec"]*1000 + intval($ru["ru_$index.tv_usec"]/1000))
- ($rus["ru_$index.tv_sec"]*1000 + intval($rus["ru_$index.tv_usec"]/1000));
}
$ru = getrusage();
echo "This process used " . rutime($ru, $rustart, "utime") .
" ms for its computations\n";
echo "It spent " . rutime($ru, $rustart, "stime") .
" ms in system calls\n";
Note that you don't need to calculate a difference if you are spawning a php instance for every test. Real max_execution_time for PHP on linux
This is quite a tricky advice, but it will definitely do what you want, if you are willing to modify and recompile PHP.
Take a look at the PHP source code at https://github.com/php/php-src/blob/master/Zend/zend_execute_API.c (the file is Zend/zend_execute_API.c
), at function zend_set_timeout
. This is the function that implements time limit. Here's how it works on different platforms:
on Windows, create a new thread, start a timer on it, and when it finishes, set a global variable called
timed_out
to 1, the PHP execution core checks this variable for every instruction, then exits (very simplified)on Cygwin, use itimer with ITIMER_REAL, which measures real time, including any sleep, wait, whatever, then raise a signal that will interrupt any processing and stop processing
on other unix systems, use itimer with ITIMER_PROF, which only measures CPU time spent by the current process (but both in user-mode and kernel-mode). This means waiting for other processes (like MySQL) doesn't count into this.
# ifdef __CYGWIN__
into# if 1
so that you set both ITIMER_REAL and the signal that PHP waits for to SIGALRM.Anyway this whole idea is untested (I use it for some very specific system, where ITIMER_PROF is broken, and it seems to work), unsupported, etc. Use it at your own risk. It may work with PHP itself, but it could break other modules, in PHP and in Apache, if they for whatever reason, use the SIGALRM signal or other timer.
Related Topics
Shortcodes Inside a Shortcode - Wordpress
Checking If String Contains "Http://"
Base64 Over Http Post Losing Data (Objective-C)
How to Use Xpath and Dom to Replace a Node/Element in PHP
Converting Between Timezones in PHP
Efficient Reloading Data/Pushing Data from Server to Client
Running PHP 5.4 Built-In Web Server Outside Localhost
PHP Uploading Files - Image Only Checking
How to Echo a Custom Object in PHP
Why Do PHP Array Examples Leave a Trailing Comma
How to Assign PHP Array Values to JavaScript Array
PHP MySQL Group by to Get Latest Record, Not First Record
Looping Through a Simplexml Object, or Turning the Whole Thing into an Array
How to Auto-Resize a Div with CSS While Keeping Aspect Ratio
Setting Max_Input_Vars PHP.Ini Directive Using Ini_Set
Laravel 4 - Including a "Partial" View Within a View (Without Using Blade Template)