Location: PHPKode > projects > MicroMVC PHP Framework > modules/core/classes/error.php
<?php defined('SYSTEM_PATH') or die('No direct access');
/**
 * Error
 *
 * The custom Error and Exception handler used instead of the native PHP handler
 *
 * @package		MicroMVC
 * @author		David Pennington
 * @copyright	(c) 2010 MicroMVC Framework
 * @license		http://micromvc.com/license
 ********************************** 80 Columns *********************************
 */
class Error {

	// On error, should the script exit() or keep running?
	public static $is_fatal = FALSE;

	// PHP error constants
	public static $error_codes = array(
		E_ERROR				=> 'Error',
		E_WARNING			=> 'Warning',
		E_PARSE				=> 'Parsing 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',
		E_STRICT			=> 'Runtime Notice',
		//E_RECOVERABLE_ERROR => 'Recoverable Error',	PHP 5.2.0
		//E_DEPRECATED		=> 'Deprecated Code',		PHP 5.3.0
		//E_USER_DEPRECATED	=> 'Deprecated Code',		PHP 5.3.0
	);
	
	
	/**
	 * Display all PHP errors (not suppressed by PHP) to the user.
	 * If debug_mode is enabled, a backtrace will also be shown.
	 * If $is_fatal is enabled, the script will exit.
	 *
	 * @param int $code
	 * @param string $error
	 * @param string $file
	 * @param int $line
	 * @return bool
	 */
	public static function handler($code, $error, $file = NULL, $line = NULL)
	{
		// If this error is suppressed by current error reporting settings
		if ((error_reporting() & $code) === 0)
		{
			// Do not execute the PHP error handler
			return TRUE;
		}
		
		// Remove system path
		$file = mb_substr($file, mb_strlen(SYSTEM_PATH));

		// Setup backtrace array
		$backtrace = array();
		
		// Show a backtrace (if in development mode)
		if(config::get('debug_mode'))
		{
			// Get backtrace
			if($backtrace = backtrace(5))
			{
				// Remove the first element (this function)
				array_shift($backtrace);
				
				// Format the backtrace
				$backtrace = self::backtrace($backtrace);
			}
			
		}
	
		// If we should also log the error
		if(config('log_errors'))
		{
			log_message($error.' in file '.$file.' on line '.$line);
		}
		
		// Set view data
		$data = array(
			'title'		=> self::$error_codes[$code],
			'message'	=> $error,
			'backtrace'	=> $backtrace,
			'line'		=> $line,
			'file'		=> $file
		);

		// Load an error
		print load::error($data, NULL, 500);
		
		// If we should exit the script on error
		if(self::$is_fatal)
		{
			// Clean the output buffer(s) if one exists
			if(ob_get_level())
			{
				while (ob_get_level())
				{
					ob_end_flush();
				}
			}
				
			// Exit with an error status
			exit(1);
		}
		
		// Do not execute the PHP error handler
		return TRUE;
	}


	/**
	 * Display exception errors along with as much supporting information as
	 * posible (only if in "debug_mode") and then kill the script.
	 *
	 * @param object $e the Exception
	 */
	public static function exception_handler(Exception $e) {

		//print dump($e); For tricky exceptions!
		
		// If we should also log the error
		if(config('log_errors'))
		{
			log_message($e->getMessage().' in file '.$e->getFile().' on line '.$e->getLine());
		}
		
		// Something might fail - even in here!
		try {

			// Get exception information
			$title		= get_class($e);
			$code		= $e->getCode();
			$message	= $e->getMessage();
			$file		= $e->getFile();
			$line		= $e->getLine();
			$backtrace	= array();

			//Get Human-friendly error title
			if(isset(self::$error_codes[$code]))
			{
				$title = self::$error_codes[$code];
			}

			//Remove system path
			$file = mb_substr($file, mb_strlen(SYSTEM_PATH));

			//Show a backtrace (if in development mode)
			if(config::get('debug_mode'))
			{

				//Get backtrace
				$backtrace = $e->getTrace();

				if($backtrace)
				{
					//If this use to be an error...
					if ($e instanceof ErrorException)
					{
						// Remove the fist element (controller::*_handler())
						array_shift($backtrace);

						// Workaround for a bug in ErrorException::getTrace() that exists in
						// all PHP 5.2 versions. @see http://bugs.php.net/bug.php?id=45895
						// @author KohanaPHP.com
						if (version_compare(PHP_VERSION, '5.3', '<'))
						{
							for ($i = count($backtrace) - 1; $i > 0; --$i)
							{
								if (isset($backtrace[$i - 1]['args']))
								{
									// Re-position the args
									$backtrace[$i]['args'] = $backtrace[$i - 1]['args'];

									// Remove the args
									unset($backtrace[$i - 1]['args']);
								}
							}
						}

					}

					// Clean and filter the backtrace
					$backtrace = self::backtrace($backtrace);
				}
			}

			// Set view data
			$data = array(
				'title'		=> $title,
				'message'	=> $message,
				'backtrace'	=> $backtrace,
				'line'		=> $line,
				'file'		=> $file
			);

			// Load an error
			print load::error($data, NULL, 500);

		} catch (Exception $e) {

			print '<h2>Error while in Exception!</h2>';
			print $e->getMessage(). ' on line '. $e->getLine(). ' in '. $e->getFile();

		}

		// Clean the output buffer(s) if one exists
		if(ob_get_level())
		{
			while (ob_get_level())
			{
				ob_end_flush();
			}
		}

		// Exit with an error status
		exit(1);
	}


