[php] PHP 치명적인 (`E_ERROR`) 오류를 어떻게 잡을 수 있습니까?

set_error_handler()대부분의 PHP 오류를 잡는 데 사용할 수 있지만 E_ERROR존재하지 않는 함수 호출과 같은 치명적인 ( ) 오류에는 작동하지 않습니다. 이러한 오류를 잡는 다른 방법이 있습니까?

나는 호출에 노력하고 mail()모든 오류 및 PHP 5.2.3을 실행하고 있습니다.



답변

register_shutdown_functionPHP 5.2 이상이 필요한을 사용하여 치명적 오류를 기록하십시오 .

register_shutdown_function( "fatal_handler" );

function fatal_handler() {
    $errfile = "unknown file";
    $errstr  = "shutdown";
    $errno   = E_CORE_ERROR;
    $errline = 0;

    $error = error_get_last();

    if($error !== NULL) {
        $errno   = $error["type"];
        $errfile = $error["file"];
        $errline = $error["line"];
        $errstr  = $error["message"];

        error_mail(format_error( $errno, $errstr, $errfile, $errline));
    }
}

error_mailformat_error기능 을 정의해야 합니다. 예를 들면 다음과 같습니다.

function format_error( $errno, $errstr, $errfile, $errline ) {
    $trace = print_r( debug_backtrace( false ), true );

    $content = "
    <table>
        <thead><th>Item</th><th>Description</th></thead>
        <tbody>
            <tr>
                <th>Error</th>
                <td><pre>$errstr</pre></td>
            </tr>
            <tr>
                <th>Errno</th>
                <td><pre>$errno</pre></td>
            </tr>
            <tr>
                <th>File</th>
                <td>$errfile</td>
            </tr>
            <tr>
                <th>Line</th>
                <td>$errline</td>
            </tr>
            <tr>
                <th>Trace</th>
                <td><pre>$trace</pre></td>
            </tr>
        </tbody>
    </table>";
    return $content;
}

Swift Mailer 를 사용 하여 error_mail함수 를 작성하십시오 .

또한보십시오:


답변

방금이 솔루션 (PHP 5.2.0 이상)을 생각해 냈습니다.

function shutDownFunction() {
    $error = error_get_last();
     // Fatal error, E_ERROR === 1
    if ($error['type'] === E_ERROR) {
         // Do your stuff
    }
}
register_shutdown_function('shutDownFunction');

미리 정의 된 상수에 다른 오류 유형이 정의되어 있습니다.


답변

PHP는 치명적인 오류를 포착하고 복구하는 일반적인 방법을 제공하지 않습니다. 치명적인 오류 후에 처리를 복구하지 않아야하기 때문입니다. 출력 버퍼와 일치하는 문자열 (PHP.net에 기술 된 원본 게시물에서 제안한 바와 같이)은 잘못 권장됩니다. 단순히 신뢰할 수 없습니다.

에러 핸들러 메소드 내에서 mail () 함수를 호출하는 것도 문제가있는 것으로 판명되었습니다. 많은 오류가있는 경우 메일 서버에 작업이로드되고 불완전한받은 편지함을 찾을 수 있습니다. 이를 피하기 위해 cron을 실행하여 주기적으로 오류 로그를 스캔하고 그에 따라 알림을 보내는 것을 고려할 수 있습니다. Nagios 와 같은 시스템 모니터링 소프트웨어를 살펴볼 수도 있습니다 .


종료 기능을 등록하는 방법에 대해 설명하려면 :

셧다운 기능을 등록 할 수 있다는 것은 사실이며, 정답입니다.

여기서 중요한 점은 일반적으로 출력 버퍼에 정규식을 사용하여 치명적인 오류를 복구하려고 시도하지 않아야한다는 것입니다. 나는 php.net에 대한 제안과 연결되거나 변경 된 수락 된 답변 에 응답하고있었습니다 .

