如何捕获致命错误:PHP 中超过了 30 秒的最大执行时间

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6861033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 01:29:20  来源:igfitidea点击:

How to catch the fatal error: Maximum execution time of 30 seconds exceeded in PHP

phptry-catchfatal-error

提问by ingh.am

I've been playing around with a system I'm developing and managed to get it to cause this:

我一直在玩我正在开发的系统并设法让它导致这个:

Fatal error: Maximum execution time of 30 seconds exceeded

致命错误:超过了最长 30 秒的执行时间

It happened when I was doing something unrealistic, but nevertheless it could happen with a user.

它发生在我做一些不切实际的事情时,但它可能发生在用户身上。

Does anyone know if there is a way to catch this exception? I've read around but everyone seems to suggest upping the time allowed.

有谁知道是否有办法捕获此异常?我已经阅读过,但似乎每个人都建议增加允许的时间。

采纳答案by cwallenpoole

Your only options are to increase the allowed execution time (setting it to 0 makes it infinite, but that is not recommended) of the script or spawn a new thread and hope for the best.

您唯一的选择是增加脚本的允许执行时间(将其设置为 0 使其无限,但不推荐)或产生一个新线程并希望最好。

The reason that this isn't catchable is that it isn't really thrown. No one line of the code actually triggered the error, rather PHP said, "Nope, sorry, this is too long. Time to shut down now." And that makes sense. Imagine having a script with a max execution time of 30 seconds catching that error and taking another 30 seconds... in a poorly designed program, that opens up some rather nasty opportunities to exploit. At a minimum, it will create opportunities for DOSattacks.

这不能被捕获的原因是它并没有真正抛出。没有一行代码实际上触发了错误,而是 PHP 说,“不,抱歉,这太长了。现在是时候关闭了。” 这是有道理的。想象一下,有一个最长执行时间为 30 秒的脚本捕获该错误,然后再花费 30 秒...... 至少,它会为DOS攻击创造机会。

回答by TheJanOnline

How about trying as PHP documentation (well... at least one of its readers) say:

尝试作为 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);
?>

Have a look at the following links:

看看以下链接:

  1. http://www.php.net/manual/en/function.set-error-handler.php#106061
  2. http://www.php.net/manual/en/function.register-shutdown-function.php
  1. http://www.php.net/manual/en/function.set-error-handler.php#106061
  2. http://www.php.net/manual/en/function.register-shutdown-function.php

回答by GordonM

This isn't an exception, it's an error. There are important differences between exceptions and errors, first and foremost errors can't be caught with try/catch semantics.

这不是例外,而是错误。异常和错误之间有重要的区别,首先是错误不能用 try/catch 语义捕获。

PHP scripts are built around a paradigm of short execution times, so PHP is configured by default to assume that if a script has been running for longer than 30 seconds it must be caught in an infinite loop and therefore should be terminated. This is to prevent an errant PHP script causing a denial of service, either by accident or by malicious intent.

PHP 脚本是围绕短执行时间的范例构建的,因此 PHP 被默认配置为假设如果脚本运行时间超过 30 秒,它必须陷入无限循环,因此应该终止。这是为了防止错误的 PHP 脚本因意外或恶意而导致拒绝服务。

However, scripts do sometimes need more running time than they are allocated by default.

然而,脚本有时需要比默认分配的更多的运行时间。

You can try changing the maximum execution time, either by using set_time_limit()or by altering the value of max_execution_timein the php.inifile to raise the limit. you can also remove the limit entirely by setting the execution time to 0, though this isn't recommended.

你可以尝试改变最大执行时间,无论是使用set_time_limit()或改变的值max_execution_timephp.ini的文件,提高了极限。您也可以通过将执行时间设置为 0 来完全取消限制,尽管不建议这样做。

set_time_limit()may be disabled by mechanisms such as disable_functionsso it might not be available to you, likewise you might not have access to php.ini. If both of these are the case then you should contact your host for help.

set_time_limit()可能会被诸如此类的机制禁用,disable_functions因此您可能无法使用它,同样您可能无法访问php.ini. 如果这两种情况都是如此,那么您应该联系您的房东寻求帮助。

One exception is PHP scripts run from the command line. Under these running conditions, PHP scripts may be interactive and need to spend a long time processing data or waiting for input. For this reason there isn't a max_execution_timelimit on scripts run from the command line by default.

一个例外是从运行PHP脚本的命令行。在这些运行条件下,PHP 脚本可能是交互式的,需要花费很长时间处理数据或等待输入。因此max_execution_time,默认情况下从命令行运行的脚本没有限制。



EDIT TO ADD: PHP 7's error handling had a major overhaul. I believe that errors and exceptions are now both subclasses of Throwable. This may make the above no longer relevant for PHP7+, though I'll have to look more closely into the specifics of how error handling works now to be sure.

编辑添加:PHP 7 的错误处理进行了大修。我相信错误和异常现在都是 Throwable 的子类。这可能会使上述内容不再与 PHP7+ 相关,但我现在必须更仔细地研究错误处理如何工作的细节才能确定。

回答by pinkal vansia

There is nothing you can do about it. but you can have graceful shutdown using register_shutdown_function

你对此无能为力。但是您可以使用 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
} 

?>

回答by Pyzozord

Yeah I tested the solution by TheJanOnline. sleep() does not count into php execution time so here is WORKING version with indefinite loop:

是的,我测试了 TheJanOnline 的解决方案。sleep() 不计入 php 执行时间,因此这里是具有无限循环的 WORKING 版本:

<?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
?>

回答by user3901681

There is a little tricky way to handle "Fatal error: Maximum execution time of 30 seconds exceeded" as exception in certain cases:

在某些情况下,将“致命错误:超过 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;
}

In your code you must to measure execution time and throw exception earlier than the timeout fatal error may be triggered. $k = 0.8 is a 80% of allowed execution time, so you have 20% of time to handle exception.

在您的代码中,您必须测量执行时间并在可能触发超时致命错误之前抛出异常。$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
}

回答by TARKUS

I came up with this based on the answer @pinkal-vansia gave. So I'm not claiming an original answer, but an answer with a practical application. I needed a way for the page to refresh itself in the event of a timeout. Since I have been observing enough timeouts of my cURL script to know the code is working, but that sometimes for whatever reason it fails to connect to the remote server, or read the served html fully, and that upon refresh the problem goes away, I am ok with script refreshing itself to "cure" a Maximum execution timeout error.

我是根据@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.
}

FYI, 300 seconds is not too long for the scraping script I'm running, which takes just a little less than that to extract the data from the kinds of pages I'm scraping. Sometimes it goes over by just a few seconds only due to connection irregularities. Knowing that it's connection times that sometimes fail, rather than script processing, it's better to not increase the timeout, but rather just automatically refresh the page and try again.

仅供参考,对于我正在运行的抓取脚本来说,300 秒并不算长,这比从我抓取的各种页面中提取数据所需的时间少一点。有时它只是由于连接不规则而仅过几秒钟。知道有时失败是连接次数,而不是脚本处理,最好不要增加超时,而只是自动刷新页面并重试。

回答by Subdigger

put this in the begining of php file

把它放在php文件的开头

<?php
    set_time_limit(0);

EDIT 1

编辑 1

but first check if there are no code like this:

但首先检查是否没有这样的代码:

while (1=1) {
  echo '=)';
}

EDIT 2

编辑 2

to catch this error look set_error_handler

要捕获此错误,请查看set_error_handler