Page 1 of 1

Making Your Site More User-Friendly By Handling Errors Correctly Rate Topic: -----

#1 codeprada  Icon User is offline

  • Changed Man With Different Priorities
  • member icon

Reputation: 947
  • View blog
  • Posts: 2,355
  • Joined: 15-February 11

Posted 07 May 2011 - 02:54 PM

*
POPULAR

In this tutorial I will talk about ways in which you can handle errors and exceptions while avoiding nasty error messages in your websites.

Q: What's wrong with PHP's way of handling errors & exceptions?
A: When PHP encounters an error or exception it automatically displays it on the screen in a rather nasty manner and stops the script.

Spoiler


Q: Why should I handle errors myself?
A: Handling errors will allow a programmer to determine what exactly he\she wants to do with the error message. This can be but not limited to logging it to a database, emailing the right people automatically, and redirecting a user to a specific page while letting them know the task they tried to execute was not completed. Users aren't found of seeing cryptic messages on their screen when they're just trying to view a simple web page. This will in turn deter users from using your site.

I find that the majority or newer PHP coders handle error using the die function.

$sql = "GIVE ME ALL THE TABLES"; //that should do the trick
$result = mysql_query($sql) or die("There was an error");


Remember when you did that? It may even be in that very website you're developing right now. If an error occurs die like the function name says causes the whole script to die which causes pages to be half loaded and so forth.

Q: What about the error message?
A: User's don't care about your error messages so you should keep them to yourself!!

Let's look at a more user-friendly way of handling such situations.

Setting Up Your Error Handler Function
function error_handler($errno, $error, $file, $line, $context)
{ 
   //just so we know the error handler got the error
   printf("The error handler got the error! The error says %s", $error);

   return true;
}

set_error_handler('error_handler');

$sql = "GIVE ME ALL THE TABLES";
$result = mysql_query($sql);

restore_error_handler();



The above code still outputs the error message to the screen but we've seen that our error handler catches errors. Our next step is to determine what you want to do with the error.

Handling The Error Effectively
function error_handler($errno, $error, $file, $line, $context)
{
   	$formated_error_message = sprintf("Error caught on line #$d in script <b>%s</b><br />Cause of Error: %s", $line, $file, $error);

	//let's do something useful with our error message
	mail("somebody@mailhost.xxx", "Error On www.mysite.xxx", $formated_error_message, "From: error_handler@mysite.xxx\r\nX-Mailer: PHP/" . phpversion());
	return true; //this notifies the script that we handled the error OK and not to call the default error handler
}

set_error_handler('error_handler');

$sql = "GIVE ME ALL THE TABLES";
$result = mysql_query($sql);

restore_error_handler();



The above snippet will attempt to email the error message to the listed recipient. You can also log your error messages to a database for an administrator or who ever else to view.

How do Create An Custom Error?
This may sound strange but there are instances where one would need to throw a particular error. For instance let's detect a mail header injection attack.

Example: Featuring trigger_error
$message = $_POST['message'];
if(preg_match("#[\n]|[\r]|[\%??]#", $message))
	trigger_error("An attack has been detected");
echo "Running the rest of the script...";


If you notice the message Running the rest of the script will still appear. To prevent such we can simply use this line to trigger the error

trigger_error("An attack has been detected") and exit(); //yep it's valid PHP


Hmmm...This is still not satisfying because it ends the script execution which can lead to blank pages or half loaded pages. Let's take this next script into consideration...

set_error_handler('error_handler', E_ALL);

function redirect()
{
	header("location: logger.php"); //remember not to output anything to the screen 
}

$message = $_POST['message'];
if(preg_match("#[\n]|[\r]|[\%??]#", $message))
	trigger_error("An attack has been detected") and redirect();
	
echo "Running the rest of the script...";

restore_error_handler();


That's better. If an attack has been detected then trigger_error will like the function name says trigger an error causing our error_handler to take necessary actions. After our error has been triggered our function redirect will be called. In our redirect function we can take the necessary action to handle the injection like redirecting our hacker to a script that logs their IP address etc... The possibilities are endless

My Error Handler Doesn't Capture Exceptions!
Just as there's an error handler there can be an exception handler. Exceptions are not handled by error handlers. In order to invoke your error handler when an Exception is thrown you must trigger an error manually in the catch statement. The code below demonstrates such. Notice even when we trigger the error the rest of the script is still executed.

<?php
echo "Beginning of script...<br />";
set_error_handler('error_handler', E_ALL);

