Как уловить фатальную ошибку: Максимальное время выполнения 30 секунд превышено в PHP

Я играю с системой, которую я разрабатываю, и мне удалось заставить ее вызвать это:

Неустранимая ошибка: превышено максимальное время выполнения 30 секунд

Это случилось, когда я делал что-то нереалистичное, но все же это могло случиться с пользователем.

Кто-нибудь знает, есть ли способ поймать это исключение? Я читал, но все, кажется, предлагают увеличить время.

Ваши единственные варианты – увеличить допустимое время выполнения (установка его на 0 делает его бесконечным, но это не рекомендуется) скрипта или порождает новый поток и надеется на лучшее.

Причина, по которой это не увлекательно, заключается в том, что ее не бросают. Ни одна строка кода не вызвала ошибку, скорее, PHP сказал: «Нет, простите, это слишком долго. Пора прекратить сейчас». И это имеет смысл. Представьте, что у вас есть сценарий с максимальным временем выполнения 30 секунд, который поймает эту ошибку и займет еще 30 секунд … в плохо разработанной программе, которая открывает некоторые довольно неприятные возможности для использования. Как минимум, это создаст возможности для DOS- атак.

Как насчет того, чтобы в качестве документации 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); ?> 

Посмотрите на следующие ссылки:

  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

Это не исключение, это ошибка. Существуют важные различия между исключениями и ошибками, прежде всего ошибки не могут быть захвачены семантикой try / catch.

PHP-скрипты построены вокруг парадигмы короткого времени выполнения, поэтому по умолчанию PHP настроен на предположение, что если скрипт работает более 30 секунд, он должен быть пойман в бесконечном цикле и поэтому должен быть прерван. Это делается для предотвращения ошибочного PHP-скрипта, вызывающего отказ в обслуживании, либо случайно, либо злонамеренным намерением.

Однако для сценариев иногда требуется больше времени работы, чем по умолчанию.

Вы можете попробовать изменить максимальное время выполнения, либо используя set_time_limit() либо изменив значение max_execution_time в файле php.ini чтобы повысить лимит. вы также можете полностью удалить предел, установив время выполнения равным 0, хотя это не рекомендуется.

set_time_limit() может быть отключен такими механизмами, как disable_functions поэтому он может быть недоступен для вас, также у вас может не быть доступа к php.ini . Если это так, тогда вам следует обратиться за помощью к своему хозяину.

Одним из исключений являются скрипты PHP, запущенные из командной строки . В этих условиях работы скрипты PHP могут быть интерактивными и нуждаются в длительной обработке данных или ожидании ввода. По этой причине по умолчанию для скриптов, запущенных из командной строки, не существует предела max_execution_time .

Вы ничего не можете с этим поделать. но вы можете иметь изящное завершение работы с помощью 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. // 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 } ?> в <?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; } 

В вашем коде вы должны измерить время выполнения и исключить исключение раньше, чем таймаут может быть вызвана фатальная ошибка. $ 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. } 

FYI, 300 секунд не слишком длинный для скрипта скремблирования, который я запускаю, что занимает чуть меньше, чем для извлечения данных из тех страниц, которые я соскабливаю. Иногда это происходит через несколько секунд только из-за неравномерности соединения. Зная, что время соединения, которое иногда терпит неудачу, а не обработку скриптов, лучше не увеличивать таймаут, а просто просто обновлять страницу и повторять попытку.

Да, я протестировал решение 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 ?> 

поместите это в начало php-файла

 <?php set_time_limit(0); 

ИЗМЕНИТЬ 1

но сначала проверьте, нет ли такого кода:

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

EDIT 2

чтобы поймать эту ошибку, посмотрите set_error_handler