그 제안은 예외 처리 중에 출력 버퍼에 대해 정규 표현식을 사용하는 것이며 치명적인 오류 (예상치 않은 구성 오류 텍스트와 일치하는 것으로 감지)의 경우 일종의 복구 또는 지속적인 처리를 시도하십시오. 그것은 권장되는 관행이 아닐 것입니다 (저는 원래 제안도 찾을 수없는 이유라고 생각합니다. 간과하거나 PHP 커뮤니티가 제안하지 않았습니다).

출력 버퍼링 콜백이 호출되기 전에 최신 버전의 PHP (약 5.1)가 셧다운 기능을 더 일찍 호출하는 것 같습니다. 버전 5 이하에서는 그 순서가 역순이었습니다 (출력 버퍼링 콜백에 종료 기능이 뒤 따름). 또한 약 5.0.5 (질문의 버전 5.2.3보다 훨씬 빠름) 이후 등록 된 종료 기능이 호출되기 전에 객체가 언로드되므로 메모리 내 객체를 사용하여 수행 할 수 없습니다. 많은 것.

따라서 셧다운 기능을 등록하는 것은 좋지만 셧다운 기능으로 수행해야하는 작업 종류는 아마도 몇 가지 부드러운 셧다운 절차로 제한 될 수 있습니다.

여기서 중요한 것은이 질문을 우연히 발견하고 원래 받아 들여진 대답의 조언을 보는 사람에게는 지혜로운 말입니다. 출력 버퍼를 정규식으로 변환하지 마십시오.


답변

글쎄, 다른 방법으로 치명적인 오류를 잡을 수있는 것 같습니다 🙂

ob_start('fatal_error_handler');

function fatal_error_handler($buffer){
    $error = error_get_last();
    if($error['type'] == 1){
        // Type, message, file, line
        $newBuffer='<html><header><title>Fatal Error </title></header>
                      <style>
                    .error_content{
                        background: ghostwhite;
                        vertical-align: middle;
                        margin:0 auto;
                        padding: 10px;
                        width: 50%;
                     }
                     .error_content label{color: red;font-family: Georgia;font-size: 16pt;font-style: italic;}
                     .error_content ul li{ background: none repeat scroll 0 0 FloralWhite;
                                border: 1px solid AliceBlue;
                                display: block;
                                font-family: monospace;
                                padding: 2%;
                                text-align: left;
                      }
                      </style>
                      <body style="text-align: center;">
                        <div class="error_content">
                             <label >Fatal Error </label>
                             <ul>
                               <li><b>Line</b> ' . $error['line'] . '</li>
                               <li><b>Message</b> ' . $error['message'] . '</li>
                               <li><b>File</b> ' . $error['file'] . '</li>
                             </ul>

                             <a href="javascript:history.back()"> Back </a>
                        </div>
                      </body></html>';

        return $newBuffer;
    }
    return $buffer;
}


답변

치명적 오류 또는 복구 가능한 치명적 오류는 이제 PHP 7 이상의 버전Error 에서 인스턴스를 발생시킵니다 . 다른 예외와 마찬가지로 블록을 사용하여 객체를 잡을 수 있습니다 .Errortry/catch

예:

<?php
$variable = 'not an object';

try {
    $variable->method(); // Throws an Error object in PHP 7 or higger.
} catch (Error $e) {
    // Handle error
    echo $e->getMessage(); // Call to a member function method() on string
}

https://3v4l.org/67vbk

또는 Throwable인터페이스를 사용 하여 모든 예외를 포착 할 수 있습니다 .

예:

<?php
    try {
        undefinedFunctionCall();
    } catch (Throwable $e) {
        // Handle error
        echo $e->getMessage(); // Call to undefined function undefinedFunctionCall()
    }

https://3v4l.org/Br0MG

자세한 정보 : http://php.net/manual/en/language.errors.php7.php


답변

