![]() |
![]() |
| http://kurepin.ru/php/slang.ru/10/ |
|
Строим сайт Глава 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 '' ); По строкам:
При необходимости, потом эту таблицу можно расширить и дополнить. Сама функция получилась у меня такой: highlight_string(' // журнал операций function log_insert($action=0, $dic=0, $desc=\'\') { $user=$this->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: highlight_string(' var $u_id; // идентификатор пользователя ?>');?> err_report() - обработчик ошибок. Я уже немного рассказал о том, как работает эта функция, поэтому давайте ее запишем. Она хоть и маленькая, но очень умная и полезная: highlight_string(' // обработчик ошибок function err_report($num, $sendmail=true) { $num=(int)$num; // номер ошибки должен быть целым числом $str=\'\'; // обнуляем переменную с описанием ошибки $file_err=$this->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); // возвращаем текст } ?>');?> Как это работает - читаем код. Сначала приводим переменные к правильному виду. Затем открываем файл с описанием ошибок и начинаем его читать построчно до тех пор, пока не найдем строку, начинающуюся нужным нам целым числом или пока не закончится файл. Вот это выражение понятно? highlight_string(' while((!feof($r)) && ((int)$str-$num)) $str=fgets($r,1024); ?>');?> Кому не понятно, объясняю: цикл 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-письма мне пока вполне достаточно. Если же добавлять журнал, то придется описывать ряд исключительных ситуаций, ротацию журнала и т.п. Пишите сами, если есть желание, и присылайте. Я с удовольствием добавлю ваш фрагмент в листинг, если код мне понравится. Готовы идти дальше, господа программисты? Тогда - вперед! 09.08.04 |
| реклама на сайте | ||||
|
| copyright ©2000-2002 Ruslan Kurepin |