Tutorial Details
- Topic: PHP Error Handling
- Difficulty: Moderate
- Format: Video Quick Tip
- Post Graphic: Available on GraphicRiver
In today’s video quick tip, we’ll review the process of setting custom error handlers with PHP. Along the way, we’ll also learn how to log and email those potential errors to ourselves. That way, even when your web application has been deployed, you’ll be the first to know when an error is encountered.
Intro
Source
<?php
// Our custom error handler
function nettuts_error_handler($number, $message, $file, $line, $vars)
{
$email = "
<p>An error ($number) occurred on line
<strong>$line</strong> and in the <strong>file: $file.</strong>
<p> $message </p>";
$email .= "<pre>" . print_r($vars, 1) . "</pre>";
$headers = 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
// Email the error to someone...
error_log($email, 1, 'you@youremail.com', $headers);
// Make sure that you decide how to respond to errors (on the user's side)
// Either echo an error message, or kill the entire project. Up to you...
// The code below ensures that we only "die" if the error was more than
// just a NOTICE.
if ( ($number !== E_NOTICE) && ($number < 2048) ) {
die("There was an error. Please try again later.");
}
}
// We should use our custom function to handle errors.
set_error_handler('nettuts_error_handler');
// Trigger an error... (var doesn't exist)
echo $somevarthatdoesnotexist;
Conclusion
If you decide to set your own error handlers, make sure that you:
- Determine whether or not to
die()and kill the page. - Provide some level of feedback for the user. If there was a fatal error, let them know in some form!
- You don’t want to email yourself errors when debugging. You can create a
$debugvariable that, if set totrue, we’ll bypass the process of emailing you the error, and will, instead, echo the error onto the page. If you need a code snippet for this, just let us know!

