Jump to content

Error Class


per1os

Recommended Posts

Hey all,

 

I created my own Error Class to handle most of the small errors so no user ever really sees it. Just making sure I couldn't of done something better, let me know:

 

<?php
/* Project: Aeonity
* File: class.errors.php
* Created on Jun 2, 2007 by Jim
*
* Additional comments: Error handling class, connects to DB if there is not an
* error there, if there is it will write the errors to a simple error log file.
*
*/

class errors {
	var $error_msg;
	var $error_num;
	var $error_line;
	var $error_file;
	var $error_string;
	var $mail;
	var $log;

/*
 * Builds the error data.
 */
function errors($error_num, $error_msg, $error_file, $error_line) {
	// set the logging preferences
	$this->log = CONFIG_LOG_ERRORS;
	$this->mail = CONFIG_MAIL_ERRORS;

	$this->error_msg = $error_msg;
	$this->error_num = $error_num;
	$this->error_line = $error_line;
	$this->error_file = $error_file;
	$this->error_string = $this->get_error_str($error_num);

	if ($this->log) {
		if ($this->log == "db") {
			$this->log_errors_db();
		}elseif ($this->log == "file") {
			$this->log_errors_file();
		}
	}

	if ($this->mail) {
		$this->mail_error();
	}

	$this->friendly_error_msg();
}

/*
 * Bulds the error string
 */
function get_error_str() {
	$string = "Error type: ";
	switch ($this->error_num) {
			case E_ERROR:               $string .= "Error";                  break;
			case E_WARNING:             $string .=  "Warning";                break;
			case E_PARSE:               $string .=  "Parse Error";            break;
			case E_NOTICE:              $string .=  "Notice";                 break;
			case E_CORE_ERROR:          $string .=  "Core Error";             break;
			case E_CORE_WARNING:        $string .=  "Core Warning";           break;
			case E_COMPILE_ERROR:       $string .=  "Compile Error";          break;
			case E_COMPILE_WARNING:     $string .=  "Compile Warning";        break;
			case E_USER_ERROR:          $string .=  "User Error";             break;
			case E_USER_WARNING:        $string .=  "User Warning";           break;
			case E_USER_NOTICE:         $string .=  "User Notice";            break;
			default:                    $string .=  "Unknown error ($this->error_num)"; break;
	}

	$string .= "\n<br />Error Number: " . $this->error_num . "\n<br />";
	$string .= "Error File: " . $this->error_file . "\n<br />";
	$string .= "Error Line: " . $this->error_line . "\n<br />";
	$string .= "Error Message: " . $this->error_msg . "\n<br />";

	if (isset($_SESSION['db_logged'])) {
		$this->error_string = $_SESSION['db_logged'] . $this->error_string;
	}

	if (isset($_SESSION['file_logged'])) {
		$this->error_string = $_SESSION['file_logged'] . $this->error_string;
	}

	return $string;
}


/*
 * Logs errors to the database, if it can
 */
function log_errors_db() {
	// session is to prevent an infinite loop of errors
	if ($this->log) {
		if ((!eregi("connect", $this->error_msg) && !eregi("mysql", $this->error_msg)) && !isset($_SESSION['db_logged'])) {
			$_SESSION['db_logged'] = $this->error_string;
			$sql ="INSERT INTO " . TABLE_ERRORLOG . " (`error_num`, `error_msg`, `error_file`, `error_line`, `error_string`, `error_date`) " .
					"VALUES ('" . escape_string($this->error_num) . "', '" . escape_string($this->error_msg) . "', '" . escape_string($this->error_file) . "', " .
							"'" . escape_string($this->error_line) . "', '" . escape_string($this->error_string) . "', '" . time() . "');";
			if (!query($sql)) {
				return $this->log_errors_file();
			}
		}
	}

	return true;
}


/*
 * Logs errors to the error log file, if it can.
 */
function log_errors_file() {
	if ($this->log) {
		if (!isset($_SESSION['file_logged'])) {
			$_SESSION['file_logged'] = (isset($_SESSION['db_logged']))?$_SESSION['db_logged'] . "\n\n" . $this->error_string:$this->error_string;
			$this->error_string = $_SESSION['file_logged'];
			$log_file = CONFIG_LOG_FILE;
			if ($fp = fopen(CONFIG_LOG_FILE, 'a+')) {
				fwrite($fp, str_replace("<br />", "", $this->error_string) . "\n\n");
				fclose($fp);
				unset($_SESSION['file_logged']);
			}
		}else {
			$this->mail_error();
		}
	}

	return true;
}


/*
 * Sends the errors via email if applicable
 */
function mail_error() {
	if (!CONFIG_DEV) {
		if (!isset($_SESSION['mailed_error']) && $_SESSION['mailed_error'] != $this->error_num) {
			if (isset($_SESSION['file_logged'])) {
					$this->error_string = $_SESSION['file_logged'] . $this->error_string;
			}

			$_SESSION['mailed_error'] = $this->error_num;
			send_mail(CONFIG_ERROR_EMAIL, LANG_ERROR_SUBJECT, $this->error_string);
		}
	}

	return true;
}


/*
 * Displays a friendly error message, without giving away private data
 */
function friendly_error_msg() {
	if (isset($_SESSION['db_logged'])) {
		unset($_SESSION['db_logged']);
	}

	if (isset($_SESSION['file_logged'])) {
		unset($_SESSION['file_logged']);
	}

	//echo $this->error_string;
	if (!isset($_SESSION['errormsg'])) {
		$_SESSION['errormsg'] = LANG_ERROR_FRIENDLYMSG;
		include(CONFIG_ERROR_PAGE);
		unset($_SESSION['errormsg']);
		die();
	}

}
}

