PHP: пользовательский обработчик ошибок - обработка разборов и фатальных ошибок

Как я могу обработать парсинг и фатальные ошибки, используя собственный обработчик ошибок?

6 ответов

Решение

Простой ответ: вы не можете. Смотрите руководство:

Следующие типы ошибок не могут быть обработаны пользовательской функцией: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING и большинство E_STRICT, созданных в файле, где вызывается set_error_handler().

Для каждой другой ошибки, вы можете использовать set_error_handler()

РЕДАКТИРОВАТЬ:

Поскольку, кажется, что есть некоторые дискуссии на эту тему, в отношении использования register_shutdown_function, мы должны взглянуть на определение обработки: для меня обработка ошибки означает ее обнаружение и реагирование таким образом, который является "приятным" для пользователя и базовых данных (базы данных, файлы, веб-службы и т. д.),

С помощью register_shutdown_function Вы не можете обработать ошибку из кода, где она была вызвана, то есть код все равно перестанет работать в том месте, где происходит ошибка. Вы можете, однако, представить пользователю сообщение об ошибке вместо белой страницы, но вы не можете, например, откатить все, что сделал ваш код до сбоя.

На самом деле вы можете обрабатывать разбор и фатальные ошибки. Это правда, что функция обработчика ошибок, которую вы определили с помощью 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().

Это работает над сайтом, который у меня в разработке. Я еще не проверял это в производстве. Но он в настоящее время ловит все ошибки, которые я нахожу при разработке.

Я считаю, что есть риск отловить одну и ту же ошибку дважды, по одному на каждую функцию. Это может произойти, если ошибка, которую я обрабатываю в функции 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, чтобы уменьшить риск того, что мои пользователи увидят ужасные сообщения об ошибках PHP.

Я надеюсь, что это помогает кому-то.

Вы можете отследить эти ошибки, используя следующий код:

(Ошибки разбора могут быть обнаружены только в том случае, если они появляются в других файлах скрипта через include() или же require()или поместив этот код в 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');

Из комментариев PHP.net на странице http://www.php.net/manual/en/function.set-error-handler.php

Я понял, что некоторые люди здесь упоминали, что вы не можете перехватить ошибки синтаксического анализа (тип 4, E_PARSE). Это неправда. Вот как я это делаю. Я надеюсь, что это помогает кому-то.

1) Создайте файл "auto_prepend.php" в корне сети и добавьте следующее:

<?php 
register_shutdown_function('error_alert'); 

function error_alert() 
{ 
        if(is_null($e = error_get_last()) === false) 
        { 
                mail('your.email@example.com', 'Error from auto_prepend', print_r($e, true)); 
        } 
} 
?> 

2) Затем добавьте этот "php_value auto_prepend_file /www/auto_prepend.php" в ваш файл.htaccess в корне сети.

  • убедитесь, что вы изменили адрес электронной почты и путь к файлу.

Исходя из моего опыта, вы можете поймать все типы ошибок, скрыть сообщение об ошибке по умолчанию и отобразить собственное сообщение об ошибке (если хотите). Ниже перечислены вещи, которые вам нужны.

1) Скрипт начального / верхнего уровня, назовем его index.php где вы храните пользовательские функции обработчика ошибок. Обработчики пользовательских функций ошибок должны оставаться наверху, чтобы они улавливали ошибки под ними, под "ниже", я имею в виду во включаемых файлах.

2) Предположение, что этот топ-скрипт не содержит ошибок, должно быть верным! это очень важно, вы не можете поймать фатальные ошибки в index.php когда ваша пользовательская функция обработчика ошибок найдена в index.php,

3) Php директивы (также должны быть найдены в index.php)set_error_handler("myNonFatalErrorHandler"); # для того, чтобы ловить несмертельные ошибкиregister_shutdown_function('myShutdown'); # чтобы ловить фатальные ошибкиini_set('display_errors', false); # для того, чтобы скрыть ошибки, отображаемые пользователю по phpini_set('log_errors',FALSE); # предполагая, что мы регистрируем ошибки самиini_set('error_reporting', E_ALL); # Мы хотим сообщать обо всех ошибках

пока в производстве (если я не ошибаюсь) мы можем уйти ini_set('error_reporting', E_ALL); как для того, чтобы иметь возможность регистрировать ошибки, в то же время ini_set('display_errors', false); будет следить за тем, чтобы ошибки не отображались пользователю.

Что касается фактического содержания двух функций, о которых я говорю, myNonFatalErrorHandler а также myShutdownЯ не выкладываю здесь подробный контент, чтобы все было просто. Кроме того, другие посетители привели много примеров. Я просто показываю очень простую идею.

function myNonFatalErrorHandler($v, $m, $f, $l, $c){
 $some_logging_var_arr1[]="format $v, $m, $f, ".$err_lvl[$l].", $c the way you like";
 //You can display the content of $some_logging_var_arr1 at the end of execution too.
}

function myShutdown()
{
  if( ($e=error_get_last())!==null ){
      $some_logging_var_arr2= "Format the way you like:". $err_level[$e['type']].$e['message'].$e['file'].$e['line'];
  }
//display $some_logging_var_arr2 now or later, e.g. from a custom session close function
}

что касается $err_lvl, то это может быть:

$err_lvl = array(E_ERROR=>'E_ERROR', E_CORE_ERROR=>'E_CORE_ERROR', E_COMPILE_ERROR=>'E_COMPILE_ERROR', E_USER_ERROR=>'E_USER_ERROR', E_PARSE=>'E_PARSE', E_RECOVERABLE_ERROR=>'E_RECOVERABLE_ERROR', E_WARNING=>'E_WARNING', E_CORE_WARNING=>'E_CORE_WARNING', E_COMPILE_WARNING=>'E_COMPILE_WARNING',
E_USER_WARNING=>'E_USER_WARNING', E_NOTICE=>'E_NOTICE', E_USER_NOTICE=>'E_USER_NOTICE',E_STRICT=>'E_STRICT');

Скрипт с ошибкой разбора всегда прерывается и не может быть обработан. Так что если скрипт вызывается напрямую или с помощью include/require, вы ничего не можете сделать. Но если он вызывается AJAX, flash или любым другим способом, есть обходной путь, как обнаруживать ошибки разбора.

Мне нужно это для обработки сценария http://swfupload.org/. Swfupload - это флэш-память, которая обрабатывает загрузку файлов и каждый раз, когда файл загружается, она вызывает скрипт обработки PHP для обработки файловых данных, но нет вывода из браузера, поэтому сценарию обработки PHP нужны эти настройки для целей отладки:

  • предупреждения и уведомления ob_start(); в начале и сохранить содержимое в сеанс с помощью ob_get_contents(); в конце сценария обработки: это может быть отображено в браузере другим сценарием
  • фатальные ошибки register_shutdown_function() для установки сеанса с тем же трюком, что и выше
  • разбирать ошибки, если ob_get_contents () находится в конце сценария обработки, и ошибка разбора, возникшая ранее, сеанс не заполняется (он нулевой). Сценарий отладки может справиться с этим следующим образом: if(!isset($_SESSION["swfupload"])) echo "parse error";

Примечание 1 null средства is not set в isset()

Другие вопросы по тегам