Изучаем PHP. Тонкости экстремальной отладки скриптов
Дело в том, что многие проекты находятся на обычных хостингах, администрация которых действует по правилу «меньше знаешь, лучше спишь». Обычно под выполнение скриптов зарезервированы довольно скудные ресурсы. А вывод ошибок подавляется, или перенаправляется. Как же быть в этой ситуации?
Чем нам может помочь PHP при отладке скриптов?
Как показывает практика, для разработчиков администраторы предусматривают переопределение многих параметров.
Примечание автора: здесь будут рассмотрены подходы, которые касаются самого языка программирования PHP. Этот способ является более универсальным, чем рассмотрение методов, связанных с конфигурацией определённого серверного П.О.
Что же делать, когда у Вас вместо сайта возникает белый лист, для начала давайте включим отображение ошибок: добавьте следующие строки в начало скрипта, требующего отладки.
<?php ini_set("error_reporting",E_ALL & ~E_NOTICE); ini_set("display_errors",1); ini_set("error_log",""); function errPrint(){ print_r(error_get_last()); } register_shutdown_function("errPrint"); ... ?>
Примечание: подход актуален для полного перехвата даже критичных ошибок при отладке в PHP версии, равной или выше 5.2.
Разберём приведённый выше PHP код:
Описание функции ini_set:
(string) ini_set ($server_var_name,$server_var_value) – устанавливает значение $server_var_value для переменной среды выполнения PHP $server_var_name, в случае удачного присвоения возвращает значение переменной, иначе возвращает false.
Для начала мы включаем отображение ошибок ini_set(«display_errors»,1). После этого мы устанавливаем значение для вывода ошибок «error_reporting», E_ALL & ~E_NOTICE, равное отображению всех ошибок, но без подсказок E_NOTICE.
Примечание автора: E_NOTICE – подсказки, как «правильно программировать» на усмотрение PHP интерпретатора. Зачастую, подсказки могут быть очень полезны при отладке сайта в целом, но при отладке в критических ситуациях они, в основном, несут малополезную информацию да ещё и в огромном количестве.
Затем мы переопределяем вывод ошибок в стандартный поток браузера посетителя ini_set(«error_log»,»»);.
Примечание автора: вторым параметром здесь можно передать абсолютный путь к файлу, доступному на запись, и весь поток ошибок будет перенаправлен в него.
Всё бы хорошо, но есть определённые критичные ошибки, связанные с работой самого интерпретатора, которые могут вызвать прерывание в работе скрипта, и не будут выведены в поток обозревателя посетителя. Вот такой загадочный он наш PHP.
Но, благо, с версии 5.2 (о чудо!), заявленная ещё в php 4, функция-перехватчик register_shutdown_functionзаработала!.
Описание функции register_shutdown_function:
(void) register_shutdown_function ( callback $function ) — принимает имя функции $function, которая выполняется по завершении исполнения кода, даже во время возникновения критичной ошибки с прерыванием работы скрипта.
Примечание автора: в данном случае функция $function должна быть определена (или подключена) до передачи в register_shutdown_function.
Определим функцию errPrint, которая распечатает последнюю ошибку print_r(error_get_last()) после завершения скрипта. И передадим название этой функции обработчику register_shutdown_function:
<?php register_shutdown_function("errPrint"); ?>
Описание функции error_get_last:
(array) error_get_last ( void ) – возвращает в виде массива информацию о последней случившейся ошибке. Массив содержит ключи «type» – тип ошибки, «message» – подробное сообщение об ошибке, «file» – путь к файлу, в котором произошла ошибка, «line» – номер строки, в которой произошла ошибка и номер символа.
А в нашем случае, последняя «случившаяся» ошибка – и есть та самая, которая приводит к остановке выполнения скрипта. Благодаря такому подходу можно будет «отловить» буквально любую ошибку и получить детальную информацию о ней.
Не забывайте отключать информацию о выводе ошибок в браузер пользователя!
Но, после отладки php скрипта и устранения критичной ошибки, не забывайте отключить полностью информацию о выводе ошибок в браузер пользователя. Связано это как с соображениями безопасности, а так же могут препятствовать нормальной инициализации сессий и работе функций, передающих заголовки header.
Так и с эстетической точки зрения не стоит выводить много малопонятной информации в браузер посетителя Вашего сайта. Для этого можно подавить полностью вывод ошибок. Или же переопределить вывод ошибок в файл с помощью функции ini_set(«error_log»,»путь к файлу ошибок, доступному на запись»);. При этом желательно, чтобы этот файл находился вне папок Вашего сайта, или доступ к файлу извне был полностью ограничен.
Приведём код полного подавления ошибок:
<?php ini_set("error_reporting",0); ini_set("display_errors",0); ini_set("error_log","путь к файлу хранения ошибок"); ?>
Так же для некоторых функций, которые всё равно генерируют ошибки и предупреждения, можно использовать оператор подавления ошибок. Для этого достаточно перед именем функции указать: @, например:
<?php @mkdir("/site/cahce",0777); ?>
Хотя, настоятельно рекомендую Вам вместо этого «ленивого» способа с помощью условных операторов обработать все ситуации, которые приводят к появлению данной ошибки. Это добавит стабильности и увеличит «запас прочности» Ваших скриптов во время возникновения внештатных ситуаций, и оставит меньше «почвы для размышления» злоумышленникам.
Помните: внимательная и скрупулёзная разработка сайтов цена вашей репутации!
Я всё равно вижу белую страницу!
Здесь может быть несколько причин:
- Данный подход универсален для php 5.2 и выше. Для того, чтобы узнать версию Вашего PHP интерпретатора, добавьте в Ваш скрипт вызов функции phpinfo();
<?php phpinfo(); ... ?>
В первых строках будет описана версия PHP.
- Если у Вас версия PHP выше 5.2, но белая страница всё-таки продолжает появляться с настроенным выводом ошибок, значит Ваш скрипт автоматически завершается сервером (Вы превышаете ресурсы процессорного времени, происходит не обрабатываемая критическая ситуация в одной из библиотек PHP и т.п.). В данном случае советую Вам обратиться к хостеру за предоставлением логов ошибок и нагрузки.
- Но если Вы не нашли ничего полезного и в логах, предоставленных хостером — самая последняя инстанция: пошаговая отладка с помощью функций принудительной остановки exit или die в «проблемных местах» и распечаткой нужной информации обнаружить «неустойчивый код», и переписать его с учётом меньшей нагрузки.Приведём пример выполнения пошаговой отладки с простой установкой флагов состояний:
<?php function add_user_avatar($user_id,$avatar_name,$watermark){ ... }; echo "вызов функции add_user_avatar"; add_user_avatar($user_id,$avatar_name,$watermark); echo "окончание работы функции add_user_avatar"; die(); ?>
Если же Вы увидели белый лист раньше отображения «окончание работы функции add_user_avatar», значит проблему стоит искать именно в ходе выполнения данной функции add_user_avatar. Если же нет, мы «передвигаем» функцию die или exit ниже, обозначая вызов и завершение далее следующих функций подобным способом.
А в следующих статьях мы рассмотрим с Вами, как написать собственный перехватчик ошибок и расширить ресурсы, выделяемые хостингом для работы наших скриптов.