	/**
	 * Returns an HTML string highlighting a specific line of a file, with some
	 * number of lines padded above and below and optionally code highlighted.
	 *
	 * @author	KohanaPHP
	 * @param   string   file to open
	 * @param   integer  line number to highlight
	 * @param   integer  number of padding lines
	 * @param	boolean  highlight the file code?
	 * @return  string
	 */
	public static function debug_source($file, $line_number, $padding = 5, $highlight = TRUE)
	{
		// Open the file and set the line position
		$file = fopen($file, 'r');
		$line = 0;

		// Set the reading range
		$start = $line_number - $padding;
		$end = $line_number + $padding;

		// Set the zero-padding amount for line numbers
		$format = '% ' . strlen($end) . 'd';

		$source = '';
		while (($row = rtrim(fgets($file))) !== FALSE) {

			// Increment the line number
			if (++$line > $end) {
				break;
			}

			if ($line >= $start) {

				if( $highlight && function_exists('highlight_code') ) {

					// Highlight the code on this line
					$row = highlight_code($row, FALSE, FALSE);

					//Remove the <code> tag and any newlines
					$row = str_replace(array("\r", "\n", '<code>', '</code>', '<br />'), '', $row);
				}

				// Add the line number to row
				$row = '<span class="number">'.sprintf($format, $line).'</span> '. $row;

				// Highlight this row if it is the one we want
				if ($line === $line_number) {
					$row = '<span class="highlight_line">'. $row. '</span>';
				}

				// Add to the captured source
				$source .= $row. "\n";
			}
		}

		// Close the file
		fclose($file);

		return $source;
	}


	/**
	 * Filters the backtrace to make it ready to present to the user.
	 *
	 * @param array $backtrace the backtrace array
	 * @return array
	 */
	public static function backtrace(array $backtrace)
	{
		//Max backtrace levels
		if(count($backtrace) > 6)
		{
			$backtrace = array_chunk($backtrace, 6, TRUE);
			$backtrace = $backtrace[0];
		}

		// The final backtrace array
		$trace = array();

		// start backtrace
		foreach ($backtrace as $v)
		{

			//If any of these are missing then skip
			if ( ! isset($v['function'], $v['file'], $v['line']))
				continue;

			$v['source'] = '';

			if ( ! isset($v['class']))
			{
				$v['class'] = NULL;
			}
			
			if ( ! isset($v['type']))
			{
				$v['type'] = '::';
			}
			
			//Also get the source of the file
			if(file_exists($v['file']))
			{
				$v['source'] = self::debug_source($v['file'], $v['line']);
			}

			//Remove system path
			$v['file'] = mb_substr($v['file'], mb_strlen(SYSTEM_PATH));

			$args = array();
			if(isset($v['args']))
			{
				foreach ($v['args'] as $a)
				{
					$type = gettype($a);

					if($type == 'integer' OR $type == 'double'){
						$args[] = $a;
							
					} elseif ($type == 'string') {
						//Longer than 25 chars?
						$a = mb_strlen($a) > 50 ? mb_substr($a, 0, 50). '...' : $a;
						$args[] = '"' . htmlspecialchars($a, ENT_QUOTES, 'UTF-8') . '"';

					} elseif ($type == 'array') {
						$args[] = 'Array(' . count($a) . ')';

					} elseif ($type == 'object') {
						$args[] = 'Object(' . get_class($a) . ')';

					} elseif ($type == 'resource') {
						$args[] = 'Resource('.strstr($a, '#').')';

					} elseif ($type == 'boolean') {
						$args[] = ($a ? 'TRUE' : 'FALSE');

					} else {
						$args[] = $type;
					}
				}

				//If only a couple arguments were given - convert to string
				if(count($args) < 4)
				{
					$args = implode(', ', $args);
				}

			}

			// Save args
			$v['args'] = $args;

			//Add trace data
			$trace[] = $v;
		}

		// Return the final backtrace
		return $trace;
	}
}
Return current item: MicroMVC PHP Framework