Programing

치명적인 오류 잡는 방법 : PHP에서 최대 실행 시간 30 초 초과

crosscheck 2021. 1. 10. 19:14

치명적인 오류 잡는 방법 : PHP에서 최대 실행 시간 30 초 초과


나는 내가 개발하고있는 시스템을 가지고 놀았고 이것이 이것을 유발하도록 관리했습니다.

치명적인 오류 : 최대 실행 시간 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()값을 사용 하거나 변경하여 최대 실행 시간을 변경해 볼 수 있습니다 . 실행 시간을 0으로 설정하여 제한을 완전히 제거 할 수도 있지만 권장하지는 않습니다.max_execution_timephp.ini

set_time_limit()다음과 같은 메커니즘에 의해 비활성화되어 사용 disable_functions하지 못할 수 있습니다. 마찬가지로에 대한 액세스 권한이 없을 수 있습니다 php.ini. 이 두 가지 모두에 해당하는 경우 호스트에게 도움을 요청해야합니다.

한 가지 예외는 명령 줄 에서 실행되는 PHP 스크립트 입니다. 이러한 실행 조건에서 PHP 스크립트는 상호 작용할 수 있으며 데이터를 처리하거나 입력을 기다리는 데 오랜 시간을 소비해야합니다. 이러한 이유로 max_execution_time기본적으로 명령 줄에서 실행되는 스크립트 에는 제한 이 없습니다 .


추가 편집 : PHP 7의 오류 처리가 대대적으로 정비되었습니다. 이제 오류와 예외가 모두 Throwable의 하위 클래스라고 생각합니다. 이로 인해 위의 내용이 더 이상 PHP7 +와 관련이 없을 수 있지만, 지금은 오류 처리가 어떻게 작동하는지 자세히 살펴보아야합니다.


그것에 대해 할 수있는 일은 없습니다. 하지만 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
} 

?>

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


특정 경우에 예외로 "치명적 오류 : 최대 실행 시간 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.

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
}

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.

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


put this in the begining of php file

<?php
    set_time_limit(0);

EDIT 1

but first check if there are no code like this:

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

EDIT 2

to catch this error look set_error_handler

ReferenceURL : https://stackoverflow.com/questions/6861033/how-to-catch-the-fatal-error-maximum-execution-time-of-30-seconds-exceeded-in-p