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


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

Author: A.N.M. Saiful Islam, 2009-12-14

6 answers

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

Следующие типы ошибок не могут быть обработаны с помощью определяемой пользователем функции: ОШИБКА E_, ОШИБКА E_PARSE, ОШИБКА E_CORE_ERROR, ПРЕДУПРЕЖДЕНИЕ E_CORE_, ОШИБКА E_COMPILE_ERROR, E_COMPILE_WARNING и большая часть E_STRICT, вызванных в файле, где вызывается set_error_handler().

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

ИЗМЕНИТЬ:

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

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

 26
Author: Dan Soap, 2011-09-30 20:58:50

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

ТОДО:

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.

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

 62
Author: jdias, 2016-04-15 19:19:12

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

(Ошибки синтаксического анализа могут быть обнаружены только в том случае, если они встречаются в других файлах сценариев с помощью 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');
 29
Author: Deniss Kozlovs, 2014-10-23 04:15:37

Из 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('[email protected]', 'Error from auto_prepend', print_r($e, true)); 
        } 
} 
?> 

2) Затем добавьте это "значение php_value авто_репенд_файл /www/auto_prepend.php "чтобы твой файл .htaccess в корневом каталоге веб-сайта.

  • убедитесь, что вы изменили адрес электронной почты и путь к файлу.
 11
Author: Creativehavoc, 2011-06-10 02:58:08

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

 4
Author: Jan Turoň, 2010-09-02 07:36:44

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

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
Author: Melsi, 2013-12-28 01:20:29