我正在尝试在普通的PHP apache脚本(而不是CLI)中使用PHP的set_time_limit()来限制其最大运行时间。它没有对系统调用或类似的东西做任何事情,我们没有使用安全模式(我们是所有者,而不是服务器的管理员)。这是Linux(Ubuntu)上的PHP 5.2.4。
简单的测试用例:
ini_set('max_execution_time', 1);
set_time_limit(1);
$i=0;
while ($i++<100000000000) {} // or anything other arbitrary that takes time
die('Done');
预期结果:与超出脚本执行时间相关的内容
实际结果:已完成。
我做错了吗? (顺便说一下,是的,脚本确实需要并且可以运行太长时间并且需要中止,遗憾的是这不是可以避免的。这不是重点。)
答案 0 :(得分:3)
从手册中引用:
注意:
set_time_limit()函数和 配置指令 max_execution_time只影响 脚本本身的执行时间。 花在活动上的任何时间 发生在执行之外 脚本如系统调用使用 system(),流操作,数据库 查询等不包括在内 确定最大时间 脚本一直在运行。这不是 在测量的Windows上是真的 时间是真实的。
sleep()是那些不影响脚本运行时间的函数之一
请参阅MPHH对手册
的sleep()页面的评论注意:set_time_limit()函数 和配置指令 max_execution_time只影响 脚本本身的执行时间。 花在活动上的任何时间 发生在执行之外 脚本如系统调用使用 system(),sleep()函数, 不包括数据库查询等 在确定最大时间时 该脚本一直在运行。
答案 1 :(得分:1)
在某些系统上,出于安全性和资源共享的原因,禁用了ini_set和类似的功能。请咨询您的管理员,了解是否存在此类限制。
答案 2 :(得分:1)
这是因为时间限制忽略了函数sleep,它会在睡眠激活时停止计时,并在停用时再次开始计数。
答案 3 :(得分:1)
尝试让你的脚本真正做一些事情,睡眠时间不计入执行时间,因为当脚本处于休眠状态时它不会执行。
编辑:查看此错误报告http://bugs.php.net/37306最后一条评论是修复了“CVS HEAD,PHP_5_2和PHP_5_1”。所以也许你的PHP版本有这个bug。也许您可以尝试更改max_input_time
。
答案 4 :(得分:1)
max_execution_time(...)和ini_set(&#39; max_execution_time&#39;,...)都不会计算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 by default use "sh", and "sh" don't support "<&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']); //seperate pgid(process group id) from parent's pgid
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); //only terminate subprocess, won't terminate sub-subprocess
posix_kill(-$status['pid'], 9); //sends SIGKILL to all processes inside group(negative means GPID, all subprocesses share the top process group, except nested 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);
}
}
?>
test.php的:
<?php
my_background_exec('A::jack', array('hello ', 'jack'), 'require "my_exec.php";require "a_class.php";', 8);
?>
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);
}
}
?>
答案 5 :(得分:0)
通过检查php.ini中的disable_functions标志来检查你的ini_set是否有效。如果没有禁用,请在你的ini_set('max_execution_time',1)之后立即回复phpinfo();以上。如果在本地列下更改了值,那么您知道ini_set有效。否则,您的脚本没有设置任何最长执行时间。