Скрываем вывод ошибок в 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());
  }
  …
?>

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




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



 #  #  #  #  #  #  #  #  #  #

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

  1. stussy
    Июль 4th, 2008

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

  2. Liiion911
    Январь 19th, 2009

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

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

  3. Pasha
    Май 27th, 2009

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

  4. Владимир
    Июнь 13th, 2009

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

  5. novice
    Июнь 14th, 2009

    Да, Владимир

  6. Владимир
    Июнь 18th, 2009

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

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

  7. juray
    Август 6th, 2009

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

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

Оставить комментарий


© 2008 - 2010 i-novice.net | Все права защищены.