2024年PHP开发者大会日本站

set_time_limit

(PHP 4, PHP 5, PHP 7, PHP 8)

set_time_limit限制最大执行时间

描述

set_time_limit(int $seconds): bool

设置脚本允许运行的秒数。如果达到此限制,脚本将返回致命错误。默认限制为30秒,或者如果存在,则为php.ini中定义的max_execution_time值。

调用set_time_limit()时,将从零开始重新启动超时计数器。换句话说,如果超时时间为默认的30秒,并且在脚本执行25秒后进行了set_time_limit(20)之类的调用,则脚本将在超时之前总共运行45秒。

参数

seconds

最大执行时间(以秒为单位)。如果设置为零,则不设置时间限制。

返回值

成功时返回true,失败时返回false

注释

注意:

set_time_limit()函数和配置指令max_execution_time仅影响脚本本身的执行时间。在脚本执行之外发生的任何活动(例如使用system()的系统调用、流操作、数据库查询等)花费的时间,在确定脚本已运行的最大时间时不包括在内。在Windows上并非如此,在Windows上测量的 时间是实际时间。

添加注释

用户贡献注释 16条注释

mba_aslam at yahoo dot com
17年前
设置set_time_limit()时,sleep()的持续时间将不被计入执行时间。以下是说明

<?php

set_time_limit
(20);

while (
$i<=10)
{
echo
"i=$i ";
sleep(100);
$i++;
}

?>

输出
i=0 i=1 i=2 i=3 i=4 i=5 i=6 i=7 i=8 i=9 i=10
kexianbin at diyism dot com
10年前
set_time_limit(...)和ini_set('max_execution_time',...);都不会计算sleep,file_get_contents,shell_exec,mysql_query等的时间消耗,所以我构建了这个函数my_background_exec(),在后台/分离进程中运行静态方法/函数,超时则将其杀死

my_exec.php
<?php
function my_background_exec($function_name, $params, $str_requires, $timeout=600)
{
$map=array('"'=>'\"', '$'=>'\$', '`'=>'\`', '\\'=>'\\\\', '!'=>'\!');
$str_requires=strtr($str_requires, $map);
$path_run=dirname($_SERVER['SCRIPT_FILENAME']);
$my_target_exec="/usr/bin/php -r \"chdir('{$path_run}');{$str_requires} \\\$params=json_decode(file_get_contents('php://stdin'),true);call_user_func_array('{$function_name}', \\\$params);\"";
$my_target_exec=strtr(strtr($my_target_exec, $map), $map);
$my_background_exec="(/usr/bin/php -r \"chdir('{$path_run}');{$str_requires} my_timeout_exec(\\\"{$my_target_exec}\\\", file_get_contents('php://stdin'), {$timeout});\" <&3 &) 3<&0";//php 默认使用 "sh",而 "sh" 不支持 "<&0"
my_timeout_exec($my_background_exec, json_encode($params), 2);
}

function
my_timeout_exec($cmd, $stdin='', $timeout)
{
$start=time();
$stdout='';
$stderr='';
//file_put_contents('debug.txt', time().':cmd:'.$cmd."\n", FILE_APPEND);
//file_put_contents('debug.txt', time().':stdin:'.$stdin."\n", FILE_APPEND);

$process=proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes);
if (!
is_resource($process))
{return array(
'return'=>'1', 'stdout'=>$stdout, 'stderr'=>$stderr);
}
$status=proc_get_status($process);
posix_setpgid($status['pid'], $status['pid']); //将进程组ID与父进程的进程组ID分离

stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
fwrite($pipes[0], $stdin);
fclose($pipes[0]);

while (
1)
{
$stdout.=stream_get_contents($pipes[1]);
$stderr.=stream_get_contents($pipes[2]);

if (
time()-$start>$timeout)
{
//proc_terminate($process, 9); //仅终止子进程,不会终止子子进程
posix_kill(-$status['pid'], 9); //向组内所有进程发送SIGKILL信号(负数表示进程组ID,所有子进程共享顶级进程组,除了嵌套的my_timeout_exec)
//file_put_contents('debug.txt', time().":kill group {$status['pid']}\n", FILE_APPEND);
return array('return'=>'1', 'stdout'=>$stdout, 'stderr'=>$stderr);
}

$status=proc_get_status($process);
//file_put_contents('debug.txt', time().':status:'.var_export($status, true)."\n";
if (!$status['running'])
{
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
return
$status['exitcode'];
}

usleep(100000);
}
}
?>

