Скрываем вывод ошибок в php

Ошибки в процессе выполнения скрипта бывают не то, чтобы часто, но все-таки иногда. Ведь все предусмотреть невозможно и бывают участки в коде, которые работают неправильно. Чтобы нам, программерам, понять, почему произошла та или иная ошибка, php выводит ее описание и даже говорит, где она произошла (в каком скрипте и на какой строчке). Но лучше их на экран не выводить, чтобы лишним глазам не было дополнительной информации о структуре и т.п. нашего сайта, иначе в нем будет легче найти уязвимость.

Вот пример:

Warning: fopen(test) [function.fopen]: failed to open stream: No such file or directory in D:\MyDocs\My Works\Development\PHP\test\test.php on line 2

Так нам PHP сказал, что мы пытаемся открыть файл с именем test, которого не существует. Также, как видите, он сказал, что это произошло в файле test.php на строке 2.

Ловим сообщения об ошибках

Итак, если мы не хотим выводить ошибки в окно браузера, нам надо этот вывод отключить или перенаправить. Отключается вывод ошибок одной строчкой, прописанной в .htaccess:

php_flag display_errors off

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

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

php_flag display_errors on

Потом нам нужно определиться с файлом, в который мы будем выводить эти ошибки. Пусть это будет файл errors.log в корневой директории нашего сайта. А затем, нам нужно перехватить все ошибки, чтобы перенаправить их вывод в файл errors.log.

Это делается с помощью функции set_error_handler. Она позволяет задать глобальную функцию-обработчик всех ошибок. Покажу сразу на примере, как это делается:

<?
function err_handler($errno, $errmsg, $filename, $linenum) {

    if (!in_array($errno, Array(E_NOTICE, E_STRICT, E_WARNING))) {
   
        $date = date('Y-m-d H:i:s (T)');
   
        $f = fopen('errors.log', 'a');
       
        if (!empty($f)) {
       
            $err  = "<error>\r\n";
            $err .= "  <date>$date</date>\r\n";
            $err .= "  <errno>$errno</errno>\r\n";
            $err .= "  <errmsg>$errmsg</errmsg>\r\n";
            $err .= "  <filename>$filename</filename>\r\n";
            $err .= "  <linenum>$linenum</linenum>\r\n";
            $err .= "</error>\r\n";
            fwrite($f, $err);
            fclose($f);
           
        }
       
    }

}

set_error_handler('err_handler');

?>

Здесь предполагается, что скрипт, в котором мы прописали данный вызов, находится в одной директории с файлом errors.log. Естественно, вызов set_error_handler нужно поставить в самое начало нашего скрипта.

Приведенный обработчик принимает следующие параметры:
$errno - номер ошибки (ее тип);
$errmsg - текстовое сообщение об ошибке, которое несет в себе весь смысл;
$filename - полный путь к файлу, в котором произошла ошибка;
$linenum - номер строки в файле.

Условием

if (!in_array($errno, Array(E_NOTICE, E_STRICT, E_WARNING)))

я отсек неважные сообщения типов E_NOTICE, E_STRICT, E_WARNING, которые только засоряли бы лог-файл errors.log:

E_NOTICE - означает, что интерпретатор заметил что-то, что может быть ошибкой, но не обязательно ошибка;
E_STRICT - предупреждение, что какой-то участок кода может быть обратно несовместим с предыдущими версиями PHP;
E_WARNING - предупреждение, после которого скрипт продолжает свое выполнение.

Потом при возникновении каждой ошибки я открываю файл errors.log для добавления туда информации в следующем формате (для удобства ее просмотра):


Дата и время возникновения ошибки
Номер типа ошибки
Сообщение
Путь к файлу, в котором произошла ошибка

Номер строки в файле с ошибкой

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

Эх, а я же забыл блокировать файл лога перед записью в него информации, ведь у нашего сайта множество посетителей и если у каждого будет возникать ошибка, то в файл запишется перекрывающаяся чертовщина… Чтобы этого не было, обернем вызов fwrite следующим образом:

flock($f, LOCK_EX);
fwrite($f, $err);
flock($f, LOCK_UN);

Теперь нам можно не бояться.

Генерируем сообщения об ошибке сами

Иногда нам нужно самим сгенерировать сообщение об ошибке. Для этого используется trigger_error:

trigger_error(‘ошибочка вышла: …’);

