Обробка помилок в php

Обробка помилок в PHP.

Обробка помилок за допомогою trigger_error () і set_error_handler ()


PHP надає прекрасну можливість контролювати виникають помилки. Тут ми поговоримо про те, як обробити помилку - повідомити (або не повідомити) про подію користувачеві, в разі необхідності - повідомити адміністратору за допомогою електронної пошти, записати інформацію про подію в log-файл.

Отже, для початку давайте визначимося, що таке помилки в PHP.

PHP підтримує такі рівні помилок:

E_ERROR
E_WARNING
E_PARSE
E_NOTICE
E_CORE_ERROR
E_CORE_WARNING
E_COMPILE_ERROR
E_COMPILE_WARNING
E_USER_ERROR
E_USER_WARNING
E_USER_NOTICE
E_ALL
E_STRICT

Насправді - це просто константи, які використовуються для визначення рівня обробки помилок, побудови біт-маски. Константи мають "говорять" імена. Дивлячись на константу - ми можемо сказати, що помилка рівня E_PARSE виникає в разі синтаксичної помилки, E_NOTICE - це нагадування програмісту про порушення "хорошого стилю" програмування на PHP.

Коли з'єднання з базою даних MySQL (або інший) завершується невдачею - інтерпретатор PHP повідомляє про помилку рівня E_WARNING

Warning. mysql_connect (): Access denied for user. 'VVingless @ localhost' (Using password. YES)
In / home / mysite / index. php (line 83)

