Jak mozna wyczytac z tytulu zastanawiam sie nad optymalnym rozwiazaniem oblugi bledow w CMSie. (mowa o php 4 - no exceptions)
Obsluga bledow sklada sie z dwoch podelementow:
1) Obsluga bledow skladni - zglaszanych przez silnik php i przechwytywanych przez error_handler
2) Obsluga bledow logicznych i algorytmicznych, niewykrywalnych dla php. Zglaszanych z poziomu kodu.
Martwia mnie obydwa problemu, ale z roznych wzgledow. Pierwszy, dlatego, ze php zglasza szalenie mala ilosc informacji o bledzie (np. nie ma mozliwosci uzyskania inforamcji o linii w ktorej nastapil blad!!!).
Drugi, z powodu (tak podejrzewam) malego doswiadcznia z tematem.
Na poczatku nie wiedzialem wogule jak podejsc do tematu i lazilem wokol niego jak pies wokol jeza. W koncu sprecyzowalem zalozenia obslugi bledow. Musi obslugiwac jak najwiekszy zakres bledow, kontrolowac stabilnosc aplikacji, obslugiwac "tranzakcje" (*1) oraz w jak najlatwiejszy sposob integrowac sie z CMSem (*2).
*1) chodzi o system podobny do uzywanego w bazach danych. Jesli kawalek kodu ma wykonac logiczna operacje "dodania konta" ktora sklada sie z dodania wpisu do tablicy |accounts|, dodania wpisu do tablicy |account_privs| oraz dodania dwoch katalogow (zalozmy!!) to fajnie by bylo, moc to latwo wycofac jest cokolwiek pojdzie nie tak.
*2) Innymi slowy, aby latwo i czysto wygladalo w CMSie wybor czy wyswietlac dalej skrypt czy juz komunikat o bledzie.
Wstepnie zaprojektowalem cos w tym stylu:
[php:1:f44bd586cd]<?php
<?php
/**************************************************
*
* Error Class. Handling errors
*
***************************************************
*
* No table related.
*
***************************************************
*
* Detail description
* @author Zbigniew Braniecki (gandalf@przeglad.com.pl)
* @version 1.0 M1
* @copyright Zbigniew Braniecki
* @access private
* @relase_date 08.10.2002
*
***************************************************
*
* Short Description
*
* Variables:
* errorlevel - Describes status of system.
* Possible codes are:
* 0 - no error
* 1 - notice error - something might be wrong, but it miht be ok too
* 2 - warning error - something is wrong, but script works
* 3 - rollback error - error in setting data. should be rolled back and warned
* 4 - security error - there was a try of illegal access
* 5 - fatal error - module wont work.
* 6 - gcms error - gcms wont run
*
* errors - Array of errors code with modules name and description.
* "code" - Code number
* "trasaction" - which transaction was active?
* "module" - Module name
* "action" - Action
* "description" - Description
*
* Methods:
*
* SetErrorLevel($level,$force=false)
* $force - if set (boolean) New errorlevel is forced even if the old one was higher.
*
* AddError($lvl,$module,$desc)
* Adds error to array of errors
*
* AddToErrFile($module,$desc,$rubbish)
* $rubbish - if there can by any parts (sql rows or files) to clean up, write them down here.
* Adds error to error file.
*
* RunCapture()
* System captures php errors and log them.
*
***************************************************
*
* Known bugs and problems
*
***************************************************
*
* Notes
*
***************************************************/
class ErrorClass {
var $errorlevel = 0;
var $errors = Array('cms'=>Array(), 'code'=>Array());
var $debug_mode = true;
var $security = false;
var $php_errcode = Array(1=>6, 2=>5, 4=>6, 8=>1, 16=>6, 32=>5, 64=>6, 128=>5, 256=>5, 512=>5, 1024=>1, 2056=>-1);
var $transactions = Array();
function SetErrorlevel ($level, $force=false) {
if (($level>$this->errorlevel) || $force) {
$this->errorlevel = $level;
}
return true;
}
function CreateTransaction ($name) {
$this->transactions[] = Array('name' => $name, 'rollback' => Array(), 'errors'=> false);
return key($this->transactions);
}
function FinishTransaction ($id) {
unset($this->transactions[$id]);
return true;
}
function Rollback ($tr_id, $module, $method, $argList) {
$this->transactions[$tr_id]['rollback'][] = Array('module'=>$module, 'method'=>$method, 'arglist'=>$argList);
return true;
}
function AddError ($lvl, $module, $action, $desc, $tr_id=false, $type='cms') {
$GLOBALS['system']->reload = false;
$this->SetErrorlevel($lvl);
switch ($lvl) {
case 0:
$code=$GLOBALS['sysdict']['error_no_error'];
break;
case 1:
$code=$GLOBALS['sysdict']['error_notice'];
break;
case 2:
$code=$GLOBALS['sysdict']['error_warning'];
break;
case 3:
$code=$GLOBALS['sysdict']['error_rollback'];
break;
case 4:
$code=$GLOBALS['sysdict']['error_security'];
break;
case 5:
$code=$GLOBALS['sysdict']['error_major'];
break;
case 6:
$code=$GLOBALS['sysdict']['error_blow'];
break;
default:
$code=$GLOBALS['sysdict']['error_unknown'];
}
if ($tr_id === false) {
if (isset($this->transactions[key($this->transactions)])) {
$tr_name = $this->transactions[key($this->transactions)]['name'];
$this->transactions[key($this->transactions)]['errors'] = true;
$tr_id = key($this->transactions);
} else {
$tr_name = '--';
}
}elseif ($tr_id !== '--') {
if (isset($this->transactions[$tr_id])) {
$tr_name = $this->transactions[$tr_id]['name'];
$this->transactions[$tr_id]['errors'] = true;
}else{
$tr_name = '--';
}
}
$this->errors[$type][] = Array('code'=>$code, 'transaction' => $tr_name,'module'=>$module, 'action'=>$action, 'description'=>$desc);
$this->AddToErrFile ($code, $module, $action, $desc);
foreach ($this->transactions as $t) {
foreach ($t['rollback'] as $e) {
eval('$GLOBALS["'.$e['module'].'"]->'.$e['method'].'('.implode($e['arglist'], ',').');');
}
}
if ($type=='code') {
print('<br>'.$GLOBALS['sysdict']['error_code'].': ');
print_r(current($this->errors[$type]));
die($GLOBALS['sysdict']['stop']);
}
return true;
}
function AddToErrFile ($lvl, $module, $action, $desc) {
$fh=fopen('../admin/error.log','a');
fputs($fh,date('[d-m-Y H:i]').' '.$GLOBALS['sysdict']['error'].' ('.$lvl.') '.$GLOBALS['sysdict']['in_module'].' - '.$module.' '.$GLOBALS['sysdict']['in_action'].' - '.$action.' - '.$desc."n");
fclose($fh);
}
function RunCapture(){
function ErrorHandler ($errno, $errstr, $errfile, $errline, $errcontexa) {
global $error;
$error->SetErrorlevel($error->php_errcode[$errno]);
$error->AddError($error->php_errcode[$errno], ' - ', ' - ', $GLOBALS['sysdict']['in_file'].' '.$errfile.', '.$GLOBALS['sysdict']['in_line'].' '.$errline, false, $GLOBALS['sysdict']['code']);
}
set_error_handler('ErrorHandler');
return true;
}
// DONE - 08.10.2002
///////////////////////////////////////////////////////
}
?>
?>[/php:1:f44bd586cd]
(sysdict to slownik CMSa)
uzycie:
[php:1:f44bd586cd]<?php
$tr_id = $errors->CreateTransaction('Adding Account');
if (!mysql_query($q_tmp)) {
$errors->AddError(3, 'Account', 'Adding Account', 'Account was not added due too Mysql Error nr. '.mysql_errno().' - '.mysql_error(), $tr_id);
return false;
}
$curr_id = mysql_insert_id();
$errors->Rollback($tr_id, 'account', 'Remove', Array($curr_id)); // For both
if (!$access->SetPrivileges($curr_id)) {
$errors->AddError(3, 'Account', 'Adding Account', 'Setting Privilages failed', $tr_id);
return false;
}
$errors->FinishTransaction($tr_id);
?>[/php:1:f44bd586cd]
Czyli na ludzki:
1) Rozpocznij tranzakcje
2) Dodaj konto do bazy - jesli sie nie powiedzie zwroc blad (tranzakcja zostanie zatrzymana, ale nie cofnieta - brak Rollbacka)
3) Dodaj rollback
4) dodac uprawnienia - jesli padnie tranzakcja zostanie cofnieta i rollback uruchomiony
.
. tutaj mozna dodawac kolejne elementy
.
n) Zakoncz tranzakcje.
Moj problem jest prosty. Chcialbym Was prosic o pomoc w udoskonaleniu tego, oczyszczeniu... bo napisalem to pewien czas temu i do dzis nie mam pomyslu jak to usprawnic. Mam ogromna nadzieje, ze swierze spojrzenie na problem waszych oczu popchnie cala sprawe do przodu.

Bede wdzieczny za kazda sugestie

P.S. Zastanawialem sie czy to nie do Oceny, ale zamiast oceny wolalbym teoretyczna chocby dyskusje o samych zalozeniach takiego errorHandlera... moze ja wogule w zla strone ide?