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

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

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

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

有谁知道是否有办法赶上这个例外? 我已经阅读,但似乎每个人都build议提高时间。

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

这是不可捕捉的原因是它并没有真正抛出。 没有一行代码实际上触发了这个错误,而是PHP说:“不,不好意思,这太长了,现在closures了。 这是有道理的。 想象一下,一个脚本的最大执行时间为30秒,捕捉到这个错误,又花了30秒…在一个devise不好的程序中,开辟了一些相当恶劣的利用机会。 它至less会为DOS攻击创造机会。

如何尝试PHP文档(以及至less有一个读者)说:

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

看看下面的链接:

  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

这不是一个例外,这是一个错误。 exception和错误之间有重要的区别,首先,错误不能被try / catch语义捕获。

PHP脚本是build立在执行时间短的范例之上的,所以PHP默认configuration为假设脚本运行时间超过30秒,它必须被陷入无限循环,因此应该被终止。 这是为了防止错误的PHP脚本导致拒绝服务,无论是意外或恶意的意图。

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

您可以尝试通过使用set_time_limit()或通过更改php.ini文件中max_execution_time的值来提高限制来更改最大执行时间。 您也可以通过将执行时间设置为0来完全删除限制,但不build议这样做。

set_time_limit()可能被诸如disable_functions的机制禁用,所以它可能对您不可用,同样,您可能无法访问php.ini 。 如果这两种情况都是这样,那么你应该联系你的主机寻求帮助。

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

你无能为力。 但是可以使用register_shutdown_function进行正常closures

 <?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. // eg 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; } 

在您的代码中,您必须测量执行时间并在超时之前抛出exception,否则可能会触发致命错误。 $ k = 0.8是允许执行时间的80%,所以你有20%的时间来处理exception。

 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秒不会太长,只需要一点点就可以从我正在抓取的各种页面中提取数据。 有时由于连接不正常而仅仅过了几秒钟。 了解到连接时间有时会失败,而不是脚本处理,最好不要增加超时,而只是自动刷新页面,然后重试。

是的,我通过TheJanOnlinetesting了解决scheme。 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 ?> 

把这个在PHP文件的开始

 <?php set_time_limit(0); 

编辑1

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

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

编辑2

抓住这个错误看看set_error_handler