web-dev-qa-db-ja.com

PHP:カスタムエラーハンドラ-解析および致命的エラーの処理

カスタムエラーハンドラを使用して解析致命的エラーを処理するにはどうすればよいですか?

54

簡単な答え:できません。 manual を参照してください:

次のエラータイプは、ユーザー定義関数では処理できません:E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING、およびset_error_handler()が呼び出されるファイルで発生するE_STRICTのほとんど。

他のすべてのエラーについては、set_error_handler()を使用できます

編集:

register_shutdown_functionの使用に関して、このトピックに関するいくつかの議論があるように思えるので、処理の定義を確認する必要があります。ユーザーおよび基になるデータ(データベース、ファイル、Webサービスなど)にとって「いい」です。

register_shutdown_functionを使用すると、呼び出されたコード内からエラーを処理することはできません。つまり、エラーが発生した時点でコードが機能しなくなります。ただし、ホワイトページの代わりにエラーメッセージをユーザーに表示することはできますが、たとえば、失敗する前にコードで実行したことをロールバックすることはできません。

27
Dan Soap

実際には、解析エラーと致命的なエラーを処理できます。 set_error_handler()で定義したエラーハンドラー関数が呼び出されないのは事実です。それを行う方法は、register_shutdown_function()でシャットダウン関数を定義することです。これが私のウェブサイトで働いていることです:

ファイルprepend.php(このファイルはすべてのphpスクリプトに自動的に追加されます)。ファイルをPHPに追加するためのヒントについては、以下を参照してください。

set_error_handler("errorHandler");
register_shutdown_function("shutdownHandler");

function errorHandler($error_level, $error_message, $error_file, $error_line, $error_context)
{
$error = "lvl: " . $error_level . " | msg:" . $error_message . " | file:" . $error_file . " | ln:" . $error_line;
switch ($error_level) {
    case E_ERROR:
    case E_CORE_ERROR:
    case E_COMPILE_ERROR:
    case E_PARSE:
        mylog($error, "fatal");
        break;
    case E_USER_ERROR:
    case E_RECOVERABLE_ERROR:
        mylog($error, "error");
        break;
    case E_WARNING:
    case E_CORE_WARNING:
    case E_COMPILE_WARNING:
    case E_USER_WARNING:
        mylog($error, "warn");
        break;
    case E_NOTICE:
    case E_USER_NOTICE:
        mylog($error, "info");
        break;
    case E_STRICT:
        mylog($error, "debug");
        break;
    default:
        mylog($error, "warn");
}
}

function shutdownHandler() //will be called when php script ends.
{
$lasterror = error_get_last();
switch ($lasterror['type'])
{
    case E_ERROR:
    case E_CORE_ERROR:
    case E_COMPILE_ERROR:
    case E_USER_ERROR:
    case E_RECOVERABLE_ERROR:
    case E_CORE_WARNING:
    case E_COMPILE_WARNING:
    case E_PARSE:
        $error = "[SHUTDOWN] lvl:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line'];
        mylog($error, "fatal");
}
}

function mylog($error, $errlvl)
{
...do whatever you want...
}

PHPは、スクリプトのいずれかでエラーをキャッチすると、errorHandler()関数を呼び出します。エラーによってスクリプトがすぐにシャットダウンされる場合、エラーは関数shutdownHandler()によって処理されます。

これは、開発中のサイトで機能しています。実稼働ではまだテストしていません。しかし、現在、開発中に見つかったすべてのエラーをキャッチしています。

同じエラーを各機能で1回ずつ、2回キャッチするリスクがあると思います。これは、関数shutdownHandler()で処理しているエラーが関数errorHandler()でもキャッチされた場合に発生する可能性があります。

TODO:

1-エラーを適切に処理するために、より良いlog()関数で作業する必要があります。私はまだ開発中なので、基本的にデータベースにエラーを記録し、画面にエコーします。

2-すべてのMySQL呼び出しにエラー処理を実装します。

3-JavaScriptコードのエラー処理を実装します。

重要な注意事項:

1-php.iniで次の行を使用して、上記のスクリプトをすべてのphpスクリプトに自動的に追加します。

auto_prepend_file = "/homepages/45/d301354504/htdocs/hmsee/cgi-bin/errorhandling.php"

それはうまく機能します。

2-E_STRICTエラーを含むすべてのエラーをログに記録して解決しています。きれいなコードを開発することを信じています。開発中、私のphp.iniファイルには次の行があります。

track_errors = 1
display_errors = 1
error_reporting = 2147483647
html_errors = 0

ライブに移行したら、display_errorsを0に変更して、ユーザーがusersいPHPエラーメッセージを表示するリスクを軽減します。

これが誰かの助けになることを願っています。

69
jdias

次のようなコードを使用して、これらのエラーを追跡できます。

(解析エラーは、include()またはrequire()を介してotherスクリプトファイルで発生した場合、またはこのコードをauto_prepend_file他の回答が述べているように。)

function shutdown() {
    $isError = false;

    if ($error = error_get_last()){
    switch($error['type']){
        case E_ERROR:
        case E_CORE_ERROR:
        case E_COMPILE_ERROR:
        case E_USER_ERROR:
            $isError = true;
            break;
        }
    }

    if ($isError){
        var_dump ($error);//do whatever you need with it
    }
}

register_shutdown_function('shutdown');
30
Deniss Kozlovs

ページのPHP.netコメントから http://www.php.net/manual/en/function.set-error-handler.php

ここでは、解析エラー(タイプ4、E_PARSE)をキャプチャできないと言っている人がいることに気付きました。本当じゃない。これが私のやり方です。これが誰かの助けになることを願っています。

1)Webルートに「auto_prepend.php」ファイルを作成し、これを追加します。

<?php 
register_shutdown_function('error_alert'); 

function error_alert() 
{ 
        if(is_null($e = error_get_last()) === false) 
        { 
                mail('[email protected]', 'Error from auto_prepend', print_r($e, true)); 
        } 
} 
?> 

2)次に、この「php_value auto_prepend_file /www/auto_prepend.php」をWebルートの.htaccessファイルに追加します。

  • メールアドレスとファイルへのパスを必ず変更してください。
11
Creativehavoc

解析エラーのあるスクリプトは常に中断され、処理できません。したがって、スクリプトが直接またはinclude/requireによって呼び出された場合、何もできません。しかし、AJAX、フラッシュ、またはその他の方法で呼び出された場合、解析エラーを検出する方法の回避策があります。

swfupload スクリプトを処理するためにこれが必要でした。 Swfuploadは、ファイルのアップロードを処理するフラッシュであり、ファイルがアップロードされるたびに、PHPスクリプトを処理してfiledataを処理します。ただし、ブラウザ出力がないため、PHP =スクリプトを処理するには、デバッグのために次の設定が必要です。

  • 警告と通知ob_start();最初にob_get_contents()によりコンテンツをセッションに保存します。処理スクリプトの最後:これは別のスクリプトによってブラウザに表示できます
  • 致命的なエラーregister_shutdown_function()は、上記と同じトリックでセッションを設定します
  • 解析エラーob_get_contents()が処理スクリプトの最後にあり、解析エラーが以前に発生した場合、セッションは満たされません(nullです) 。デバッグスクリプトは次のように処理できます:if(!isset($_SESSION["swfupload"])) echo "parse error";

注1nullは_is not set_からisset()を意味します

4
Jan Turoň