А это клавиатура, с помощью которой я творю...
http://kurepin.ru/php/slang.ru/10/
Rambler's Top100
Строим сайт slang.ru, глава 10

Строим сайт slang.ru

Глава 10. class_utils: журнал операций и обработка ошибок


Ну что, распишем некоторые функции в классе class_utils? А почему бы и нет. Тем более что этот класс в нашем ООП-древе идет сразу за class_mysql.

log_insert().

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

create table tbl_log
(
 l_id       bigint unsigned not null auto_increment primary key,
 l_user     smallint unsigned not null default 0,
 l_dt       datetime not null,
 l_action   smallint not null default 0,
 l_dic      smallint not null default 0,
 l_ip       char(15) not null default '',
 l_desc     varchar(255) not null default ''
);

По строкам:
  • l_id - идентификатор записи;
  • l_user - идентификатор пользователя, совершившего действие;
  • l_dt - дата и время выполнения действия;
  • l_action - код операции;
  • l_dic - словарь, в рамках которого выполнялась операция
  • l_ip - IP-адрес компьютера, с которого было выполнено действие;
  • l_desc - комментарий к действию в свободном текстовом виде.

При необходимости, потом эту таблицу можно расширить и дополнить.

Сама функция получилась у меня такой:

u_id; // идентификатор пользователя $action=(int)$action; // только целое число $dic=(int)$dic; // только целое число $ip=$_SERVER[\'REMOTE_ADDR\']; // IP пользователя берем из окружения $desc=AddSlashes($desc); // описание ошибки может содержать кавычки $this->sql_query=\'insert into tbl_log\'; $this->sql_query.=\'(l_user, l_dt, l_action, l_dic, l_ip, l_desc) \'; $this->sql_query.=\'values(\'.$user.\', now(), \'.$action.\', \'.$dic.\', "\'.$ip.\'", "\'.$desc.\'")\'; $err=$this->sql_execute(); if($err) return($err); return(0); } ?>');?>

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

Функция очень проста, как вы видите: сбор основных данных и размещение их в таблице tbl_log нашей базы данных.

Обратите внимание на то, что переменные в объявлении функции даны с указанием значений по умолчанию. Это сделано для того, чтобы в функцию можно было передавать не все значения, а только те, которые у нас есть. Остальные переменные будут иметь значения по умолчанию, а php-интерпретатор не будет ругаться на то, что мы не все значения предали в функцию при ее вызове.

В этой функции встречается новая глобальная переменная $u_id. Она будет присваиваться в случае удачной авторизации пользователя. Пока же надо объявить ее в class_utils:

');?>

err_report() - обработчик ошибок.

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

path_info.\'/errors.txt\'; // путь к файлу с ошибками // открываем файл ошибок для чтения if($r=@fopen($file_err, \'r\')) { flock($r,1); // залочить файл на чтение while((!feof($r)) && ((int)$str-$num)) $str=fgets($r,1024); fclose($r); // закрываем файл list($found_num,$str)=explode("\t",trim($str)); } else { $str=\'no description\'; $this->err_to_support(\'0 [\'.$num.\']\',\'не удалось открыть файл \'.$file_err); $sendmail=false; } if(($found_num<=$this->debug_level) && ($sendmail)) { // отправляем письмо администратору $err=$this->err_to_support($num,$str); if($err) $err_note=\' (\'.$this->err_report(301,false).\')\'; } // формируем окончательное сообщение для пользователя $str=$str.$err_note; return($str); // возвращаем текст } ?>');?>

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

Вот это выражение понятно?

');?>

Кому не понятно, объясняю: цикл while выполняется до тех пор, пока не найден конец файла (!feof) или пока результатом вычитания из номера ошибки ($num) очередной строки (ее целочисленного начала) не станет ноль. С тем же успехом можно было написать не $str-$num, а $str!=$num.

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

; end of file

Но я решил превратить баг в фичу - записал последней строкой в файл errors.txt:

1	не определена

Таким образом, если файл удалось прочесть, а номер ошибки не был найден, описанием ошибки станет фраза "не определена".

Это весьма удобная фича, выполняющая два важных дела: первое - дает соответствующее описание неизвестным ошибками; второе - отправляет уведомление администратору, так как номер у этой ошибки - 1 - самый низкий. Видите, мы на протяжении всей функции используем переменную $num, полученную извне, а в проверке на критичность ошибки перед отправкой письма используем переменную $found_num, в которой хранится номер найденной ошибки при просмотре файла. $found_num всегда будет равна $num, кроме случая, когда описание ошибки в файле не будет найдено. На этом и сыграли.

Что будет, если не обнаружится сам файл errors.txt или если его не удастся прочесть? Будет произведена отправка соответствующего уведомления администратору, а пользователь получит номер ошибки и заглушку "no description" вместо описания. Заодно мы выставляем $sendmail в состояние "false", чтобы дважды не получать сообщение об ошибке.

При отправке письма администратору тоже производится анализ возвращенной ошибки; если письмо не было отправлено, мы рекурсивно вызываем функцию err_report(), передав ей в качестве параметра, номер ошибки и запрет на отправку письма администратору. Почему запрет? Да потому, что подобная рекурсия может превратиться в замкнутый цикл. А нам этого совсем не надо. Однако, получив ошибку отправки сообщения администратору, мы уведомляем об этом пользователя, добавив описание ошибки 301 к описанию основной ошибки.

Ошибку 301 я записал как:

301	не удалось отправить администратору сервера email-уведомление;
пожалуйста, найдите способ связаться с администрацией сервера,
чтобы сообщить номер ошибки - это очень важно!

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

Готовы идти дальше, господа программисты? Тогда - вперед!





[шаг назад] [печатать] [в начало сайта]


person:
Ru Kurepin
COPi-number:
0000 0021 / atos
Business card

реклама на сайте
copyright ©2000-2002 Ruslan Kurepin