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

#php

Вопрос:

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

Комментарии:

1. Почему бы не перехватить ошибки синтаксического анализа вверх по течению с помощью a php -l ?

2. Как вы это делаете из браузера, в котором запущена программа PHP?

Ответ №1:

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

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.

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

Комментарии:

1. Похоже, он не обрабатывает «Ошибки синтаксического анализа»… попробуйте следующее: эхо «Кошка»; эхо «Собака», эхо «Лев».;

2. Вы должны добавить файл для обработки ошибок синтаксического анализа!

3. E_DEPRECATED и E_USER_DEPRECATED также должен быть включен в функцию пользовательского обработчика ошибок.

4. Если я вручную добавляю такой файл, он не выдает ошибку «abc();», где abc не определен. Отобразится ошибка «не обработано». Пожалуйста, приведите полный пример теста.

Ответ №2:

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

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

Комментарии:

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

2. Да, ты можешь. Однако у этого есть некоторые недостатки: см. Мое редактирование выше

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

4. Или вы можете «обработать» их с помощью приложения, такого как NewRelic, которое позволяет вам фиксировать их, а затем активно отслеживать и исправлять. Если вы просто проигнорируете их, они никогда не будут обработаны.

5. Как отмечалось в других ответах, вы можете поймать все типы ошибок include s (не: require ). Поэтому все, что вам нужно, — это небольшой файл верхнего уровня, который выполняет всю работу, а затем становится настоящим. .php include Это относительно легко реализовать с NginX помощью и php-fpm (подсказка: cgi.fix_pathinfo=0 ).

Ответ №3:

Вы можете отслеживать эти ошибки с помощью такого кода:

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

Комментарии:

1. Да, есть способ поймать E_PARSE! Поместите функцию обработчика ошибок в index.php и включить/потребовать другой файл, где должна быть логика сайта!

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

3. @LucasBatistussi, вы все еще не можете поймать ошибки синтаксического анализа для index.php

4. Тестирование на php 5.3 — win 7. Функция выключения НЕ вызывается при ошибках синтаксического анализа.

5. @LucasBatistussi, ты можешь объяснить? Я вставляю функцию обработчика ошибок index.php и затем включаю ее в свой скрипт с помощью include(index.php) . Но он все равно не может поймать ошибки синтаксического анализа(синтаксическая ошибка). Я не думаю, что это возможно без встраивания его в php.ini.

Ответ №4:

Из 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. Это решение охватывает E_PARSE, E_COMPILE_ERROR и т.д. Итак, ответ Дэна Мыла и php.net руководство неверно. Спасибо!

2. Если вы используете FastCGI, вы не можете установить значение PHP в файле .htaccess. Вместо этого вы используете свой локальный файл php.ini и устанавливаете непосредственно auto_prepend_file = /www/auto_prepend.php

Ответ №5:

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

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');
 

Комментарии:

1. Спасибо, что добавили, что функции не могут находиться в том же файле, что и ошибка.

2. Лучше использовать закрытие в качестве обработчика ошибок, потому что в настоящее время именованные функции могут быть переопределены

3. Это единственный ответ, который меня устраивает. Ключом было ini_set('display_errors', false); скрыть отчеты PHP. Следует также отметить, что функция set_error_handler не требуется, так как обратный вызов функции register_shutdown_function получает даже ошибки E_NOTICE, такие как использование определенных констант, которые не были определены. При таком понимании обработка исключений (try/catch) не требуется для многих программ, которые останавливаются при первой обнаруженной ошибке.

Ответ №6:

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