Скрываем вывод ошибок в 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 в обработчик:
Ну вот, теперь мы умеем контролировать вывод ошибок.

Июль 4th, 2008
закинул пост к себе на социалку
Январь 19th, 2009
искал себе как оффнуть ошибки (тут нашел *php_flag display_errors off*) а потом прочитал статью до конца и решил, что сделаю как написано… када сделаю – напишу !!! =))
Респект автору !!!
Май 27th, 2009
Спасибо! Познавательная статья.
Июнь 13th, 2009
я еще добавил в конец exit(’Возникли неполадки в работе сайта сообщите пожалуйста: ****@mail.ru’); Очень удобно прекращает работу скрипта именно с того места где произошла ошибка. У меня важность функций как раз сверху вниз убывает. Так, например, если не могу связаться с базой, то дальнейшее выполнение скрипта бессмыслено.
Только у меня не получилась вот эта часть:
flock($f, LOCK_EX);
fwrite($f, $err);
flock($f, LOCK_UN);
ЕЕ надо вставлять вместо fwrite($f, $err);?
Июнь 14th, 2009
Да, Владимир
Июнь 18th, 2009
flock($f, LOCK_EX);
fwrite($f, $err);
flock($f, LOCK_UN);
Хоть убейте не получается! В файл записываются одни и те же ошибки.
Август 6th, 2009
Для фатальных ошибок не работает.
Ошибки по-прежнему выводятся в браузер, errors.log не пополняется.
Для trigger_error – работает великолепно.
А вот если попадается, скажем, синтаксическая ошибка – вываливается сообщение в стандартный выходной поток.