Php логирование в файл. Логирование в PHP с помощью Zend Log

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

Кроме того, именно эта служебная информация обычно помогает злым хакерам ломать сайт. В качестве классического примера можно привести вариант с выводом запроса при ошибке: "you have an error in query near WHERE id= " ... Большое спасибо. Подставляем после "WHERE id=..." строку "0 OR 1>0" и запрос выполняется по всей таблице. Если запрос на удаление, то...сами понимаете, весело =). Поэтому я всегда переменные в запросах заключаю в кавычки. На всякий случай...

Но я увлекся. Сегодня не об этом. Сегодня поговорим о том, как избежать вывода ошибок клиенту, сохранив при этом все сообщения вебмастеру на память.

Начнем, пожалуй, с краткого обзора видов ошибок в РНР.

Таблица 1. Описания ошибок в PHP4 (оригинальный список)
Числовое
значение
Константа Описание Ловится/нет
1 E_ERROR Фатальные ошибки. Например, ошибка при обращении к памяти. Выполнение скрипта при этом прерывается. нет
2 E_WARNING Предупреждения (не фатальные ошибки). Выполнение скрипта не прерывается. да
4 E_PARSE Ошибки во время анализа синтаксиса. Генерируются парсером. нет
8 E_NOTICE Замечания (менее серьезные ошибки, чем предупреждения). Указывают на ситуацию, которая может стать причиной более серьезной ошибки, но могут случаться и в процессе нормальной работы скрипта. да
16 E_CORE_ERROR Ошибки во время загрузки РНР. Аналог E_ERROR, генерируется ядром РНР. нет
32 E_CORE_WARNING Предупреждения во время загрузки РНР Аналог E_WARNING, генерируется ядром РНР. нет
64 E_COMPILE_ERROR Фатальные ошибки во время компиляции кода. Аналог E_ERROR, генерируется зендовским движком. нет
128 E_COMPILE_WARNING Предупреждения во время компиляции кода. Аналог E_WARNING, генерируется зендовским движком. нет
256 E_USER_ERROR Пользовательская ошибка. да
512 E_USER_WARNING Пользовательское предупреждение. да
1024 E_USER_NOTICE Пользовательское замечание да

Нас интересуют те ошибки, которые мы можем перехватить. К ним относятся: E_WARNING, E_NOTICE и E_USER_*. Остальные виды ошибок перехвату не поддаются либо из-за того, что происходят они еще до окончания загрузки самого ядра РНР, либо из-за того, что происходят на этапе синтаксического анализа и компилирования РНР-кода, поэтому их вывод придется просто отключить:

ini_set ("display_errors",0);

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

По умолчанию уровень ошибок в РНР имеет значение E_ALL & ~E_NOTICE (или 2039 в числовой форме), что означает, что мы пропускаем мимо ушей замечания, но сообщаем о всех остальных ошибках.

Поэтому изменим уровень вывода ошибок на E_ALL:

error_reporting (E_ALL);

Теперь переопределим хэндлер ошибок и подставим вместо него нашу функцию , которая и будет заниматься теперь обработкой ошибок:

set_error_handler ("user_log");

Рассмотрим эту функцию подробней. Ей передаются 5 параметров:

  • код ошибки
  • текст ошибки
  • имя файла, в котором произошла ошибка
  • строка в файле
  • массив переменных

Возвращать эта функция ничего не обязана. Так как мы собираемся просматривать потом лог ошибок, то надо сделать запись лога, например, в файл так, чтобы нам потом было удобно с ним работать.

