Налаштування логів в php. Ведення лог файлу відвідувачів Log файл php
На сер'езних сайтах дивно бачити, коли помилки виводяться користувачеві в браузер в найнесподіваніших місцях. Чому вони з'являються - це окрема розмова. Але чому вони виводяться? Адже текст помилок є інформацією для дебага і призначена для розробника, а не для клієнта.
Крім того, саме ця службова інформація зазвичай допомагає злим хакерам ламати сайт. Як класичний приклад можна привести варіант з висновком запиту при помилці: "you have an error in query near WHERE id \u003d" ... Велике спасибі. Підставляємо після "WHERE id \u003d ..." рядок "0 OR 1\u003e 0" і запит виконується по всій таблиці. Якщо запит на видалення, то ... самі розумієте, весело \u003d). Тому я завжди змінні в запитах роблю висновок в лапки. На всякий випадок...
Але я захопився. Сьогодні не про це. Сьогодні поговоримо про те, як уникнути виведення помилок клієнту, зберігши при цьому всі повідомлення вебмайстру на пам'ять.
Почнемо, мабуть, з короткого огляду видів помилок в РНР.
Таблиця 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 параметрів:
- код помилки
- текст помилки
- ім'я файлу, в якому сталася помилка
- рядок в файлі
- масив змінних
Повертати ця функція нічого не зобов'язана. Так як ми збираємося переглядати потім лог помилок, то треба зробити запис логу, наприклад, в файл так, щоб нам потім було зручно з ним працювати.
\u003d (LOG_FILE_MAXSIZE * 1024)) (// перевіряємо настройки, якщо встановлено лог_ротейт, // то "зрушує" старі файли на один вниз і створюємо порожній лог // якщо немає - чистимо і пишемо замість старого балки if (LOG_ROTATE \u003d\u003d\u003d true ) ($ i \u003d 1; // вважаємо старі логи в каталозі while (is_file (LOG_FILE_NAME. ".". $ i)) ($ i ++;) $ i--; // у кожного з них по черзі збільшуємо номер на 1 while ($ i\u003e 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); )?\u003e
Можна було б, звичайно, використовувати більш логічне для таких цілей сховище - базу, але ж помилки, в більшості своїй, виникають саме при роботі з базою, тому я б на неї не покладався.
Власне, це все. Усе інше, я думаю, не складе для вас праці, особливо, якщо користуватися функціями file (); & Explode (); . А якщо все-таки складе, то ви можете скористатися [ось цим кодом].
Передбачаючи питання "чому я не використовував CSV, який, здавалося б, логічно використовувати в цій ситуації?", Відповідаю: повідомлення про помилки можуть містити невідому кількість службових символів (ака ком і крапок з комою), що явно ускладнило б розбір CSV. Та й не збираюся я переглядати лог в Ексель.
Ще різні думки на цю тему:
- при устаревании балки gz "іповать файл і складати його в архів;
- то ж, але з посилкою на пошту;
- при виникненні критичних помилок - слати мейл (див. приклад з мануала по функції
У кожному реальному PHP додатків час від часу виникають помилки і виключення, вискакують попередження, повідомлення. Якщо ми не будимо записувати цю інформацію (Залогуватися), то в один прекрасний момент стане неможливим зрозуміти, в який же частині додатка виникають ці помилки і виключення, і, відповідно, не зможемо вирішити їх. До того ж, існують такі ситуації, коли логирование подій, дій просто необхідно, як у випадку, з входом користувача в систему і виходом з неї, наприклад.
В PHP вже існують необхідні кошти для журналирования: функція error_log () - для відправки повідомлення в системний журнал, функція set_error_handler (), Для перехоплення попереджень і помилок. Ці функції можуть бути використані для призначеного для користувача керування помилками, даючи розробнику коду можливість самостійного управління логікою обробки і фільтрації помилок.
Однак такий низькорівневий доступ призводить до частого дублювання коду, і що ще більш важливо, такий код більш схильний до помилок. Тому на допомогу програмісту приходять вже готові компоненти, добре протестовані і зарекомендували себе в "бойових" умовах.
До таких компонентів відноситься компонент zend-log з фреймворка Zend. компонент zend-log може бути використаний в якості багатоцільового компонента логування, такий собі майстер на всі руки. Він підтримує безліч форматів журнальних повідомлень і різновидів баз логування (файли, бази даних), плюс до всього має опрацьовану систему фільтрації повідомлень і багато чого ще. також zend-log сумісний з PSR-3 стандартом логування. Встановлюється так:
Сomposer require zendframework / zend-log
Використовується в такий спосіб (для прикладу використовується файл index.php в корені проекту):
Require "vendor / autoload.php";
Use Zend \\ Log \\ Logger;
use Zend \\ Log \\ Writer \\ Stream;
$ Logger \u003d new Logger;
// відправляємо помилки в консоль
$ Writer \u003d new Stream ( "php: // ouput");
$ Logger -\u003e addWriter ($ writer);
$ Logger -\u003e log (Logger :: INFO, "Якась інформація");
Результат виконання коду вище:
2017-09-26T10: 40: 34 + 03: 00 INFO (6): Якась інформація
Підсумковий рядок включає час події, пріоритет і повідомлення. Формат виведеного повідомлення, безумовно, може бути змінений, якщо буде потреба з допомогою методу setFormatter (). За замовчуванням, рядок логу описується наступним шаблоном:
% Timestamp%% priorityName% (% priority%):% message%% extra%
- % Timestamp% - це мітка часу
- % PriorityName% - текстова мітка пріоритету
- % Priority% - числова мітка пріоритету
- % Message% - повідомлення
- % Extra% - необов'язкове значення для додаткової інформації
Якщо Ви захочете змінити формат повідомлення, то це робиться в такий спосіб:
$ Formatter \u003d new Zend \\ Log \\ Formatter \\ Simple ( "повідомлення% message%". PHP_EOL);
$ Writer -\u003e setFormatter ($ formatter);
компонент zend-log може бути також використаний для логування помилок і виключень самого інтерпретатора PHP. Для цього в класі Logger існую два статичних методу: Logger :: registerErrorHandler ($ logger) - для перехоплення помилок і Logger :: registerExceptionHandler ($ logger) - для перехоплення виключень.
Use Zend \\ Log \\ Logger;
use Zend \\ Log \\ Writer;
$ Logger \u003d new Logger;
$ Writer \u003d new Writer \\ Stream (__ DIR__. "/Test.log");
$ Logger-\u003e addWriter ($ writer);
// Залогуватися помилки
Logger :: registerErrorHandler ($ logger);
// Залогуватися виключення
Logger :: registerExceptionHandler ($ logger);
Як згадувалося раніше, zend-log надає нам можливість фільтрації повідомлень для логування, тобто перед тим як записати повідомлення в лог, ми може подивитися чи задовольняє воно нашим критеріям, і якщо так, то записуємо.
Ось приклад:
$ Filter \u003d new Zend \\ Log \\ Filter \\ Priority (Logger :: CRIT);
// метод addFilter інтерфейсу Writer
$ Writer-\u003e addFilter ($ filter);
В даному прикладі, ми будемо Залогуватися тільки ті повідомлення, чий пріоритет менше або дорівнює критичного ( Logger :: CRIT).
Повний список пріоритетів, визначених в класі Zend \\ Log \\ Logger:
Const EMERG \u003d 0; // Аварія: система непридатна для використання
const ALERT \u003d 1; // Тривога: терміново необхідно вживати заходів
const CRIT \u003d 2; // Критична ситуація
const ERR \u003d 3; // Помилка
const WARN \u003d 4; // Попередження
const NOTICE \u003d 5; // Увага
const INFO \u003d 6; // Інформація
const DEBUG \u003d 7; // Дебаг, налагодження
Ми також можемо фільтрувати повідомлення на основі регулярних виразів, тимчасових міток і т.д. Таким чином, логирование в PHP - це важлива і часом необхідна річ при розробці web-додатків.
В інтернеті існує велика кількість сервісів, що надають послуги з обліку відвідуваності Вашого сайту. Дані послуги надаються як платно, так і безкоштовно. Наприклад, можна привести LiveInternet. Цей сервіс досить широкий в інтернеті і майже кожен сайт користується його послугами. Власник має детальну статистику про відвідування його сайту.
Безперечно! Дані сервіси незамінні в обліку відвідуваності сайту і подальшого вивчення поведінки користувачів. Але в даній статті я хочу розповісти, як можна зробити на сервері лог-файл візитів відвідувачів.
Лог-файл візитів
Даний лог файл буде дуже корисний, для обліку візитів і переглядів відвідувачами Ваш сайт. Для створення лог-файлу використовується скрипт, написаний на мові php. Скрипт досить простий в розумінні та встановлення на сайт.
Скрипт php для створення лог-файлу
Скрипт записує точний час заходу на сайт, визначає браузер відвідувача, і що найголовніше - визначає звідки прийшов відвідувач до Вас. Запис лог-файлу відбувається при кожному відображенні до тієї чи іншої сторінки сайту. Тобто, власник сайту може подивитися в лог файлі які конкретно переглядав сторінки сайту відвідувач за певним IP і часу, використовуючи певний браузер.
Лістинг скрипта записи даних в лог-файл
$er_time=date("H:i:s d M Y"); // Записываем текущую дату обращения на сайт $U=getenv("HTTP_USER_AGENT"); // Узнаем какой браузер использует посетитель $H=getenv("HTTP_REFERER"); // Получаем адрес ulr откуда прищел посетитель $R=getenv("REMOTE_ADDR"); // Получаем IP адрес посетителя $W=getenv("REQUEST_URI"); // Получаем адрес страницы, которую запросил пользователь $f=fopen("logs/users.log","a"); // Указываем путь до лог-файла flock ($f,2); fwrite($f,"$er_time\n Br: $U\n Rf: $H\n IP: $R\n Rq: $W\r\n"); // Запись полученных данных в файл \r\n\ указывает на запись с новой строчки в файле. Данная операция будет выполняться при каждом открытие страницы. fclose($f); // Закрытие файла?>установка скрипта
Збережіть скрипт в шаблоні, або в зовнішньому файлі users.php. Для того, щоб вставити скрипт в сторінку використовуйте наступний код.
Під логування в PHP мається на увазі те, про яких типах помилок буде повідомляти вам ваше веб-додаток / сайт / php-скрипт і яким чином.
Існує 2 (3) основні способи отримання помилок від програми:
- Висновок цих помилок безпосередньо на екран
- Запис цих помилок в спеціальний лог-файл
- або ж відразу обидва варіанти: висновок цих помилок на екран і запис їх в спеціальний лог-файл
Як правило, практикується таке, що при розробці (на локальному оточенні) всі помилки показуються прямо на екрані, щоб їх було легше і оперативніше відловлювати і виправляти, а в бойовому середовищі (на продакшені) помилки не показуються взагалі (тому що для користувача - це даремна інформація) і вся інформація про них пишеться в лог-файл, який розробник регулярно переглядає.
Налаштування для логування помилок
- 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 () передавши в неї, відповідно, необхідний параметр і значення для нього.
- display_errors - цей параметр відповідає за безпосередній показ помилок на екрані після того, як вона, власне, відбулася. Даний параметр може мати значення 0 або 1 або On / Off. Тобто або показувати помилки на екрані, або ні.
- display_startup_errors - ця опція відповідає за показ помилок, що сталися після запуску PHP. Наприклад, якщо в файлі конфігурації є синтаксична помилка, то інформація про неї буде показана. Даний параметр може мати значення 0 або 1 або On / Off.
- log_errors - дана директива відповідає за те, щоб записувати повідомлення про помилки в лог-файл. Даний параметр може мати значення 0 або 1 або On / Off. Тобто записувати помилки в лог або ж немає.
- error_log - це налаштування відповідає за шлях до файлу (лог-файлу), в який будуть записуватися всі відбулися помилки програми
- 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 або ж у файлі вашого віртуального хоста.