In this article we will be looking at how to handle errors in PHP. Errors are an inevitable part of software development, and accordingly, we will be looking at the various error types and demonstrating how to handle them.

 

If you intend to run any of the sample scripts in this article, please make sure that display errors is turned on in your PHP initialization document. This section looks something like this:

 

    display_errors = On [Security]
    ; With this directive set to off, errors that occur during the execution of
    ; scripts will no longer be displayed as a part of the script output, and thus,
    ; will no longer be exposed to remote users. With some errors, the error message
    ; content may expose information about your script, web server, or database
    ; server that may be exploitable for hacking. Production sites should have this
    ; directive set to off.

 

The reason for this is that, when display errors are turned on, PHP will display all errors that occur during script execution. If however, the directive is switched off, we will not be able to see any errors as the browser will be blank.

 

Types of PHP Errors

 

PHP has three types of errors:

 

Syntactical PHP Errors

 

Of these three, syntactical errors are the most common and also easiest to fix. A syntactical error occurs when code is not properly formulated, for example, if you leave out a semicolon from the end of a code block or if you do not close the bracket in an if-statement. The code below is erroneous because it does not terminate the code with a semicolon:

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
</head>

<body>
<?php

$i = "jack"
if($i <> "jack"){
echo "Right"
}else{
echo "Wrong"
}
?>
</body>
</html>

 

The code produces the following error:

 



Click here for larger image

Figure 1. PHP 5 Syntax Error

 

The reason why we are getting a syntax error is because the first line of code after the code tag does not terminate with a semicolon(;). Syntactical errors are fairly easy to fix, unlike the other types of errors you will encounter. Syntactical errors stop a script from executing. You will also notice that the error message is vague. It does not specifically point to the exact place where the error occurs.

 

Runtime PHP Errors

 

Unlike syntactical errors, runtime errors actually allow a script to execute but will not allow it to do everything it is supposed to do. For example, calling a function with fewer parameters than it expects will produce a runtime error. Take a look at the code below:

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
</head>

<body>
<?php

function showAge($myname,$age){
echo $myname. " is  ".$age. " old.";
}

showAge("Jack")
?>
</body>
</html>

 

The code produces the following runtime error:

 



Click here for larger image

Figure 2. PHP 5 Runtime Error

 

Where runtime errors are concerned, PHP tells you exactly what the problem is. For instance, in our example we only included one parameter in the function called showAge(), which expects two parameters. The error tells you that the second argument is missing from the showAge() function. Also note that the error statement continues with a "Notice" section that continues to execute the code.

 

Logical PHP Errors

 

Logical errors by all accounts are the worst because:

 

 

Normally the only way you discover logical errors is when the code does not produce the desired results.

 

Handling PHP 5 Errors

 