И эта ошибка будет также поймана нашим перехватчиком, который мы написали выше. А зачем генерировать сообщение об ошибке самим? Ну иногда просто бывают случаи, когда сообщение об ошибке не выкидывается само. Пример тому - выполнение функции mysql_query, которое может закончиться неудачно, а сообщения мы не увидим. Чтобы увидеть это сообщение, нам сначала нужно вызвать mysql_error, а потом передать текст ошибки с помощью trigger_error в обработчик:

<?
  …
  if (!mysql_query($sql)) {
    trigger_error('MySQL Error: '.mysql_error());
  }
  …
?>

Ну вот, теперь мы умеем контролировать вывод ошибок.





Читайте также:



11 Ответов на “Скрываем вывод ошибок в php”

  1. закинул пост к себе на социалку

  2. искал себе как оффнуть ошибки (тут нашел *php_flag display_errors off*) а потом прочитал статью до конца и решил, что сделаю как написано… када сделаю - напишу !!! =))

    Респект автору !!!

  3. Pasha

    Спасибо! Познавательная статья.

  4. я еще добавил в конец exit(‘Возникли неполадки в работе сайта сообщите пожалуйста: ****@mail.ru’); Очень удобно прекращает работу скрипта именно с того места где произошла ошибка. У меня важность функций как раз сверху вниз убывает. Так, например, если не могу связаться с базой, то дальнейшее выполнение скрипта бессмыслено.
    Только у меня не получилась вот эта часть:
    flock($f, LOCK_EX);
    fwrite($f, $err);
    flock($f, LOCK_UN);
    ЕЕ надо вставлять вместо fwrite($f, $err);?

  5. novice

    Да, Владимир

  6. flock($f, LOCK_EX);
    fwrite($f, $err);
    flock($f, LOCK_UN);

    Хоть убейте не получается! В файл записываются одни и те же ошибки.

  7. juray

    Для фатальных ошибок не работает.
    Ошибки по-прежнему выводятся в браузер, errors.log не пополняется.

    Для trigger_error - работает великолепно.
    А вот если попадается, скажем, синтаксическая ошибка - вываливается сообщение в стандартный выходной поток.

  8. Жаль, что не нашла эту статью раньше, когда было очень, очень нужно :) В любом случае, нашла здесь полезное для себя. Большое спасибо!

  9. сссс
    сссссс
    ссссссс
    чясчясчясячсчяс
    ячсячсячсяч
    ячсячсячс
    счя
    яч
    сяч
    сяч
    ся
    чсяч
    сяч
    ся
    чс
    ячс
    ячс
    ячс
    ячс
    яч
    сяч
    сяч
    ся
    чс
    ячс
    ячс
    ячс
    ячс
    яч
    сяч
    сяч
    ся
    чс
    ячс
    ячс
    ячс
    ячс
    ыфвыфвыф

    чясячсячс
    ячсчясяч
    ячс
    ячс
    ячс
    яч
    сяч
    сяч
    ся
    чс
    1
    1
    1
    1
    1
    1
    11
    1
    1
    1
    1

    11
    1
    1
    2
    2
    2

    323
    43
    4

    433
    2322

    ропропр
    пр
    оп
    ро
    рпо
    рпо
    рп
    оен
    г
    нег
    не
    гне
    г
    г
    не
    о

    роь
    оо

    а
    рке
    н
    кег
    ено
    рпо
    рп
    ро
    л
    л
    нг
    лшг

    шгл
    ро
    рп
    опр
    оп
    ро
    ен
    ен
    г
    нег
    енг
    енг
    енг
    не
    ген
    ге
    но
    про
    прорпо
    про
    рп
    о
    о
    ен
    енг
    еген
    гне
    г
    нег
    нег
    оп
    про
    рп
    мит
    мит

    рпо
    рпо
    не
    гне
    г
    енг
    негорп

    о
    рпо
    рп
    о
    рпо
    рппр
    о
    по
    енгне
    ш
    гнл

    рпо
    рпо
    ео
    а
    рпо
    рп

    ео
    ен
    г
    ен
    не
    г
    р
    а
    пр
    п

    негннннннннннннннннннннннннннннннYour text to link…

  10. […] или прописыванием в .htaccess (как вариант — можно оставить вывод в файл лога) — мне не по нраву, поскольку предпочитаю всегда […]

  11. wolf

    вставил вашу функцию в config.php и выдает такую ошибку

    Fatal error: Cannot redeclare err_handler() (previously declared in Z:\home\amm.su\WWW\config.php:14) in Z:\home\amm.su\WWW\config.php on line 30

    как решить проблему?


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map