PHP에서 모든 오류 유형을 잡는 방법을 개발했습니다 (거의 모든 것)! E_CORE_ERROR에 대해 잘 모르겠습니다 (해당 오류에 대해서만 작동하지는 않습니다). 그러나 다른 치명적 오류 (E_ERROR, E_PARSE, E_COMPILE …)의 경우 하나의 오류 처리기 함수 만 사용하면 제대로 작동합니다! 내 해결책이 있습니다.

다음 코드를 기본 파일 (index.php)에 넣으십시오.

<?php
    define('E_FATAL',  E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR |
            E_COMPILE_ERROR | E_RECOVERABLE_ERROR);

    define('ENV', 'dev');

    // Custom error handling vars
    define('DISPLAY_ERRORS', TRUE);
    define('ERROR_REPORTING', E_ALL | E_STRICT);
    define('LOG_ERRORS', TRUE);

    register_shutdown_function('shut');

    set_error_handler('handler');

    // Function to catch no user error handler function errors...
    function shut(){

        $error = error_get_last();

        if($error && ($error['type'] & E_FATAL)){
            handler($error['type'], $error['message'], $error['file'], $error['line']);
        }

    }

    function handler( $errno, $errstr, $errfile, $errline ) {

        switch ($errno){

            case E_ERROR: // 1 //
                $typestr = 'E_ERROR'; break;
            case E_WARNING: // 2 //
                $typestr = 'E_WARNING'; break;
            case E_PARSE: // 4 //
                $typestr = 'E_PARSE'; break;
            case E_NOTICE: // 8 //
                $typestr = 'E_NOTICE'; break;
            case E_CORE_ERROR: // 16 //
                $typestr = 'E_CORE_ERROR'; break;
            case E_CORE_WARNING: // 32 //
                $typestr = 'E_CORE_WARNING'; break;
            case E_COMPILE_ERROR: // 64 //
                $typestr = 'E_COMPILE_ERROR'; break;
            case E_CORE_WARNING: // 128 //
                $typestr = 'E_COMPILE_WARNING'; break;
            case E_USER_ERROR: // 256 //
                $typestr = 'E_USER_ERROR'; break;
            case E_USER_WARNING: // 512 //
                $typestr = 'E_USER_WARNING'; break;
            case E_USER_NOTICE: // 1024 //
                $typestr = 'E_USER_NOTICE'; break;
            case E_STRICT: // 2048 //
                $typestr = 'E_STRICT'; break;
            case E_RECOVERABLE_ERROR: // 4096 //
                $typestr = 'E_RECOVERABLE_ERROR'; break;
            case E_DEPRECATED: // 8192 //
                $typestr = 'E_DEPRECATED'; break;
            case E_USER_DEPRECATED: // 16384 //
                $typestr = 'E_USER_DEPRECATED'; break;
        }

        $message =
            '<b>' . $typestr .
            ': </b>' . $errstr .
            ' in <b>' . $errfile .
            '</b> on line <b>' . $errline .
            '</b><br/>';

        if(($errno & E_FATAL) && ENV === 'production'){

            header('Location: 500.html');
            header('Status: 500 Internal Server Error');

        }

        if(!($errno & ERROR_REPORTING))
            return;

        if(DISPLAY_ERRORS)
            printf('%s', $message);

        //Logging error on php file error log...
        if(LOG_ERRORS)
            error_log(strip_tags($message), 0);
    }

    ob_start();

    @include 'content.php';

    ob_end_flush();
?>


답변

치명적인 오류는 포착 / 처리 할 수 ​​없지만 기록 /보고 할 수는 있습니다. 빠른 디버깅을 위해이 간단한 코드에 대한 하나의 답변을 수정했습니다.

function __fatalHandler()
{
    $error = error_get_last();

    // Check if it's a core/fatal error, otherwise it's a normal shutdown
    if ($error !== NULL && in_array($error['type'],
        array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING,
              E_COMPILE_ERROR, E_COMPILE_WARNING,E_RECOVERABLE_ERROR))) {

        echo "<pre>fatal error:\n";
        print_r($error);
        echo "</pre>";
        die;
    }
}

register_shutdown_function('__fatalHandler');