Quick Tip: Email Error Logs with PHP
videos

Quick Tip: Email Error Logs with PHP

Tutorial Details

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 $debug variable that, if set to true, 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!

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.philohermans.com Philo

    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.

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Oh definitely.

    • Colin

      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”

      • http://www.jacobbednarz.com Jacob Bednarz

        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.

      • Craig

        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.

      • http://brettic.us bretticus

        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!

  • http://www.peewee1002.co.uk Peter Sawyer

    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…..?

  • http://www.bitrepository.com/ Gabriel

    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.

  • Eduardo Barros

    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.

  • http://www.onjax.com Luke Brookhart

    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.

  • A reader

    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.

    • A reader

      [..]when something goes wrong.’ attitude.?*

      You guys should consider a edit-your-comment-during-a-limited-time-span plugin, heh.

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Even the best web apps are buggy.

    • http://www.lastrose.com LastRose

      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.

    • Wow

      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.

      • Aaron

        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.

  • http://www.thomasv.nl ThomasV

    Any idea why I get a .dat attachment with this php function? Nice Quick tip Jeffrey!

  • http://www.thomasv.nl ThomasV

    Nevermind Jeffrey, I switched text/html with html/text (Noob mistake, only human afterall)

    • http://www.thomasv.nl ThomasV

      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.

      • http://www.rawtherdesign.com Shebby

        @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 :)

      • http://www.thomasv.nl ThomasV

        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

      • http://www.rawtherdesign.com/ Shebby

        @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();

        ?>

      • http://www.thomasv.nl ThomasV

        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.

      • http://www.rawtherdesign.com shebby

        @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!!

    • http://www.rawtherdesign.com shebby

      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();

  • Dave

    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?

  • Wouter

    I couldn’t find the webpage about error_log. What is the url?

  • David Runion

    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.

  • Giovanni

    This is excellent….Thanks!

  • Sahan

    Awesome tip thanks.. :)

  • Sylvin (France)

    Good tip to monitor easilly errors!

    The spelling is ‘Content-Type’ with a capital T, it seems Outlook is sensitive to this capital T.

  • http://www.lastrose.com LastRose

    Very interesting,
    wonder what the best way to do this in codeigniter would be

    • http://www.lastrose.com LastRose

      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.”);
      }
      }

  • http://www.zipbox.co.uk Stewart

    Excellent tip! Can see many a overloaded inbox on the horizon!

  • http://www.linknomer.com andrei

    Great tip!

  • frank

    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.

  • http://www.pangomedia.se Christian

    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);
    }
    }

  • http://www.wigflair.com Wigflairdotcom

    Nice tutsplus tuts !!

  • http://elastik.sourceforge.net/ James

    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 …

  • http://www.think360studio.com/ Think360 studio – Web Design Company India

    Thank you for informative post.

  • http://www.blog.designlove.co.uk/ Cheapest Web Designs

    Thank you king of tuts!

  • http://www.woodenswings.in wooden swings

    Great article dude!!!

    Thanks for the quick tip! It’s interesting that many webmasters do not implement this method on their websites.

  • http://www.phpcourse.in PHP Training Mumbai

    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.