function errors($error_num, $error_msg, $error_file, $error_line) {
$error = new errors($error_num, $error_msg, $error_file, $error_line);
die();
}

?>

 

Appreciate the time you take for looking at it!

Link to comment
Share on other sites

It seems like a useful class, and I think it's a pretty good overall.  If you'd like some criticism I'll try my hand, but bear in mind that what I'll criticize and the remedies I suggest may not be important given the purpose of this class.

 

At any rate the obvious thing you could improve is the series of conditionals.  For instance you have conditionals checking for the strings "db" and "file".  You also have a switch checking against the different error types.  The problem with this design is that you will have to add new conditionals each time you want to support a new error type or error handler, so for instance if you distributed this class it would be difficult for end users to extend it.

 

Solving these problems will require building potentially many levels of indirection into your code, which may not be worth it.  For instance you could replace the switch with a hash.  You would create an array where the keys were the error types and the values were the strings you wanted to concatenate, but this still requires opening the class each time you want to add a new error type, so it's not a huge improvement.  Therefore the next step would be creating a resource manager class which could open a file and generate the hash for you.  After that you could add or remove error types by editing the file, so the end user would be able to generate custom error messages and types without having to edit your code.

 

A similar thing might be done with the logging type.  The trick would be to make a strategy for the logging.  What I mean is you would create an interface with a function log($message) for example.  Then you would create two classes which implement the interface but one would be DBLog and the second FileLog.  The two would implement the log method differently.  Then you would have a hash (generated from a resource file like the switch statements were) which contained keys to file paths.  Then instead of checking for db or log you would just pull the file path from the resource manager and use some reflection to generate the class and call the log method.  This would mean that new logging methods could be added by creating a new class and adding it to the resource file.

 

Anyway, as you can see this would require you to do a bit more work, but if you're interested I can give you a resource manager class which you could freely use or edit.  Let me know if you'd like it and I'll make it available.

 

Hope that was useful and feel free to ask questions if you have any.

Link to comment
Share on other sites

Yea man. I would appreciate that resource manager class.

 

Thanks for the tips/ideas. I just created this in about an hour today as I got sick of sending some files to production and finding out later, from a user, that there was an error with the main functionality that I did not test.

 

Really appreciate it bed. I will see what I can't cook up the next hour that I try to improve the class.

Link to comment
Share on other sites

OK I've made it available with a package that I've made.  The link in my signature should take you to it; you just need to download and unzip it.  Feel free to ignore the rest of the stuff and grab the ResourceManager.  Please let me know if you run into some bugs, need an explanation on how it works, or want something added.

 

Edit: nevermind it's available now.

Link to comment
Share on other sites

One thing which occurred to me.  Your example looks like it was written for PHP 4 and my code was written for PHP 5, so if you are running PHP 4 it will not work.  Feel free to downgrade it to PHP 4 (which will mean changing private to var and maybe a few other things).

Link to comment
Share on other sites

Will do, yea currently I do not feel like updating my webhost to PHP5, too much of an undertaking with too much that can be screwed up due to it.

 

I will take care of the downgrade for it. Thanks for the heads up.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.