+1 for mentioning Exceptions and the try/catch syntax.
Another thing I would like to add is that, it’s very important that you record all possible errors within an error log on your server. This way you will know when people are experiencing trouble rather then letting them see specific vulnerabilities.
A few specific ways it can be done are stated below, please note that this is just a basic system I use and is by no means ‘bulletproof’.
- Create a “crash” table in your database and a set of wrapper classes for reporting errors. I’d recommend setting categories for the crashes (“blocking”, “security”, “PHP error/warning” (vs exception), etc).
- In all of your error handling code, make sure to record the error. Doing this consistently depends on how well you built the API (above step) - it should be trivial to record crashes if done right.
Also don’t forget to write fail over logic incase your DB crashes =p. Such as sending emails to admin or simply just recording the DB activities in a plain text file.
One thing I would like to do is give an example about exceptions. Exceptions are a fairly modern way to treat errors in PHP. The easiest thing to do is probably set up an error handler that throws an exception. That way all errors are converted to exceptions, leaving you to deal with one error scheme only.
The following will convert errors to exceptions for you.
function exceptions_error_handler($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}
set_error_handler('exceptions_error_handler');
error_reporting(E_ALL ^ E_STRICT);
“There are a few cases though, where code is specifically designed to work with errors. For example, the schemaValidate method of DomDocument raises warnings, when validating a document. If you convert errors to exceptions, it will stop validating after the first failure. Some times this is what you want, but when validating a document, you might actually want all failures. In this case, you can temporarily install an error-handler, that collects the errors.”
class errorhandler_LoggingCaller {
protected $errors = array();
function call($callback, $arguments = array()) {
set_error_handler(array($this, "onError"));
$orig_error_reporting = error_reporting(E_ALL);
try {
$result = call_user_func_array($callback, $arguments);
} catch (Exception $ex) {
restore_error_handler();
error_reporting($orig_error_reporting);
throw $ex;
}
restore_error_handler();
error_reporting($orig_error_reporting);
return $result;
}
function onError($severity, $message, $file = null, $line = null) {
$this->errors[] = $message;
}
function getErrors() {
return $this->errors;
}
function hasErrors() {
return count($this->errors) > 0;
}
}
In action:
$doc = new DomDocument();
$doc->load($xml_filename);
$validation = new errorhandler_LoggingCaller();
$validation->call(
array($doc, 'schemaValidate'),
array($xsd_filename));
if ($validation->hasErrors()) {
var_dump($validation->getErrors());
}
There is no ‘one right way’ to tackle error handling. You just have to ask yourself some basic questions:
- How do you want errors handled on a dev environment (show on screen?) versus in a production environment (logged and emailed?)
- Not all error types can be handled with a custom error handler
- You can also look into Trigger_Error which is similar to throw new Exception in that they both escape out of the current execution immediately, only trigger_error() is not catchable