Скрываем вывод ошибок в 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());
}
…
?>
Ну вот, теперь мы умеем контролировать вывод ошибок.
закинул пост к себе на социалку
искал себе как оффнуть ошибки (тут нашел *php_flag display_errors off*) а потом прочитал статью до конца и решил, что сделаю как написано… када сделаю - напишу !!! =))
Респект автору !!!
Спасибо! Познавательная статья.
я еще добавил в конец exit(‘Возникли неполадки в работе сайта сообщите пожалуйста: ****@mail.ru’); Очень удобно прекращает работу скрипта именно с того места где произошла ошибка. У меня важность функций как раз сверху вниз убывает. Так, например, если не могу связаться с базой, то дальнейшее выполнение скрипта бессмыслено.
Только у меня не получилась вот эта часть:
flock($f, LOCK_EX);
fwrite($f, $err);
flock($f, LOCK_UN);
ЕЕ надо вставлять вместо fwrite($f, $err);?
Да, Владимир
flock($f, LOCK_EX);
fwrite($f, $err);
flock($f, LOCK_UN);
Хоть убейте не получается! В файл записываются одни и те же ошибки.
Для фатальных ошибок не работает.
Ошибки по-прежнему выводятся в браузер, errors.log не пополняется.
Для trigger_error - работает великолепно.
А вот если попадается, скажем, синтаксическая ошибка - вываливается сообщение в стандартный выходной поток.
Жаль, что не нашла эту статью раньше, когда было очень, очень нужно В любом случае, нашла здесь полезное для себя. Большое спасибо!
сссс
сссссс
сссссссчясчясчясячсчяс
ячсячсячсяч
ячсячсячс
счя
яч
сяч
сяч
ся
чсяч
сяч
ся
чс
ячс
ячс
ячс
ячс
яч
сяч
сяч
ся
чс
ячс
ячс
ячс
ячс
яч
сяч
сяч
ся
чс
ячс
ячс
ячс
ячс
ыфвыфвыф
чясячсячс
ячсчясяч
ячс
ячс
ячс
яч
сяч
сяч
ся
чс
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…
[…] или прописыванием в .htaccess (как вариант — можно оставить вывод в файл лога) — мне не по нраву, поскольку предпочитаю всегда […]
вставил вашу функцию в 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
как решить проблему?