Basic steps you should follow when debugging are as follows (they've always worked for me):

 

  1. Name all pages in your project uniquely and in such a way that they identify its purpose and function. For example, a page that list names can be called list_names or list_of_names, this already tells you what the page is supposed to do and also ensures that you run the correct page/script. Sometimes, when you try to fix a problem, no matter what you do, it just does not go away. Most of the time, this is because you are working on the wrong script.
  2. Make sure you run your scripts through a URL such as http://localhost/list_names.php (on your development machine) or http://www.mywebsite.com/list_names.php (on the Web).
  3. Do preventative coding. For example when creating a if-statement, write the skeleton of the statement:
          If(){
          }else{
          }//end of statement

     

    Then add the code that you want to add. This way you will avoid getting a whole lot of syntactical errors.

PHP Error Handling on Production Sites

 

For those of you who are running production sites, switch off display_errors. Although these errors have become somewhat safer in terms of the content that it displays, they still pose a security risk to your site. To manage errors that occur during production, make use of PHP's error-handling capabilities. To demonstrate these capabilities, we will create a custom error handler. Before we start developing our own error handler, I'd like to share the following things about PHP's error reporting. PHP has three kinds of error levels:

 

 

This will sound familiar to you, since we already looked at each type in detail. The three error types each have reporting levels as listed below:

 

Number

Constant

Reporting on

 

1

 

E_ERROR

 

Fatal runtime errors (that stop execution of the script)

 

2

 

E_WARNING

 

Runtime warnings (non-fatal errors)

 

4

 

E_PARSE

 

Parse errors

 

8

 

E_NOTICE

 

Notices (things that may or may not be a problem)

 

256

 

E_USER_ERROR

 

User-generated error messages, generated by the trigger_error() function

 

512

 

E_USER_WARNING

 

User-generated warnings, generated by the trigger_error() function

 

1024

 

E_USER_NOTICE

 

User-generated notices, generated by the trigger_error() function

 

2048

 

E_STRICT

 

Recommendations for compatibility and interoperability(available as from PHP6)

 

8191

 

E_ALL

 

All errors, warnings, and recommendations

 

In our custom error handler, we will try to catch the type of error that PHP is reporting and then handle it appropriately. We can either send the error to an email address, or we can log the error to a file. Our error handler will be a class, which will get its information from a config file:

 

Config file:

 

<?php
$app_name="Error Manager";
$filename = 'error_log.txt'; //filename to which the error will be logged
$email ='admin@website.com';//email address to which error messages are to be sent to
$emailname = 'joe blogg'; //email recipient name
$currdate=date("l, dS of F Y @ H:i:s A");

?>

 

The config file contains the email address, logfile and current date information. We can easily include this information in the main class, but it is better security-wise to have it somewhere (even outside of the root) where you can make changes.

 

Errorhandler class:

 

<?php
/*
functions:
handle error - Actual error handler
vars are not echoed when the error is printed out. You can do this if you so wish
TO DO:
HTML Format error messages
*/
class errors
{

    var $msg;
    function errors()
    {
    global $filename,$email,$currdate,$app_name;
        // Populate class variables
        $this->email = $email;
        $this->logfile =$filename;
        $this->currdate=$currdate;
        $this->appname="Error Manager";
        // Take over from PHP error handling
        set_error_handler(array($this, 'handle_error'));
    }


    function handle_error($type, $string, $efile, $line, $vars)
    {

           // Decide which type of error it is, and handle appropriately
        switch ($type)
        {
            // Error type
            case E_ERROR:
            case E_USER_ERROR:
            //build the message
            $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ;
            //$this->msg .= print_r($vars);
            if(isset($this->appname)){
            $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>';
            }else{
             $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>';
            }
            echo '<br>';
            /*//log the error to file
            error_log($this->msg,3,$this->logfile);
            //sent message to web administrator
            error_log($this->msg,1,$this->email); */
            //print out message
           echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ;
           echo 'Error generated on <b>'.$this->currdate.'</b><br>';
           echo '<br>';
            break;


             case E_WARNING:
             case E_USER_WARNING:
             //build the message
            $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ;
           // $this->msg .= print_r($vars);
             if(isset($this->appname)){
            $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>';
            }else{
             $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>';
            }
            echo '<br>';
            /*//log the error to file
            error_log($this->msg,3,$this->logfile);
            //sent message to web administrator
            error_log($this->msg,1,$this->email); */
            //print out message
           echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ;
           echo 'Error generated on <b>'.$this->currdate.'</b><br>';
          echo '<br>';
             break;

             case E_PARSE:
            //build the message
            $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ;
          //  $this->msg .= print_r($vars);
             if(isset($this->appname)){
            $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>';
            }else{
             $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>';
            }
            echo '<br>';
            /*//log the error to file
            error_log($this->msg,3,$this->logfile);
            //sent message to web administrator
            error_log($this->msg,1,$this->email); */
            //print out message
           echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ;
           echo 'Error generated on <b>'.$this->currdate.'</b><br>';
           echo '<br>';
            break;

            case E_NOTICE:
            case E_USER_NOTICE:
            //build the message
            $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ;
           // $this->msg .= print_r($vars);
             if(isset($this->appname)){
            $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>';
            }else{
             $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>';
            }
            echo '<br>';
            /*//log the error to file
            error_log($this->msg,3,$this->logfile);
            //sent message to web administrator
            error_log($this->msg,1,$this->email); */
            //print out message
           echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ;
           echo 'Error generated on <b>'.$this->currdate.'</b><br>';
           echo '<br>';
             break;
        }

    }

    }



?>

 

The errorhandler class uses a function called handle_error() to list all the available error reporting levels and constructs a message using the reported error:

 

function handle_error($type, $string, $efile, $line, $vars)
    { 
 
           // Decide which type of error it is, and handle appropriately
        switch ($type)
        {
            // Error type
            case E_ERROR:
            case E_USER_ERROR:
            //build the message
            $this->msg = '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line.'</b> <br>' ;
            //$this->msg .= print_r($vars);
            if(isset($this->appname)){
            $this->msg .='Error generated by <b>'.$this->appname.'</b> on <b>'.$this->currdate.'</b><br>';
            }else{
             $this->msg .='Error generated on <b>'.$this->currdate.'</b><br>';
            }
            echo '<br>';

 

Then it writes the error message to a file:

 

            /*//log the error to file
            error_log($this->msg,3,$this->logfile);

 

And then sends the error to the email address that was defined in the config file:

 

            //sent message to web administrator
            error_log($this->msg,1,$this->email); */
            //print out message
           echo '<b>Error:</b> <br> Error message: <b>'.$string.'</b> in <b>'.$efile.'</b> on line <b>'. $line. '</b><br>' ;
           echo 'Error generated on <b>'.$this->currdate.'</b><br>';
           echo '<br>';
            break;

 

To test the errorhandler class, you simply do the following:

 

<?php
include "errorhandler.class.php";
include "config/errorhandler.conf.php";
//instantiate the class
 $errors = new errors();
//trigger some  errors
$row = mysql_fetch_array($result);
100/0;
?>

 

I've included the source code for download.

 

Conclusion

 

Handling errors this way keeps your site secure and enables you to deal with any errors in the background. The error handler can, of course, be expanded to include any new error reporting levels that might be introduced in the newer versions of PHP.