=(LOG_FILE_MAXSIZE*1024)) { //проверяем настройки, если установлен лог_ротэйт, //то "сдвигаем" старые файлы на один вниз и создаем пустой лог //если нет - чистим и пишем вместо старого лога if (LOG_ROTATE===true) { $i=1; //считаем старые логи в каталоге while (is_file(LOG_FILE_NAME.".".$i)) { $i++; } $i--; //у каждого из них по очереди увеличиваем номер на 1 while ($i>0) { rename(LOG_FILE_NAME."..".$i,LOG_FILE_NAME. "." .(1+$i--)); } rename (LOG_FILE_NAME,LOG_FILE_NAME.".1"); touch(LOG_FILE_NAME); } elseif(is_file(LOG_FILE_NAME)) { //если пишем логи сверху, то удалим //и создадим заново пустой файл unlink(LOG_FILE_NAME); touch(LOG_FILE_NAME); } } /* проверяем есть ли такой файл если нет - можем ли мы его создать если есть - можем ли мы писать в него */ if(!is_file(LOG_FILE_NAME)) { if (!touch(LOG_FILE_NAME)) { return "can\"t create log file"; } } elseif(!is_writable(LOG_FILE_NAME)) { return "can\"t write to log file"; } //обратите внимание на функцию, которой мы пишем лог. error_log($err_str, 3, LOG_FILE_NAME); } ?>

Можно было бы, конечно, использовать более логичное для таких целей хранилище - базу, но ведь ошибки, в большинстве своем, возникают именно при работе с базой, поэтому я бы на нее не полагался.

Собственно, это все. Остальное, я думаю, не составит для вас труда, особенно, если пользоваться функциями file (); & explode (); . А если все-таки составит, то вы можете воспользоваться [вот этим кодом ].

Предвидя вопрос "почему я не использовал CSV, который, казалось бы, логично использовать в этой ситуации?", отвечаю: сообщения об ошибках могут содержать неизвестное количество служебных символов (ака запятых и точек с запятой), что явно затруднило бы разбор CSV. Да и не собираюсь я просматривать лог в Экселе.

Еще разные мысли на эту тему:

  • при устаревании лога gz"иповать файл и складывать его в архив;
  • то же, но с посылкой на почту;
  • при возникновении критических ошибок - слать мэйл (см. пример из мануала по функции

Под логированием в PHP подразумевается то, о каких типах ошибок будет сообщать вам ваше веб-приложение/сайт/php-скрипт и каким образом.

Существует 2 (3) основных способа получения ошибок от приложения:

  1. Вывод этих ошибок непосредственно на экран
  2. Запись этих ошибок в специальный лог-файл
  3. или же сразу оба варианта: вывод этих ошибок на экран и запись их в специальный лог-файл

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

Настройки для логирования ошибок

  1. error_reporting — это самый главный параметр. Он отвечает за то, сообщения об ошибках каких типов будут отображаться/писаться в лог-файл.Я считаю, что тут существует только 2 опции, которые возможно использовать:
    • -1 (или E_ALL) — сообщается обо всех типах ошибок;
    • 0 — не сообщается ни о каких типах ошибок

    Я рекомендую использовать исключительно -1 (или E_ALL).
    Т.к. приложение не должно иметь никаких ошибок, в принципе. Эту опцию можно задать через конфигурационный файл в php.ini или же прямо в php-скрипте посредством вызова функции error_reporting :

    Error_reporting(-1); error_reporting(E_ALL);

    Кстати говоря, это единственная опция, которая имеется в языке PHP в виде функции. Все остальные опции возможно задать исключительно при помощи правки конфигурационного файла php.ini или же вызова функции ini_set() передав в неё, соответственно, необходимый параметр и значение для него.

  2. display_errors — этот параметр отвечает за непосредственный показ ошибок на экране после того, как она, собственно, произошла. Данный параметр может иметь значение 0 или 1 либо On / Off. Т.е. либо показывать ошибки на экране, либо нет.
  3. display_startup_errors — эта опция отвечает за показ ошибок, произошедших после запуска PHP. Например, если в конфигурационном файле есть синтаксическая ошибка, то информация о ней будет показана. Данный параметр может иметь значение 0 или 1 либо On / Off.
  4. log_errors — данная директива отвечает за то, чтобы записывать сообщения об ошибках в лог-файл. Данный параметр может иметь значение 0 или 1 либо On / Off. Т.е. записывать ошибки в лог или же нет.
  5. error_log — данная настройка отвечает за путь к файлу (лог-файлу), в который будут записываться все произошедшие ошибки приложения
  6. html_errors — эта же опция отвечает за формат отображения ошибок приложения. Если задана как 1 или On, то ошибка будет показана при помощи HTML’а, т.е. будет trace происхождения ошибки и всё будет достаточно информативно и красочно. Если же значение этой настройки задано как 0 или Off, то ошибки будут отображаться в виде обычного текста в виде небольшого числа строк.

1. Настройки для отображения ошибок на экране




ini_set("html_errors", 1);
ini_set("log_errors", 0);

2. Настройки для записи ошибок в лог-файл

Error_reporting(-1); // ini_set("error_reporting", -1);
ini_set("display_errors", 0);
ini_set("display_startup_errors", 0);
ini_set("log_errors", 1);

3. Настройки для одновременного отображения ошибок и их записи в лог-файл

Error_reporting(-1); // ini_set("error_reporting", -1);
ini_set("display_errors", 1);
ini_set("display_startup_errors", 1);
ini_set("log_errors", 1);
ini_set("html_errors", 1);
ini_set("error_log", "/var/log/php/error.log");

Так же, эти опции можно задать и в конфигурационном файле php.ini или же в файле вашего виртуального хоста.

В интернете существует большое количество сервисов, предоставляющие услуги по учету посещаемости Вашего сайта. Данные услуги предоставляются как платно, так и бесплатно. К примеру, можно привести LiveInternet. Этот сервис довольно широкий в интернете и почти каждый сайт пользуется его услугами. Владелец имеет подробную статистику о посещении его сайта.

Спору нет! Данные сервисы незаменимы в учете посещаемости сайта и дальнейшего изучения поведения пользователей. Но в данной статье я хочу рассказать, как можно сделать на сервере лог-файл визитов посетителей.

Лог-файл визитов

Данный лог файл будет очень полезен, для учета визитов и просмотров посетителями Ваш сайт. Для создания лог-файла используется скрипт, написанный на языке php. Скрипт довольно простой в понимании и установке на сайт.

Скрипт php для создания лог-файла

Скрипт записывает точное время захода на сайт, определяет браузер посетителя, и что самое главное – определяет откуда пришел посетитель к Вам. Запись лог-файла происходит при каждом отображении к той или иной страницы сайта. То есть, владелец сайта может посмотреть в лог файле какие конкретно просматривал страницы сайта посетитель по определенному IP и времени, используя определенный браузер.

Листинг скрипта записи данных в лог-файл

Установка скрипта

Сохраните скрипт в шаблоне, либо во внешнем файле users.php. Для того, чтобы вставить скрипт в страничку используйте следующий код.

Большинство всех вопросов на сайте начинаються "Помогите, не работает, не запускается...". Все ответы сводяться к подсказкам и советам, а вот почему мне раньше не пришло в голову написать статтью о том, как и где искать ошибки или об использовании логов я не знаю. Поэтому восполняем пробел и всем советую ознакомится с этой статье.

Лог (логи ) — (англ. log , возможно Вы встречали раньше файлы *.log ) как правило, текстовый файл в котором в хронологическом порядке идет перечень событий, журнал событий, дневник, запись, протокол т.д. Логи создаются различными программами, сервисами, операционными системами. Для каждой программы может создаваться свой лог (текстовый файл).

При разработке сайта, для веб разработчика ценными будут логи созданые:
1. логи на уровне операционной системы :
- Мой компьютер — Панель управления — Административные инструменты — Просмотр событий
- Мой компьютер — Выполнить - "eventvwr.msc"


Сюда попадают записи о все события в операционной системе Windows. В том числе, здесь, на вкладках:
- Custom Views / Administrative events
- Windows Logs / System

Вы можете найти логи связаные с сервисом Apache (если веб сервер Apache запущен как сервис) и другие ошибки вызваные, например, расширениями (extension) php. По большому счету сюда заносяться все ошибки Windows. Apache, как сервис, считается часть Windows, поэтому если при запуске сервиса Apache возникает какая-угодно ошибка, Вам нужно искать расшифровку и этой ошибки здесь . Далее, если расшифровка ошибки в логах, не дает Вам понять в чем же сообственно проблема, скопируйте основные части лога в google и ищите похожие проблемы. С большой вероятностью Вы найдете ответы, которые Вам помогут. При запуске любой игры, программы, сервиса, когда возникает ошибка, в логах появляеться новая запись с более детальным описанием ошибки. Отталкиваясь от этого Вы всегда можете найти ответ в интернете.

2. логи на уровне Apache :
помимо Windows логов, сам Apache создает собственный лог в ввиде текствого файла. При установке и настройке веб сервера Apache в файле httpd.conf есть строка: ErrorLog "C:/apache/error.log" где, "C:/apache/error.log" путь к файлу-логу веб сервера Apache. Установите свой путь или просто запомните, в случае возникновения ошибок при запуске Apache, Вам нужно открыть этот файл и найти последние записи, где будут отражаться причины ошибок. Помимо этого веб сервер Apache позволяет создавать логи отдельно для каждого виртуального хоста. Пример виртуальных хостов в файле conf/extra/httpd-vhosts.conf :


DocumentRoot "C:/apache/symfony/www/web"
ServerName symfony
ServerAlias www.symfony
ErrorLog "C:/apache/symfony/error.log"
CustomLog "C:/apache/symfony/access.log" common


DocumentRoot "C:/apache/phpmyadmin"
ServerName phpmyadmin
ServerAlias www.phpmyadmin
ErrorLog "C:/apache/phpmyadmin/error.log"
CustomLog "C:/apache/phpmyadmin/access.log" common

3. логи на уровне php :
при настройке конфигурации php в файле php.ini , для настройки отображения логов, находим следующие строки:

error_reporting = E_ALL & ˜E_NOTICE & ˜E_STRICT //виды и типы логируемых отображаемых ошибок
log_errors = On //включаем логирование
log_errors_max_len = 1024 //определяем максимальный размер файла логов (1024 байт)
error_log = php_errors.log //указываем имя файла в котором будут сохраняться логи, эти файлы будут создаваться в корне Вашего виртуального хоста. Для каждого хоста будет создан свой файл.

Помимо того, что в файл будут записываться все php ошибки, Вы также можете создавать логи во время выполнения php скрипта с помошью функции error_log . Это может быть полезно, если Вы активно используете в коде try … catch, в таком случає, скрипты не будут завершаться в случае критических ошибок, а в логах всегда будут отмечены все непредвиденные ошибки.

try {
$r = 5/0;
} catch (Exception $exc) {
error_log($exc->getMessage());
}

По результатам выполнения этого кода, в файл логов php_errors.log будет вставлена строка на подобии такой:

PHP Warning: Division by zero in C:\apache\test\www\index.php on line 5

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

483