function error_handler($errno, $error, $file, $line, $context)
{
	echo sprintf("%d<br />%s<br />%s<br />%d<br />", $errno, $error, $file, $line);
	return true;
}

try
{
	throw new ErrorException("ErrorException thrown");
}
catch(ErrorException $e)
{
	trigger_error($e->getMessage());
}
catch(Exception $e)
{
	echo $e->getMessage();
}
restore_error_handler();

echo "End of script...";
		
?>



Now you've seen much better ways to handle errors other than just using die to kill the entire script. When designing for companies or clients you WILL have to handle those errors.

My Site Never Displays Errors Because I Use @
Using @ to suppress an error isn't advised. What if when someone is purchasing an item from your site and your mail function can't work because port 25 is blocked. You will never know since the error was suppressed.

Final Comments
It's better to have two ways of keeping track of errors. In the example above I only showed you 1 method which was emailing the necessary personnel. What if the mail function doesn't work. Have a second method like logging it to a database. Refrain from logging such information in TXT files. In the case of multiple users accessing a page or script containing the error there's going to be file lock issues and loss of data.

Useful Resources
Error Handling Functions
set_error_handler
set_exception_handler
restore_error_handler
restore_exception_handler
ErrorException
Exception
trigger_error

This post has been edited by codeprada: 10 May 2011 - 05:29 PM


Is This A Good Question/Topic? 11
  • +

Replies To: Making Your Site More User-Friendly By Handling Errors Correctly

#2 creativecoding  Icon User is offline

  • Hash != Encryption
  • member icon


Reputation: 926
  • View blog
  • Posts: 3,205
  • Joined: 19-January 10

Posted 09 May 2011 - 09:41 AM

View Postcodeprada, on 07 May 2011 - 03:54 PM, said:

My Site Never Displays Errors Because I Use @
Using @ to suppress an error isn't advised. What if when someone is purchasing an item from your site and your mail function can't work because port 25 is blocked. You will never know since the error was suppressed.


Not to mention it's slow and unsightly.
Was This Post Helpful? 0
  • +
  • -

#3 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3541
  • View blog
  • Posts: 10,257
  • Joined: 08-June 10

Posted 10 May 2011 - 04:36 AM

View Postcodeprada, on 07 May 2011 - 11:54 PM, said:

My Error Handler Doesn't Capture Exceptions!
Just as there's an error handler there can be an exception handler. Exceptions are not handled by error handlers directly. They can however when caught throw an ErrorException which will be treated like an error and thus caught by our error handler.

try
{
	//hmmmm I'm thinking about a real life scenario where an Exception is thrown
	//let's just fake it for now
 	throw new Exception("Hello World. This is a fake exception");
}
catch(Exception $e)
{
	throw new ErrorException($e->getMessage(), $e->getCode(), 0, $e->getFile(), $e->getLine()); //feeling a bit lazy...let the error handler deal with it
}


expanding the said things.

Exception Handling and Error Handling are two different pairs of shoes. i.e. Exceptions are not handled by Error handlers at all (and vice versa).

To the best of my knowledge, even an ErrorException is not caught by an Error Handler (cf. the ErrorException example). It is an extension of Exception with an additional parameter (severity, i.e. error, warning, notice, etc.) used for converting errors into exceptions.

If you catch an Exception after throwing it you just do that. A caught Exception does not automatically throw a new Exception (as the code demonstrates, you have to do that yourself). Most of the times you don’t need to re-throw an Exception either (because you have to catch that too). The catch block would normally execute the code as described at the Error Handler.

What distinguishes an Exception from an Error is that you can "jump" over code and thus avoid dependency errors* (it leaves you time to properly finish your script). Error Handlers are executed at the place they are triggered and return there, Exceptions "return" at the next matching catch block.


* - for example, if you throw an Exception when the DB connection fails, you can bypass all the other database code and proceed at the end of the script.

This post has been edited by Dormilich: 10 May 2011 - 11:21 AM

Was This Post Helpful? 2
  • +
  • -

#4 codeprada  Icon User is offline

  • Changed Man With Different Priorities
  • member icon

Reputation: 947
  • View blog
  • Posts: 2,355
  • Joined: 15-February 11

Posted 10 May 2011 - 05:31 PM

Corrected. Thanks Dormilich.
Was This Post Helpful? 0
  • +
  • -

#5 defiance  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 7
  • Joined: 21-February 12

Posted 27 February 2012 - 06:03 AM

How can I log the errors to my database? I tried to log them but didn't succeed :helpsmilie:
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1