MySQL Error Handling
The recommended "best practice" has three parts:
The developer should be alerted to all errors, notices, warnings, etc. both during development and when the PHP application goes into production.
The developer should be able to choose how to be notified of these problems.
No errors, notices, warnings, etc. should ever be displayed to the user. Even in development, errors dumped to the browser can be bad because they can become hidden in the HTML. In production, you should display a generic page that says "System down for maintenance" or some other generic message. At no time do you want to tip off a hacker as to what went wrong, nor do you want to display the details of what went wrong. That information is for you alone. Although some developers feel that errors should be displayed during development and even in a production environment - modified, of course, so as not to tip off a hacker - we will assume here that errors will never be displayed.
We can set these three parameters in one of two ways.
If you have control over the php.ini file then set the following parameters:
(See Note 1)
error_reporting = E_ALL
log_errors = On
display_errors = Off
If you don't have control over php.ini, then at the beginning of your script you can set the same parameters using the following:
error_reporting(E_ALL);
ini_set('log_errors','1');
ini_set('display_errors','0');
When "log_errors" is set to "On", errors will go into one of two places:
The Apache error log file
If you control your own server, you can view the Apache error logs using the following command:
tail -f /path/to/your/log/error_log
The " -f " setting will show the errors as they are appended to the file. If the error has already occurred, you can use the following command to view the last 100 lines of the log. tail -100 error_log | more The number "100" can be changed to any number of lines you may want to view and piping the output to the more command will show a screen's worth of data at a time.
In a shared hosting environment, to a specified file within your designated directory. In this environment, you may need to download the error log file in order to view it.
In either case, the file that PHP will write its errors to can be changed in either the php.ini file in the "Error Handling and Logging" section, specifically, error_log = filename or, if you do not have control over php.ini, you can set the file in your code by using the following:
ini_set('error_log', '/full/path/to/your/file/my-errors.log');
EXPECTED ERRORS
This type of error can be the the result of something a website visitor has done such as providing invalid form input (the visitor omitted some values or entered letters in a field that is expecting numbers) or it can be a database query that returns no records. For example, you may have a form that requires that particular fields be completed before submitting or particular fields may require a particular type of input such as only numbers and dashes in a field that captures phone numbers. Therefore, your PHP code should ALWAYS check for acceptable values.
Illustrated below is a simple example that illustrates the concept. Click here to see it in action.
/**************************************************************
Check values entered by user.
The code shown here is meant solely to illustrate the concept
in the main article. There are many different coding methods
that one can use to validate form input.
***************************************************************/
//Initialize array to an empty array
$errMsg = array();
/*
Check to see if the form has been posted. If true, then
check values.
*/
if (isset($_POST['submit'])){
if (trim($_POST['Name']) === ''){
$errMsg[] = 'Please enter your name';
}
//We want to make sure that the phone number is in the format we want
if (!preg_match("/^[0-9]{3}[-]{1,1}[0-9]{4}$/", $_POST['Phone'])){
$errMsg[] = 'Phone number should be entered as digits in the following format: ###-####';
}
/*
If an error has occurred, the array "$errMsg" will have a count greater than zero
so display our error message to the user
*/
if (count($errMsg)!== 0){
foreach ($errMsg as $key => $value){
$tmp .= "
}
echo "An error has occurred:
- $tmp
} else {
echo "Congratulations! You successfully entered your Name and Phone Number!";
}
}
//Note below that we are echoing back to the user any values already entered and we are
//making those values browser-safe with the "htmlentities" function
//(See Note 2)
?>
UNEXPECTED ERRORS
Unexpected errors are errors that are not part of the normal operation of your PHP application such as a database that suddenly stops running. When an unexpected error occurs, you want to:
know the state of the application
know when it happened
know that it happened
have a record of the above three items
prevent the user from knowing any of the details of what happened (See Note 3)
Below are general guidelines for implementing our recommended best practices for notifying the developer of unexpected errors.
In the top level include file for your application, set the error handler for your application to your own error handler by using
set_error_handler('myErrHandler');
You could simply place this statement at the beginning of all of your PHP scripts but using an "include" file makes it easier to maintain your code. See require_once and related functions and the PHundamentals article Site Structure: Where to Locate Includes?.
When an error occurs, trigger the error handler, e.g.,
if(!mysql_connect("myDatabase","myUser","myPassword")){
trigger_error('Can not connect to database',E_USER_ERROR);
}
So what should your error handler look like? We've provided a sample error handler though the exact error handler you use is solely up to you. However, the sample code below fulfills the five basic requirements of an error handler as noted above.
The error handler lets you know the "state" of the application (handled by trigger_dump())
The error handler lets you know when it happened (handled by date())
The error handler lets you know that it happened (handled by mail())
The error handler records all three of the items above (handled by error_log())
You need to prevent the user from knowing any of the details of what happened, except that it happened (handled by header)
function myErrHandler($code, $message, $errFile, $errLine) {
//Set message/log info
$subject = "$message: MAJOR PROBLEM at " . APP_NAME . ': ' . date("F j, Y, g:i a");
$body = "errFile: $errFile\r\n"
. "errLine: $errLine\r\n"
. trigger_dump($GLOBALS);
/*
An email will be sent to the site administrator.
Its subject line will have the date and time it occurred while
the body will contain the state of all of the global variables. This information
is obtained through the function trigger_dump.
*/
mail(ADMIN_EMAIL_ADDR,$subject,$body);
//The same subject line and body of the email will get written to the error log.
error_log("$subject\r\n $body");
/*
We don't want users to know the true nature of the problem so
we just redirect them to a generic error page that has been created.
The generic page should have a simple message, such as "System down
for maintenance." The key idea is not to let any potentially malicious
user learn about the actual problem that had occurred.
*/
header ("Location: https://{$_SERVER['HTTP_HOST']}/". GENERIC_ERR_PAGE );
exit;
}
/*
The function below is called by the mail
and error_log calls above.
*/
function trigger_dump( $mixed,$type = 0 ) {
/*
$mixed will handle whatever you may decide to pass to it.
$type will determine what this function should do with the
information obtained by var_dump
*/
switch( (int) $type ) {
case 0:
/*
Grab the contents of the output buffer
when you want to send the information
back to the calling function
*/
ob_start();
var_dump($mixed);
//If you are using PHP ver. 4.3 use the
//code below:
return ob_get_clean();
//If you are using an earlier version
//of PHP, then use the code below:
$ob_contents = ob_get_contents();
ob_end_clean();
return $ob_contents;
case 1:
/*
When you want to display the information to the browser
*/
print '
';';
var_dump($mixed);
print '
break;
case 2:
//When you want your error handler to deal with the information
ob_start();
var_dump($mixed);
//If you are using PHP ver. 4.3 use the
//code below:
trigger_error(ob_get_clean());
break;
//If you are using an earlier version
//of PHP, then use the code below:
$ob_contents = ob_get_contents();
ob_end_clean();
trigger_error($ob_contents);
break;
}
}
?>