a_class.php
<?php
class A
{
static function
jack($a, $b)
{
sleep(4);
file_put_contents('debug.txt', time().":A::jack:".$a.' '.$b."\n", FILE_APPEND);
sleep(15);
}
}
?>

test.php
<?php
require 'my_exec.php';

my_background_exec('A::jack', array('hello', 'jack'), 'require "my_exec.php";require "a_class.php";', 8);
?>
jonathon dot keogh at gmail dot com
16年前
你可以使用 `set_time_limit(0);` 使脚本无限运行——但是这不推荐,你的Web服务器可能会因为HTTP超时(通常约5分钟)而中断你。

你应该查看你的Web服务器指南以获取更多关于HTTP超时的信息。

Jonathon
cweiske at cweiske dot de
16年前
要获取当前使用的运行时间,请使用 `getrusage()`
eric pecoraro at shepard com
19年前
我在用户提示长时间运行的后台操作的应用程序中遇到了脚本超时问题。我编写了这个 cURL/CLI 后台脚本,它在从HTTP发出请求时解决了这个问题。

<?php

/* 后台CLI 1.0

eric pecoraro _at_ shepard dot com - 2005-06-02
使用风险自负。不提供任何明示或暗示的担保。

将此文件包含在任何脚本的顶部,以便在后台运行它,
且无时间限制 ... 例如:include('background_cli.php');

调用此文件的脚本不应向浏览器返回输出。
*/
# 需求 - cURL 和 CLI
if ( !function_exists('curl_setopt') OR !function_exists('curl_setopt') ) {
echo
'需要安装 cURL 和 CLI。' ; exit ;
}

# 构建路径
$script = array_pop(explode('/',$SCRIPT_NAME)) ;
$script_dir = substr($SCRIPT_NAME,0,strlen($SCRIPT_NAME)-strlen($script)) ;
$scriptURL = 'http://'. $HTTP_HOST . $script_dir . "$script" ;
$curlURL = 'http://'. $HTTP_HOST . $script_dir . "$script?runscript=curl" ;

# 指示脚本由 CLI 调用
if ( php_sapi_name() == 'cli' ) {
$CLI = true ;
}

# 如果脚本由 cURL_prompt() 调用,则执行的操作
if ( $runscript == 'curl' ) {
$cmd = "/usr/local/bin/php ".$PATH_TRANSLATED ; // 要运行的脚本的服务器位置
exec($cmd) ;
exit;
}

# 用户界面
// 提交后用户的答案。
if ( $post ) {
cURL_prompt($curlURL) ;
echo
'<div style="margin:25px;"><title>后台CLI</title>';
echo
'好的。如果一切顺利,<b>'.$script.'</b> 正在后台努力工作,没有' ;
echo
'超时限制。 <br><br><form action='.$scriptURL.' method=GET>' ;
echo
'<input type=submit value=" 重置后台 CLI "></form></div>' ;
exit ;
}
// 开始屏幕。
if ( !$CLI AND !$runscript ) {
echo
'<title>后台CLI</title><div style="margin:25px;">' ;
echo
'<form action='.$scriptURL.' method=POST>' ;
echo
'点击从 PHP CLI 命令行在后台运行 <b>'.$script.'</b>。<br><br>' ;
echo
'<input type=hidden value=1 name=post>' ;
echo
'<input type=submit value=" 在后台运行 "></form></div>' ;
exit ;
}

# cURL URL 提示函数
function cURL_prompt($url_path) {
ob_start(); // 开始输出缓冲区
$c=curl_init($url_path);
curl_setopt($c, CURLOPT_TIMEOUT, 2); // 2 秒后断开连接
curl_exec($c);
curl_close($c);
ob_end_clean(); // 丢弃输出缓冲区
}
?>
robertbrogers at gmail dot com
10年前
文档说明
调用时,set_time_limit() 会将超时计数器从零重新开始。换句话说,如果超时时间是默认的 30 秒,并且在脚本执行 25 秒后调用了 set_time_limit(20),则脚本将在超时前总共运行 45 秒。

