Criticism please!
*note: I modified some stuff to make it easier to look at out of context
Here we have the custom error handler
Code: Select all
/**
* Global error handler.
*
* This should not be called by anything - only for uncaught errors.
*/
public function globalErrorHandler($errorNumber, $errorMsg, $file, $line, $context)
{
$error = new SpotSec_Error($errorNumber, $errorMsg, $file, $line, $context, SpotSec_Error::TYPE_ERROR, false);
// Log error
SpotSec_Error_Logger::log($error);
// Queue error for those implementations that need it (e.g. web-interface, SOAP)
SpotSec_Error_Queue::getInstance()->push($error);
// Show error on standard out if running from command line
if (preg_match('/cli/', php_sapi_name()))
echo SpotSec_Error::getErrorType($errorNumber) . ": " . $errorMsg . " - $file ($line)\n";
// TODO: Add "when to die" policy for uncaught errors
}Code: Select all
class SpotSec_Error
{
protected $_code;
protected $_message;
protected $_tag;
protected $_line;
protected $_context;
protected $_caught;
protected $_trace;
protected $_type;
const TYPE_EXCEPTION = 'exception';
const TYPE_ERROR = 'error';
/**
* Global Error types
*
* Define global error message mapping.
* Handled errors and exceptions use COMMON_xxx constants.
* Unhandled errors and exceptions use built-in E_xxx constants.
*/
static $globalErrorTypes = array(
SpotSec_Exception::FATAL => 'fatal',
SpotSec_Exception::ERROR => 'error',
SpotSec_Exception::WARNING => 'warning',
SpotSec_Exception::INFO => 'info',
SpotSec_Exception::VALIDATION => 'validation',
SpotSec_Exception::NOTICE => 'notice',
SpotSec_Exception::DEBUG => 'debug',
E_STRICT => 'strict',
E_ERROR => 'error',
E_WARNING => 'warning',
E_PARSE => 'parse error',
E_NOTICE => 'notice',
E_CORE_ERROR => 'core error',
E_CORE_WARNING => 'core warning',
E_COMPILE_ERROR => 'compile error',
E_COMPILE_WARNING => 'compile warning',
E_USER_ERROR => 'user error',
E_USER_WARNING => 'user warning',
E_USER_NOTICE => 'user notice'
);
/**
* Error constructor.
*
* @param integer $code error code
* @param string $message error message
* @param string $tag a method name or some other nickname
* @param integer $line line number
* @param array $context error context
* @param integer $type type of error - exception or error
* @param boolean $caught true if error was caught by application
* @param array $trace error back trace
* @returns void
*/
function __construct($code, $message, $tag, $line, $context = null, $type, $caught = true, $trace = null)
{
$this->_code = $code;
$this->_message = $message;
$this->_tag = $tag;
$this->_line = $line;
$this->_context = $context;
$this->_type = $type;
$this->_caught = $caught;
$this->_trace = $trace;
}
/**
* Returns error code.
*
* @returns integer error code
*/
function getCode()
{
return $this->_code;
}
/**
* Returns error message.
*
* @returns string error message
*/
function getMessage()
{
return $this->_message;
}
/**
* Returns error tag.
*
* @returns string error tag
*/
function getTag()
{
return $this->_tag;
}
/**
* Returns line number where error occurred.
*
* @returns integer line number
*/
function getLine()
{
return $this->_line;
}
/**
* Returns error context.
*
* @returns array error context
*/
function getContext()
{
return $this->_context;
}
/**
* Returns flag on state of the error.
*
* @returns boolean true if error was caught by application.
*/
function isCaught()
{
return $this->_caught;
}
/**
* Returns error type: error or exception.
*
* @returns string error type
*/
function getType()
{
return $this->_type;
}
/**
* Returns error trace.
*
* @returns array error trace.
*/
function getTrace()
{
if ($this->_trace) {
return $this->_trace;
} else {
return array();
}
}
/**
* Returns the error level string from the error code
*
* @todo move this somewhere else
* @param integer $code
* @return string
*/
public static function getErrorType($code)
{
$typemap = self::$globalErrorTypes;
if (in_array($code, $typemap, true)) {
return $typemap[$code];
} else {
return null;
}
}
}Code: Select all
class SpotSec_Error_Logger
{
/**
* Constructor
*
*/
private function __construct()
{}
/**
* Logs errors
*
* @todo look at todo comments and fix COMMON_DEBUG_MODE
*
* @param SpotSec_Error $error
*/
public static function log(SpotSec_Error $error)
{
static $basetime = 0;
// Set the log variables
$errorNumber = $error->getCode();
$errorMsg = $error->getMessage();
$file = $error->getTag();
$line = $error->getLine();
$context = $error->getContext();
$caught = $error->isCaught();
$type = $error->getType();
// TODO: discuss what policy we want here. Current policy is...
// In debug mode, all errors are logged. In production mode, the following errors are logged:
// - all uncaught errors
// - COMMON_ERROR
// - COMMON_FATAL
/*if ((!COMMON_DEBUG_MODE) && ($errorNumber >= SpotSec_Exception::WARNING)) {
return;
}*/
// Set prefix for log line
if ($type == SpotSec_Error::TYPE_ERROR) {
$prefix = 'error';
} elseif ($type == SpotSec_Error::TYPE_EXCEPTION) {
$prefix = 'exception';
} else {
$prefix = 'unknown';
}
if (!$caught) {
$prefix .= ' uncaught';
}
// Specify log line format
$logline = sprintf("$prefix: %s: %s (%d): %s", SpotSec_Error::getErrorType($errorNumber), preg_replace('/.*\//', '', $file), $line, $errorMsg);
// Perform extra goodness in debug mode
if (COMMON_DEBUG_MODE) {
// Append timestamp to log line
if ($basetime == 0) {
$basetime = microtime(true);
$timestamp = 0;
} else {
$currenttime = microtime(true);
$timestamp = microtime(true) - $basetime;
}
$logline = sprintf("%.4f: %s", round($timestamp, 4), $logline);
// Log messages to standard out when in command-line mode
if (ini_get('display_errors') && preg_match('/cli/', php_sapi_name())) {
echo "$logline\n";
}
// Log messages to custom log file (if set) and standard out on
if (ini_get('error_log')) {
date_default_timezone_set('CST');
$timestamp = date("M j G:i:s T Y");
error_log("{$timestamp}: $logline\n", 3, ini_get('error_log'));
foreach ($error->getTrace() as $traceinfo) {
// Backtrace log format
$logline = sprintf("$prefix: debug backtrace: %s (%d): %s",
preg_replace("/.*\//", "", $traceinfo['file']),
$traceinfo['line'],
$traceinfo['function']);
error_log("{$timestamp}: $logline\n", 3, ini_get('error_log'));
}
}
} else {
$logName = 'SpotSec';
// Log errors to syslog
try {
Zend_Log::registerLogger(new SpotSec_Log_Adapter_Syslog($logName, LOG_NDELAY | LOG_PID, LOG_LOCAL6, false), $logName);
Zend_Log::log($logline, Zend_Log::LEVEL_INFO, $logName);
} catch (Exception $e) {
//TODO: do backup plan
}
// Log backtrace
foreach ($error->getTrace() as $traceinfo) {
// Backtrace log format
$logline = sprintf("$prefix: debug backtrace: %s (%d): %s",
preg_replace('/.*\//', '', $traceinfo['file']),
$traceinfo['line'],
$traceinfo['function']);
try {
Zend_Log::log($logline, Zend_Log::LEVEL_INFO, $logName);
} catch (Exception $e) {
//TODO: do backup plan
}
}
}
}
/**
* Logs an exception to the log.
*
* @static
* @global array global error message mapping
* @return void
*/
public static function logException(Exception $exception, $iscaught)
{
self::log(
new SpotSec_Error(
$exception->getCode(),
$exception->getMessage(),
$exception->getFile(),
$exception->getLine(),
'',
SpotSec_Error::TYPE_EXCEPTION,
$iscaught,
$exception->getTrace()
)
);
}
}Code: Select all
class SpotSec_Error_Queue
{
/**
* @var SpotSec_ErrorQueue instance
*/
static private $_instance = null;
/**
* @var array error queue
*/
static private $_errors = array();
/**
* SpotSec_ErrorQueue constructor.
*
* @access private
*/
private function __construct()
{}
/**
* Do not allow attempts to clone our singleton.
*
* @access private
*/
private function __clone()
{}
/**
* Returns an ErrorQueue instance.
*
* @static
* @return ErrorQueue current instance
*/
static public function getInstance()
{
if (self::$_instance == null) {
self::$_instance = new self;
}
return self::$_instance;
}
/**
* Add error to error queue.
*
* @param SpotSec_Error $error error object
* @return void
*/
public function push(SpotSec_Error $error)
{
self::$_errors[] = $error;
}
/**
* Return list of queued Error objects.
*
* @param boolean $purge if true, the queue will be purged
*
* @return array list of Errors
*/
public function getAll($purge = true)
{
$errors = self::$_errors;
if ($purge){
self::$_errors = array();
}
return $errors;
}
/**
* Return list of queued error messages.
*
* @param boolean $purge if true, the queue will be purged
*
* @return array list of Errors
*/
public function getAllMessages($purge = true)
{
$messages = array();
foreach (self::$_errors as $error) {
if ($error->isCaught()) {
$messages[] = $error->getMessage();
} else {
if (ini_get('display_errors')) {
$errorNumber = $error->getCode();
if(($errorNumber & error_reporting()) == $errorNumber) {
$tag = preg_replace("/.*\//", "", $error->getTag());
$line = $error->getLine();
$errmsg = $error->getMessage();
$messages[] = sprintf("%s: %s (%d): %s", SpotSec_Error::getErrorType($errorNumber), $tag, $line, $errmsg);
}
}
}
}
if ($purge){
self::$_errors = array();
}
return $messages;
}
/**
* @access private
*/
function __destruct()
{}
}