Nice quick tip! :)
This is great for live websites, but during development I’ll stick with the default error message, or write the complete error to a text file.
Oh definitely.
I run a similar script in my .Net projects that only executes if it’s not being served from localhost and isn’t something common like a 404. That way I can dev on my workstation and get the full message, but when I publish to the production server people get friendly errors and I get an email notice.
In this example you could wrap line 29 in an if statement that checks the domain of the page for != “localhost”
Or more efficiently, a switch statement with separate conditionals for development and live environments.
Example: Development environment displays all errors whereas the live evironment shows a nice “Sorry, it’s broken” type message and just email/logs the full issue.
I do what Jacob does – I use different development environments in order to decipher between the two. I do this all in CodeIgniter, where my error logs are probably the furthest thing from the default setup.
I avoid this when I have a single IP per vhost (example might be a website that has SSL/TLS enabled.) Why? Because it’s very trivial to change the localhost alias in your hosts file to the website’s IP address and send that host header to the server. If you have code like this in place, then it’s easy to get a little extra information for an attack vector. Since most of us deploy, most of the time, to shared hosting, it’s probably not a big deal (most of the time.)
Cheers!
Didn’t net tuts write a tutorial on a detailed 404 page with a mailer as well.
Does it work in the same way or is it worth revising my code…..?
Thanks for the quick tip! It’s interesting that many webmasters do not implement this method on their websites. I’ve seen many scripts – with a lot of PHP code – that didn’t have this feature.
Cool. But you probably would need to log the erros in a file or database for a certain time, and not send emails about the same errors in like 24 hours, so your email box won’t get flooded.
I built a similar system to email the errors, but when there’s an error on a page that gets a lot of traffic, it can clog up your whole email queue. I changed it to log to a database, so our intranet can just display (and later purge) the errors. It has made bug tracking quite efficient.
Shouldn’t you just test and debug your code properly instead of working with the ‘Oh, I’ll get an email when something goes wrong.’.?
If something goes wrong in, for example, a checkout process, users might never come back. Even if the error has been dealt with.
[..]when something goes wrong.’ attitude.?*
You guys should consider a edit-your-comment-during-a-limited-time-span plugin, heh.
Even the best web apps are buggy.
Also what works today may not work tomorrow.
Let’s suppose that the PHP version that is installed on your server gets updated with out anyone telling you. (or even if someone does tell you) and one of the functions that you relied on has been modified, and/or no longer works. This would send you an email about it long after you have forgotten you even wrote it.
What a fantastic concept… just write code that works 100% and only ever launch with that. Hey everyone, go ahead and stop with your production error notices / monitoring systems, we should just launch perfect code instead!. Wow, thank you ‘A reader’ for your amazing suggestion.
I’m working on a big project that does a lot of communicating with Social Networks. It’s impossible to fully test this project and the even bigger concern is that Facebook can change their API at anytime and break the script.
Creating a logging system like this lets me be notified right away if scripts get broken.
Any idea why I get a .dat attachment with this php function? Nice Quick tip Jeffrey!
Nevermind Jeffrey, I switched text/html with html/text (Noob mistake, only human afterall)
Sorry for the excess of comments,
I just wanted to ask one more thing: Why doesn’t this code work for errors like (Fatal error: Call to undefined function getme() in …) ?
I don’t get the reason it doesn’t look at that kind of errors.
@ThomasV,
I think what you can do is include you code like this
//Jeffrey’s code here
//call your function here
my_function();
//trigger error handler if any errors need to be caught
trigger_error(“Your custom error message”, E_USER_NOTICE);
Let me know if that works :)
It doesn’t work for me because it goes right to “Having an error” if I place it in before I request the function to be executed, when I place it after the function it gives the fatal error of a non existing function. It still doesn’t handle non existing functions, but maybe it’s not supposed to support such a thing. I would love to see it though
@ThomasV,
I have edited Jeffrey`s code here to provide i guess a simpler explanation.
Just tested this so this should work :)
If this works for you , you can proceed and email the error by adapting what i have missed out from the original code inside the function
<?php
function nettuts_error_handler($number, $message, $file, $line, $vars)
{
$email = "
An error ($number) occurred on line
$line and in the file: $file.
$message “;
echo $email;
die();
}
// We should use our custom function to handle errors.
set_error_handler(‘nettuts_error_handler’);
trigger_error(“Your custom error message”, E_USER_ERROR);
//this function below is undefined so should echo out “Your custom error message”
my_function();
?>
No it doesn’t work for me the way I want this to work. If you would remove the line @ my_function(); then it would still trigger an error. So the script doesn’t go on if no error is present. Try for yourself, removing my_function(); still results in an error while there isn’t one. But still many thanks for your help.
@ThomasV,
I am lol-ing at myself as to how i thought that script would run. Obviously i have manually triggered the error handler there so thats not going to work is it ? ;p sorry!
I havent had much experience with error handling and when i tested the previous script, i had a eureka moment and i wrapped it up! sorry about that :)
After doing some research, here is the best solution
sorry about the confusion earlier!!
i guess i didnt declare the code correctly! sorry about the spam guys!
error_reporting(E_ALL);
ini_set(‘display_errors’, 0);
function shutdown(){
$isError = false;
if ($error = error_get_last()){
switch($error['type']){
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
$isError = “You have not defined this function”;
break;
}
}
if ($isError){
echo $isError;
} else {
echo “Script completed”;
}
}
register_shutdown_function(‘shutdown’);
my_function();
Jeffrey,
Great tip especially for a noobie like myself. Can you provide the code snippet for debug mode to have all the errors written to screen?
I couldn’t find the webpage about error_log. What is the url?
Thanks Jeffrey, I may implement this for some bugs I want to learn more about.
I use the following snippet in a daily (M-F) cron job to concat all the error_log files into one and then email a list of past errors:
$getErrors=’
rm -f /home/davidr/all_errors.txt /home/davidr/filesWithErrors.txt;
find /home/davidr/public_html -name “error_log” > /home/davidr/filesWithErrors.txt;
cat /home/davidr/filesWithErrors.txt >> /home/davidr/all_errors.txt;
cat /home/davidr/filesWithErrors.txt | xargs cat >> /home/davidr/all_errors.txt;
cat /home/davidr/filesWithErrors.txt | xargs rm;’;
shell_exec($getErrors);
* snipped the part where I email the file to myself *
Of course, if you’re getting a lot of errors, I recommend you gzip the file like:
$gzip=’tar cvpzf /home/davidr/errors.tgz /home/davidr/all_errors.txt’;
shell_exec($gzip);
…And then mail the .tgz file instead of a .txt file. You should get 10:1 compression at least.
This is excellent….Thanks!
Awesome tip thanks.. :)
Good tip to monitor easilly errors!
The spelling is ‘Content-Type’ with a capital T, it seems Outlook is sensitive to this capital T.
Very interesting,
wonder what the best way to do this in codeigniter would be
figured it out, a message in http://stackoverflow.com/questions/260597/in-codeigniter-how-can-i-have-php-error-messages-emailed-to-me had the answer. You need to extend the CI_Exceptions core class by creating MY_Exceptions file. Combine that with this tutorial
class MY_Exceptions extends CI_Exceptions {
function My_Exceptions()
{
parent::CI_Exceptions();
}
function log_exception($number, $message, $file, $line, $vars)
{
$email = “”//Email Message as shown in article
$headers = ‘Content-type: text/html; charset=iso-8859-1′ . “\r\n”;
error_log($email, 1, ‘you@youremail.com’, $headers);
if ( ($number !== E_NOTICE) && ($number < 2048) ) {
die(“There was an error. Please try again later.”);
}
}
Excellent tip! Can see many a overloaded inbox on the horizon!
Great tip!
Hi , I get this error, can you help how to fix it, thanks.
Warning: error_log() [function.error-log]: Failed to connect to mailserver at “localhost” port 25, verify your “SMTP” and “smtp_port” setting in php.ini or use ini_set() in C:\wamp\www\puro\errorHandler.php on line 13
What and where should I change something to make it works.
Cool! The last thing you mentioned is good. I use this method for connecting to the correct database.
function db_connect() {
//if on localhost
if($_SERVER['HTTP_HOST'] == ‘localhost’) {
@mysql_connect($local_dbhost, $local_dbuser, $local_dbpass) or die ($mysql_error_msg . mysql_error());
@mysql_select_db($local_dbname);
}
//if not on localhost (online)
else {
@mysql_connect($dbhost, $dbuser, $dbpass) or die ($mysql_error_msg . mysql_error());
@mysql_select_db($dbname);
}
}
Nice tutsplus tuts !!
Hello!
Firstly, your code will only catch some errors. To catch more, read this: http://jarofgreen.wordpress.com/2011/02/04/catching-php-errors/
Secondly, you state in your video that $vars has things like $_SERVER in it. Not always true!
function nettuts_error_handler($number, $message, $file, $line, $vars) { print_r($vars); }
set_error_handler(‘nettuts_error_handler’);
function q() { print $uiiid; }
q();
This will return:
Array ( )
It will return the variables in scope. If you are in a function, this does not include $_SERVER.
Finally, I’m working on a open source system that collects full information on errors, removes duplicates, creates tickets in a tracking system and emails devs. Info and a screenshot is at http://jarofgreen.wordpress.com/2011/01/30/tracking-errors-with-php/
If you want to see how we do it, have a look! SourceForge code repository browser is off-line at the moment but when it’s back it’s at
http://elastik.svn.sourceforge.net/viewvc/elastik/trunk/mod.ErrorReportingService/includes/RemoteReportingWidget.php?content-type=text%2Fplain
Feedback would be most welcome …
Thank you for informative post.
Thank you king of tuts!
Great article dude!!!
Thanks for the quick tip! It’s interesting that many webmasters do not implement this method on their websites.
Hi,
With this article if you have provided how to upload files and how to attach file with mailer then confirm this will be enhance your current article. any how looking for next one.