Exceptions.php CI Explained

I’ve stopped work on this series to start a new one for CI 3.

Introduction

This post is part of a series which explains the CodeIgniter (CI) source code. This post explains the CI 2.1.3 Exceptions class.

./system/core/Exceptions.php

Code

/**
 * Exceptions Class
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Exceptions
 * @author		ExpressionEngine Dev Team
 * @link		http://codeigniter.com/user_guide/libraries/exceptions.html
 */
class CI_Exceptions {

CI_Exceptions class declaration beginning.

Code

	var $action;
	var $severity;
	var $message;
	var $filename;
	var $line;

Properties which pertain to a single PHP error.

Code

	/**
	 * Nesting level of the output buffering mechanism
	 *
	 * @var int
	 * @access public
	 */
	var $ob_level;

Code

	/**
	 * List if available error levels
	 *
	 * @var array
	 * @access public
	 */
	var $levels = 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'
					);

Code: __construct()

	/**
	 * Constructor
	 */
	public function __construct()
	{
		$this->ob_level = ob_get_level();
		// Note:  Do not log messages from this constructor.
	}

Q: What is PHP output buffering?

A: PHP manual says: The Output Control functions allow you to control when output is sent from the script. This can be useful in several different situations, especially if you need to send headers to the browser after your script has began outputting data. The Output Control functions do not affect headers sent using header() or setcookie(), only functions such as echo and data between blocks of PHP code.

Q: What does ob_level() return?

Return the nesting level of the output buffering mechanism

Code: log_exception()

	/**
	 * Exception Logger
	 *
	 * This function logs PHP generated error messages
	 *
	 * @access	private
	 * @param	string	the error severity
	 * @param	string	the error string
	 * @param	string	the error filepath
	 * @param	string	the error line number
	 * @return	string
	 */
	function log_exception($severity, $message, $filepath, $line)
	{
		$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];

		log_message('error', 'Severity: '.$severity.'  --> '.$message. ' '.$filepath.' '.$line, TRUE);
	}

Defines method log_exception(); which logs a PHP generated error message.

If $severity value is not the key of one of the set elements of the $levels array then allow the value of $severity to remain the same. Otherwise, set the value of $severity to $this->levels[$severity] .

Most likely the severity logged will be one of the values from the level array. Otherwise, it will be a custom string.

Code: show_404()

	/**
	 * 404 Page Not Found Handler
	 *
	 * @access	private
	 * @param	string	the page
	 * @param 	bool	log error yes/no
	 * @return	string
	 */
	function show_404($page = '', $log_error = TRUE)
	{
		$heading = "404 Page Not Found";
		$message = "The page you requested was not found.";

		// By default we log this, but allow a dev to skip it
		if ($log_error)
		{
			log_message('error', '404 Page Not Found --> '.$page);
		}

		echo $this->show_error($heading, $message, 'error_404', 404);
		exit;
	}

What show_404() does:

  1. Takes the file-name of the missing page and a Boolean which determines whether the error should be logged.
  2. Logs the 404 error if it should.
  3. Displays an HTML formatted page specifying that there’s been a 404 and the file-name of the missing page.
  4. Terminates everything.

Code: show_error()

	/**
	 * General Error Page
	 *
	 * This function takes an error message as input
	 * (either as a string or an array) and displays
	 * it using the specified template.
	 *
	 * @access	private
	 * @param	string	the heading
	 * @param	string	the message
	 * @param	string	the template name
	 * @param 	int		the status code
	 * @return	string
	 */
	function show_error($heading, $message, $template = 'error_general', $status_code = 500)
	{
		set_status_header($status_code);

		$message = '<p>'.implode('</p><p>', ( ! is_array($message)) ? array($message) : $message).'</p>';

		if (ob_get_level() > $this->ob_level + 1)
		{
			ob_end_flush();
		}
		ob_start();
		include(APPPATH.'errors/'.$template.'.php');
		$buffer = ob_get_contents();
		ob_end_clean();
		return $buffer;
	}

NOTE: show_error() returns a string. It does NOT display anything.

Code:

set_status_header($status_code);

Sends the specified ($status_code) status header to the web server. See the more detailed description ..

Code:

$message = '<p>'.implode('</p><p>', ( ! is_array($message)) ? array($message) : $message).'</p>';

Transforms $message to a string consisting of HTML paragraphs; where each paragraph is a single message from the original $message.

more detailed explanation

if (ob_get_level() > $this->ob_level + 1)
{
	ob_end_flush();
}

I don’t fully understand output buffering but this is what I think the previous code snippet does:

If the output buffering level has gone up by 2 or more from the time the Exceptions object was instantiated then send the topmost buffer’s content to the browser now.

The code does this now to empty the last output buffer before it starts a new buffer (and starts operating exclusively with buffers.)

Next:

ob_start();

Q: What’s ob_start() ?

A: This function will turn output buffering on. While output buffering is active no output is sent from the script (other than headers), instead the output is stored in an internal buffer. Output buffers are stackable, that is, you may call ob_start() while another ob_start() is active. Just make sure that you call ob_end_flush() the appropriate number of times.

Next:

include(APPPATH.'errors/'.$template.'.php');

Sends the HTML for the error page to the output buffer. This page will have $heading and $message embedded in it.

$buffer = ob_get_contents();
ob_end_clean();
return $buffer;

Does:

  1. Assign the output buffer content to $buffer .
  2. Clean (erase) the output buffer and turn off output buffering
  3. Return $buffer .

Code: show_php_error()

	/**
	 * Native PHP error handler
	 *
	 * @access	private
	 * @param	string	the error severity
	 * @param	string	the error string
	 * @param	string	the error filepath
	 * @param	string	the error line number
	 * @return	string
	 */
	function show_php_error($severity, $message, $filepath, $line)
	{
		$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];

		$filepath = str_replace("\\", "/", $filepath);

		// For safety reasons we do not show the full file path
		if (FALSE !== strpos($filepath, '/'))
		{
			$x = explode('/', $filepath);
			$filepath = $x[count($x)-2].'/'.end($x);
		}

		if (ob_get_level() > $this->ob_level + 1)
		{
			ob_end_flush();
		}
		ob_start();
		include(APPPATH.'errors/error_php.php');
		$buffer = ob_get_contents();
		ob_end_clean();
		echo $buffer;
	}

I’ll describe the code piece-by-piece.

$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];

If $severity value is not the key of one of the set elements of the $levels array then allow the value of $severity to remain the same. Otherwise, set the value of $severity to $this->levels[$severity] .

$filepath = str_replace("\\", "/", $filepath);

Replace any "\\" with a "/" in $filename.

// For safety reasons we do not show the full file path
if (FALSE !== strpos($filepath, '/'))
{
	$x = explode('/', $filepath);
	$filepath = $x[count($x)-2].'/'.end($x);
}

If there is no '/' in $filepath then:

  1. $x becomes an array of all the segments of $filepath
  2. transform the file path into one which only has the last two segments
if (ob_get_level() > $this->ob_level + 1)
{
	ob_end_flush();
}
ob_start();
include(APPPATH.'errors/error_php.php');
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;

Output a div containing the error message.

See methods above which have a more in-depth explanation.

Advertisements

About samehramzylabib

See About on https://samehramzylabib.wordpress.com
This entry was posted in CI Source Code Explained. Bookmark the permalink.

2 Responses to Exceptions.php CI Explained

  1. Pingback: Use a PHP Function and Include Together to Output HTML | Sam's PHP

  2. Pingback: Common.php CI Explained | Sam's PHP

Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s