Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

Простой ответ: вы не можете. См. manual:

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

Ответ 2

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

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

Я считаю, что есть риск дважды поймать одну и ту же ошибку, по каждой функции. Это может произойти, если ошибка, которую я обрабатываю в функции shutdownHandler(), также была обнаружена функцией errorHandler().

TODO-х:

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

2 - Внедрить обработку ошибок для всех вызовов MySQL.

3 - Внедрить обработку ошибок для моего кода javascript.

ВАЖНЫЕ ПРИМЕЧАНИЯ:

1 - Я использую следующую строку в своем php.ini для автоматического добавления вышеприведенного script ко всем 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.

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

Ответ 3

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

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

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

2) Затем добавьте это значение "php_value auto_prepend_file /www/auto _prepend.php" на ваш .htaccess в корневом каталоге.

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

Ответ 5

Ошибка script с ошибкой синтаксического разбора всегда прерывается и ее невозможно обработать. Поэтому, если script вызывается напрямую или включает/требует, вы ничего не можете сделать. Но если он вызывается AJAX, flash или любым другим способом, там есть обходной способ обнаружения ошибок синтаксического анализа.

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

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

Примечание 1 null означает is not set - isset()

Ответ 6

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

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

2) Предположим, что это верхняя ошибка script является ошибкой! это очень важно, вы не можете обнаружить фатальные ошибки в 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); #assuming, мы регистрируем ошибки сами 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');