如果我有一个长时间运行的脚本,并且想要一个精确的超时限制,我会尽可能将其设置在第一行附近。
php at mightycpa.com
21 年前
您可能还需要查看 Apache 的超时设置(对我来说是 Win32 版本),我在 php.ini 中更改了最大执行时间值,但仍然被 httpd.conf 文件中的 Apache 超时值停止。
AtlantisNet
16年前
在 IIS 中,还有一个全局超时设置,它将覆盖任何 PHP 设置。您可以按照以下说明更改此超时设置

http://www.iisadmin.co.uk/?p=7
f.nakamura
9 年前
set_tme_limit 重置执行时间计数。

测试代码1
<?php
echo '<html><body>';
set_time_limit(1);
$i = 0;
while(++
$i < 100000001){
if(
$i % 100000 == 0){
echo
$i / 100000, "<br/>\n";
}
}
echo
"done.<br/>\n";

// 不会输出 'done.'。
?>

测试代码2
<?php
echo '<html><body>';
set_time_limit(1);
$i = 0;
while(++
$i < 100000001){
if(
$i % 100000 == 0){
set_time_limit(1);
echo
$i / 100000, "<br/>\n";
}
}
echo
"done.<br/>\n";

// 会输出 'done.'
?>
php at stock-consulting dot com
17年前
要查找当前设置的超时限制,请使用

<?php
ini_get
('max_execution_time');
?>

如果之前在脚本中调用过 set_time_limit,则结果将是传递给 set_time_limit 的值(而不是像函数名“ini_get”似乎表明的那样,来自 php.ini 文件的值)。
rycardo74 at gmail dot com
19年前
这可以很好地工作,实现了HTML流式传输和时间限制的突破。

<?php
header
('Content-type: text/plain');
echo
date("H:m:s"), "\n";
set_time_limit(30);
for (
$i = 0; $i < 1000; $i++)
{

echo
date("H:m:s"),"\n";
for (
$r = 0; $r < 100000; $r++){
$X.= tan(M_LNPI+log(ceil( date("s")*M_PI*M_LNPI+100)));
}
ob_flush();
flush();

}
echo
"work! $x";
?>
konrads dot smelkovs at gmail dot com
18 年前
如果您正在从数据库流式传输大量数据,则这也会计入最大执行时间。
rsallo at gna dot NOSPAM dot es
21 年前
当您使用 IIS 时,PHP 超时只有在它低于 IIS 定义的脚本超时时才有效。

IIS 5 的默认超时时间为 300 秒。如果您需要更长的超时时间,则还必须更改 IIS 属性。否则,您的服务器将在 PHP 脚本达到其自身的超时时间之前停止它。
ratty at brohoof dot com
13 年前
我希望早点发现的一件事是,如果您使用的是 php-cli 并确实需要限制执行时间,并且如果您在 *nix 系统中,您可以使用 coreutils 中的“timeout”。
例如

timeout 5 /usr/bin/php -q /path/to/script

如果它花费的时间超过 5 秒,它将终止脚本。
我编写了一些快速 PHP 脚本,例如与 cacti 一起使用。
匿名用户
5 年前
如果您想检查剩余时间,这应该有效(至少在 Windows 上有效,在非 Windows 平台上,我不确定)

$seconds_remaining_until_termination = ini_get('max_execution_time') === "0" ? null : ((int)ini_get('max_execution_time'))-(microtime(true)-$_SERVER['REQUEST_TIME_FLOAT']);

此代码计算脚本因时间限制终止前剩余的秒数。(在 Windows 7 X64 SP1,PHP 7.3.7 环境下测试) - 如果没有时间限制,则返回 null。
Daan
3年前
如果您想计算脚本的实际运行时间(包括所有外部数据库/HTTP调用等),在 Unix 系统中(Windows 系统中这是默认行为),您可以使用以下函数:

<?php

$timeoutInSeconds
= 3;

// 这将确保始终异步调用
pcntl_async_signals(1);

// 第二个参数是任何可调用函数 (https://php.net/manual/en/language.types.callable.php)
pcntl_signal(SIGALRM, function() {
exit(
'Stop it!');
});
pcntl_alarm($timeoutInSeconds);

?>
To Top