我一直在摆弄我正在开发的一个系统,并设法使它导致以下情况:
致命错误:Maximum execution time of 30 seconds exceeded
它发生在我做一些不现实的事情时,但它可能发生在用户身上。
有没有人知道,如果有一种方法来捕获这个异常?我四处阅读了一下,但似乎每个人都建议提高允许的时间。
如何尝试作为PHP文档(嗯…至少有一个读者)说:
<?php
function shutdown()
{
$a = error_get_last();
if ($a == null) {echo "No errors";}
else {print_r($a);}
}
register_shutdown_function('shutdown');
ini_set('max_execution_time', 1);
sleep(3);
?>
请看以下链接:
- http://www.php.net/manual/en/function.set-error-handler.php # 106061
- http://www.php.net/manual/en/function.register-shutdown-function.php
您唯一的选择是增加脚本的允许执行时间(将其设置为0使其无限,但不建议这样做)或生成一个新线程并希望最好的
不可捕获的原因是它没有真正被抛出。实际上没有任何一行代码触发错误,而是PHP说,"不,对不起,这太长了。"现在该关闭了。"这是有道理的。想象一下,如果一个脚本的最大执行时间为30秒,那么它捕获这个错误并花费另外30秒的时间……在一个设计糟糕的程序中,这为开发提供了一些相当恶劣的机会。至少,它将为DOS攻击创造机会。
这不是异常,这是一个错误。异常和错误之间有重要的区别,首先,错误不能用try/catch语义捕获。
PHP脚本是围绕短执行时间的范例构建的,因此PHP在默认情况下配置为假设如果脚本运行超过30秒,它必须被捕获在一个无限循环中,因此应该终止。这是为了防止错误的PHP脚本导致拒绝服务,无论是意外的还是恶意的。
然而,脚本有时确实需要比默认分配的运行时间更多的时间。
您可以尝试更改最大执行时间,通过使用 set_time_limit()
或通过更改php.ini
文件中的 max_execution_time
的值来提高限制。您也可以通过将执行时间设置为0来完全删除该限制,但不建议这样做。
set_time_limit()
可能被disable_functions
等机制禁用,因此您可能无法使用它,同样您可能无法访问php.ini
。如果这两种情况都存在,那么你应该联系你的房东寻求帮助。
max_execution_time
限制。EDIT TO ADD: PHP 7的错误处理进行了重大修改。我认为错误和异常现在都是Throwable的子类。这可能使上述内容不再适用于PHP7+,尽管我现在必须更仔细地研究错误处理的具体工作方式才能确定。
是的,我测试了TheJanOnline的解决方案。sleep()不计入php的执行时间,所以下面是带有无限循环的工作版本:
<?php
function shutdown()
{
$a=error_get_last();
if($a==null)
echo "No errors";
else
print_r($a);
}
register_shutdown_function('shutdown');
ini_set('max_execution_time',1 );
while(1) {/*nothing*/}
// will die after 1 sec and print error
?>
你对此无能为力。但是你可以使用register_shutdown_function
实现优雅关机<?php
ini_set('display_errors', '0');
ini_set("max_execution_time",15 ); //you can use this if you know your script should not take longer than 15 seconds to finish
register_shutdown_function('shutdown');
function shutdown()
{
$error = error_get_last();
if ($error['type'] === E_ERROR) {
//do your shutdown stuff here
//be care full do not call any other function from within shutdown function
//as php may not wait until that function finishes
//its a strange behavior. During testing I realized that if function is called
//from here that function may or may not finish and code below that function
//call may or may not get executed. every time I had a different result.
// e.g.
other_function();
//code below this function may not get executed
}
}
while(true)
{
}
function other_function()
{
//code in this function may not get executed if this function
//called from shutdown function
}
?>
有一个小棘手的方法来处理"致命错误:最大执行时间超过30秒"作为例外在某些情况下:
function time_sublimit($k = 0.8) {
$limit = ini_get('max_execution_time'); // changes even when you set_time_limit()
$sub_limit = round($limit * $k);
if($sub_limit === 0) {
$sub_limit = INF;
}
return $sub_limit;
}
在你的代码中,你必须测量执行时间,并在超时之前抛出异常,致命错误可能被触发。$k = 0.8是允许执行时间的80%,所以你有20%的时间来处理异常。
try{
$t1 = time(); // start to mesure time.
while (true) { // put your long-time loop condition here
time_spent = time() - $t1;
if(time_spent >= time_sublimit()) {
throw new Exception('Time sublimit reached');
}
// do work here
}
} catch(Exception $e) {
// catch exception here
}
我根据@pinkal-vansia给出的答案想出了这个。所以我不是在说一个原创的答案,而是一个有实际应用的答案。我需要一种方法让页面在超时时自行刷新。因为我已经观察了足够的超时我的cURL脚本知道代码是工作的,但有时无论出于什么原因,它无法连接到远程服务器,或读取所提供的html完全,并在刷新问题就消失了,我可以用脚本刷新自己"治愈"一个最大的执行超时错误。
<?php //script name: scrape_script.php
ini_set('max_execution_time', 300);
register_shutdown_function('shutdown');
function shutdown()
{
?><meta http-equiv="refresh" content="0; url=scrape_script.php"><?php
// just do a meta refresh. Haven't tested with header location, but
// this works fine.
}
仅供参考,300秒对于我正在运行的抓取脚本来说并不太长,它只需要比这少一点,就可以从我正在抓取的各种页面中提取数据。有时由于连接不规范,它只超过几秒钟。知道有时失败的是连接时间,而不是脚本处理,所以最好不要增加超时,而只是自动刷新页面并再次尝试。
我遇到过一个类似的问题,我是这样解决的:
<?php
function shutdown() {
if (!is_null($error = error_get_last())) {
if (strpos($error['message'], 'Maximum execution time') === false) {
echo 'Other error: ' . print_r($error, true);
} else {
echo "Timeout!'n";
}
}
}
ini_set('display_errors', 0);
register_shutdown_function('shutdown');
set_time_limit(1);
echo "Starting...'n";
$i = 0;
while (++$i < 100000001) {
if ($i % 100000 == 0) {
echo ($i / 100000), "'n";
}
}
echo "done.'n";
?>
这个脚本将在最后打印Timeout!
。
你可以将$i = 0;
行修改为$i = 1 / 0;
,它将打印:
Other error: Array
(
[type] => 2
[message] => Division by zero
[file] => /home/user/test.php
[line] => 17
)
引用:
- PHP: register_shutdown_function - ManualPHP: set_time_limit - ManualPHP: error_get_last - Manual