Зауваження: Для того щоб інтерпретатор PHP повідомляв про помилки - PHP повинен бути налаштований відповідним чином: прапор display_errors потрібно включити - 1, директива error_reporting повинна вказувати на те, що необхідно відображати помилки рівня E_WARNING (бажано звичайно і інші). Якщо значення цих директив не задовольняють вашим вимогам - ви можете спробувати встановити їх самостійно, поклавши в папку зі скриптом файл .htaccess (точка на початку імені обов'язкове) приблизно такого змісту:


php_flag display_errors on
php_value error_reporting "E_ALL

Це означає, що повідомлення про помилки будуть показуватися, причому всіх рівнів, крім E_NOTICE
Коли програміст допускає синтаксичну помилку - інтерпретатор PHP повідомляє про помилку рівня E_PARSE


Parse error: parse error, unexpected '(', expecting T_STRING in /home/mysite/index.php on line 150

Але найцікавіші для нас рівні помилок - E_USER_ERROR і E_USER_WARNING. Як стає зрозуміло з назви - це рівні помилок, які може встановлювати користувач. Для цього існує функція trigger_error () - з її допомогою, Ви можете повідомляти користувачеві про подію так, як це робить PHP.

Як відомо з керівництва по PHP - функція trigger_error () приймає два параметри.

void trigger_error (string error_msg [, int error_type])

Перший параметр - текстове повідомлення про помилку, наприклад "файл не знайдено". Другий параметр - визначає рівень помилки. Функція trigger_error () працює тільки з сімейством помилок E_USER - це значить, що ви можете встановити помилку рівня E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE і не можете встановити помилку рівня E_WARNING. Другий параметр є необов'язковим, і за замовчуванням приймає значення E_USER_NOTICE.

Припустимо, наші дані для стрічки новин зберігаються в файлі news.txt, і якщо файл не знайдений - необхідно повідомити про помилку. Текст програми буде виглядати приблизно так:

if (! file_exists ( '/ home / mysite / news.txt')) trigger_error ( 'News file not found');
>

В результаті інтерпретатор PHP повідомить про помилку рівня E_USER_NOTICE

Notice: News file not found in /home/mysite/index.php on line 47
Але що нам це дає? Для початку те, що якщо в php.ini або файлі .htaccess були встановлені директиви

php_value log_errors "1"
php_value log_errors_max_len "+1024"
php_value error_log "/home/mysite/my.log"
То в файл /home/mysite/my.log автоматично буде додано запис про подію.

Як відомо з мануала - в PHP 4 функція приймає один єдиний строковий параметр - ім'я функції, яка буде виконуватися кожного разу, коли відбувається помилка. PHP 5 дає можливість встановити ще один параметр - тип помилок які будуть оброблятися за допомогою нашого обробника. Функція повертає рядок - ім'я функції обробника, який був встановлений до цього моменту.

string set_error_handler (callback error_handler [, int error_types])

set_error_handler ( "my_error_handler");
Користувацька функція, яка буде обробляти помилки, може приймати наступні вхідні параметри:

- код рівня помилки
- строкова інтерпретація помилки
- ім'я файлу, в якому сталася помилка
- рядок, в якій сталася помилка

Слід так само відзначити, що ця функція не може обробляти помилки рівнів E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING

Це пов'язано з тим, що помилки перерахованих рівнів відбуваються до того, як інтерпретатор отримує інформацію про призначеному для користувача обробнику помилок.

Отже, оголошуємо нашу функцію

function my_error_handler ($ code, $ msg, $ file, $ line)>

Зауваження: кожен більш-менш об'ємний скрипт зазвичай розділяється на кілька файлів для зручності роботи з ним. Як організовувати модульність програми - тема окремо розмови. Зараз же, я хочу лише порадити виділяти загальні налаштування в окремий файл, який буде підключатися на початку програми за допомогою інструкції include, або за допомогою директиви auto_prepend_file. У цей файл можна помістить і наш обробник. Установка обробника помилок повинна здійсниться якомога ближче до початку програми, бажано в самому початку.
Для того щоб переконається що це дійсно працює - створимо новий PHP файл, і спробуємо запустити його

Вміст файлу myerrortest.php

function my_error_handler ($ code. $ msg. $ file. $ line)

echo "Помилка $ msg ($ code)
n ";
echo "$ file ($ line)";
>

if (! file_exists ( '/home/mysite/news.txt')) <
trigger_error ( 'News file not found');
>


Результат обробки даного файлу буде таким:

Сталася помилка News file not found (1024)
/home/mysite/myerrortest.php (12)
Тепер у нас є функція, яка отримує дані про всі відбуваються помилки. Подумаємо, як ми можемо це використовувати.

Будемо обробляти помилки рівнів
E_ERROR
E_WARNING
E_NOTICE
E_USER_ERROR
E_USER_NOTICE

Перші три помилки в хорошій закінченою програмі не повинні відбуватися взагалі, тому про них ми будемо тільки повідомляти користувачеві висновком тексту помилки на екран. Так можна працювати, поки скрипт в стані розробки, потім повідомлення про них можна або відключити, або записувати в log-файл.

Тепер наша функція обробки помилок буде виглядати приблизно так:

// Трохи попередніх налаштувань

// встановлюємо режим відображення помилок
// відображати всі помилки, крім E_NOTICE
error_reporting (E_ALL

// ця константа відповідає за
// включення / вимикання режиму відладки
// під час налагодження - повідомлення не надсилаються
// поштою, а просто друкуються на екран
define ( 'DEBUG'. 0);

// це глобальна змінна, в якій
// буде зберігатися повідомлення, яке
// повинен бачити користувач
$ MSG = '';

// log-файл
define ( 'LOGFILE'. '/home/mysite/mylog.log');

// різниця в часі з сервером (в секундах)
define ( 'TIMEOFFSET'. 0);

function my_error_handler ($ code. $ msg. $ file. $ line)
<
// глобальна змінна, в яку буде
// записуватися повідомлення про помилку.
global $ MSG;

// пропускаємо помилки рівня E_NOTICE
// і ігноруємо помилки, якщо режим повідомлення про помилки відключений
if (($ code == E_NOTICE) or (error_reporting () == 0)) <
return;
>

// якщо ми викликали помилку рівня E_USER_NOTICE - просто
// записати текст помилки в глобальну змінну $ MSG
// і припинити виконання функції

if ($ code == E_USER_NOTICE) <
$ MSG = $ msg;
Return;
>

// якщо помилка рівня E_ERROR - друкуємо текст помилки
// і завершуємо виконання скрипта

if ($ code == E_ERROR) <
die ( '
ERROR: '. $ Msg. '
In '. $ File. '(Line'. $ Line. ')
');
>

// якщо помилка рівня E_WARNING - друкуємо текст помилки
// і припиняємо виконання функції

if ($ code == E_WARNING) <
echo '
WARNING: '. $ Msg. '
In '. $ File. '(Line'. $ Line. ')
';
Return;
>

// якщо помилка рівня E_USER_ERROR

if ($ code == E_USER_ERROR)

$ MSG = 'Критична Помилка: дія виконана не було.

Повідомлення про помилку було відправлено розробнику. ' ;

// подробиці записуємо в змінну $ text

$ Text = $ msg. '
'. 'Файл:'. $ File. '('. $ Line. ')';

// Якщо константа DEBUG встановлена ​​в 1 - друкуємо інформацію про
// помилку на екран, якщо немає - відправляємо текст помилки поштою
// функція error_mail () і пишемо в log - функція error_writelog ()

if (DEBUG == 1) <
error_print ($ text);
> else <
error_mail ($ text);
error_writelog ($ text);
>


// встановлюємо оброблювач
set_error_handler ( 'my_error_handler');

Тепер описуємо службові функції


// ф-я друкує помилку на екран
function error_print ($ text)
<
echo $ text. '

';
>

// ф-я відправляє помилку поштою
function error_mail ($ text)
<
$ Text = str_replace ( "
"." N ". $ Text);

$ Info = 'Час:'. get_datetime (). "NRemote IP:". get_ip (). "N";

mail (ADM_EMAIL. "Error reporting". $ info. $ text);
>

// ф-я пише помилку в лог
function error_writelog ($ text)
<
$ Text = str_replace ( "
"." T ". $ Text);
if (@ $ fh = fopen (LOGFILE. "a +")) <
fputs ($ fh. get_datetime (). "t". get_ip (). "t". $ text. "n");
fclose ($ fh);
>
>


// отримуємо час, з урахуванням різниці в часі
function get_time ()
<
return (date ( "H: i". time () + TIMEOFFSET));
>

// отримуємо дату, з урахуванням різниці в часі
function get_date ()
<
return (date ( "Y-m-d". time () + TIMEOFFSET));
>

// отримуємо дату і час, з урахуванням різниці в часі
function get_datetime ()
<
return get_date (). ''. get_time ();
>

// отримуємо IP
function get_ip ()
<
return ($ _SERVER [ 'REMOTE_ADDR']);
>
І нарешті приклад використання

// ф-я записує новина в файл
function write_news ($ title. $ text)
<
$ News_file = '/home/mysite/news.txt';

// перевіряємо наявність заголовка - помилка не є критичною
if (! trim ($ title))

// для того щоб визначити що функція завершилася
// невдачею - необхідно повернути false. функція
// trigger_error () - повертає true, ми будемо
// повертати її інвертований результат

return. trigger_error ( 'Необхідно вказати заголовок новини');
>

// перевіряємо наявність тексту новини - помилка не є критичною
if (! trim ($ text)) <
return. trigger_error ( 'Необхідно вказати текст новини');
>

// перевіряємо наявність файлу в який будемо писати
// якщо файл не знайдений - виникає критична помилка

if (! file_exists ($ news_file)) <
return. trigger_error ( 'Файл бази новин не знайдено!'. E_USER_ERROR);
>

//. тут попередня обробка даних.

// записуємо новина
$ Fh = fopen ($ news_file. "A +");
fputs ($ fh. $ title. "t". $ text. "n");
fclose ($ fh);

// якщо все нормально - функція повертає true
return true;
>

// намагаємося записати новина
// ці дані можуть приходити з web-форми

$ Res = write_news ( "Моя новина". "Текст моєї новини");

// якщо повернувся false - друкуємо помилку
echo $ MSG;

// якщо все в порядку - можна повідомити про це
// а краще отфорвардіть користувача абикуди.
echo 'Новина була додана';
>

Це досить простий приклад, тему можна розвивати.

Схожі статті