PHP: пользовательский обработчик ошибок - обработка разборов и фатальных ошибок - PullRequest
53 голосов
/ 14 декабря 2009

Как мне обработать парсинг & фатальные ошибки с использованием обработчика ошибок custom ?

Ответы [ 6 ]

68 голосов
/ 06 сентября 2011

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

Надеюсь, это кому-нибудь поможет.

30 голосов
/ 14 декабря 2009

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

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

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

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

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

EDIT:

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

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

11 голосов
/ 10 июня 2011

Из комментариев 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 в корне сети.

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

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

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); # для того, чтобы скрыть ошибки, отображаемые пользователю по php ini_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');
4 голосов
/ 02 сентября 2010

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

Мне нужно было это для обработки сценария swfupload . 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()

...