PageRenderTime 13ms CodeModel.GetById 2ms app.highlight 7ms RepoModel.GetById 2ms app.codeStats 0ms

/system/classes/Exceptions.class.php

http://mortar.googlecode.com/
PHP | 409 lines | 204 code | 52 blank | 153 comment | 36 complexity | 44879cc919353f755de8543e22ecb69c MD5 | raw file
  1<?php
  2/**
  3 * MortarExceptions
  4 *
  5 * While originally developed for Mortar, these exceptions are completely stand alone and are very easy to integrate
  6 * into existing projects. Developers can either call the different exceptions directly or create inheriting exception
  7 * classes for the different objects in their projects. Since this library will include the exception's class name when
  8 * logging or displaying errors the latter method is preferred.
  9 *
 10 * MortarException - 0
 11 * MortarError - E_ERROR
 12 * MortarWarning - E_WARNING
 13 * MortarNotice - E_NOTICE
 14 * MortarDepreciated - E_USER_DEPRECATED
 15 * MortarUserError - E_USER_ERROR
 16 * MortarUserWarning - E_USER_WARNING
 17 * MortarUserNotice - E_USER_NOTICE
 18 *
 19 * @copyright Copyright (c) 2009, Robert Hafner
 20 * @license http://www.opensource.org/licenses/bsd-license.php
 21 */
 22
 23/*
 24  Copyright (c) 2009, Robert Hafner
 25  All rights reserved.
 26
 27  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 28  following conditions are met:
 29
 30	* Redistributions of source code must retain the above copyright notice, this list of conditions and the following
 31		disclaimer.
 32	* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 33		following disclaimer in the documentation and/or other materials provided with the distribution.
 34	* Neither the name of the "Mortar" nor the names of its contributors may be used to endorse or promote
 35		products derived from this software without specific prior written permission.
 36
 37  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 38  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 39  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 41  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 42  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 43  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 44*/
 45
 46
 47
 48if(!defined('EXCEPTION_OUTPUT'))
 49{
 50	/**
 51	 * Defines the format which should be used for displaying errors- 'text', 'html' and 'simple' are accepted. This
 52	 * can be defined by developers as long as it's done before this file is loaded.
 53	 */
 54	define('EXCEPTION_OUTPUT', (defined('STDIN') ? 'text' : 'html'));
 55}
 56
 57/**
 58 * MortarException
 59 *
 60 * This class acts as the base for all the other exception classes. It outputs errors and a stack trace when the
 61 * debugging level is high enough. This class itself, while having the display and logging functions built in, is
 62 * designed as a drop in replacement for the Exception class and therefore does not actually log or display anything.
 63 */
 64class MortarException extends Exception
 65{
 66	/**
 67	 * Each exception inheriting from this class should define this using one of the php error constants (E_ERROR,
 68	 * E_WARNING, E_NOTICE, etc) so this class can emulate php actions using the php.ini values.
 69	 *
 70	 * @var int
 71	 */
 72	protected $errorType = 0;
 73
 74	/**
 75	 * Initializes the exception and passes itself off to the static function "handleError", using the errorType
 76	 * property as the errorLevel for that function. Additionally, if the function "runAction" exists it is called.
 77	 *
 78	 * @param string $message
 79	 * @param int $code This should be left blank or replaced with an error code
 80	 */
 81	public function __construct($message = '', $code = 0)
 82	{
 83		parent::__construct($message, $code);
 84		static::handleError($this, $this->errorType);
 85		if(method_exists($this, 'runAction'))
 86			$this->runAction();
 87	}
 88
 89	/**
 90	 * Takes in any exception (including those not related to this library) and processes them as an error using the
 91	 * errorLevel argument. Various error configuration values are extracted from the php runtime, such as the error
 92	 * reporting and logging values, and if it's appropriate the exception is displayed or sent to the php logger.
 93	 *
 94	 * @param Exception $e
 95	 * @param int $errorLevel This should correspond to the various php error constants (E_ERROR, E_WARNING, etc)
 96	 */
 97	static public function handleError(Exception $e, $errorLevel = null)
 98	{
 99		if(!isset($errorLevel))
100		{
101			$errorLevel = 0; // I could just make this the default argument, but I'd prefer knowing whether something
102							 // was passed or not.
103		}elseif(!is_numeric($errorLevel)){
104			$errorLevel = E_ALL | E_STRICT;
105		}
106
107		$error_reporting = error_reporting();
108
109		$display_error = ini_get('display_errors');
110		$display_error = (strtolower($display_error) == 'on' || $display_error == true);
111
112		$track_error = ini_get('track_errors');
113		$track_error = (strtolower($track_error) == 'on' || $track_error == true);
114
115		$log_error = ini_get('log_errors');
116		$log_error = (strtolower($log_error) == 'on' || $log_error == true);
117
118		$exception_format = defined('EXCEPTION_OUTPUT') ? strtolower(EXCEPTION_OUTPUT) : 'html';
119
120		if($track_error || $log_error || ($display_error && $exception_format == 'simple'))
121			$errorSimpleText = static::getAsSimpleText($e);
122
123		if($track_error == true || strtolower($track_error) == 'on')
124		{
125			global $php_errormsg;
126			$php_errormsg = $errorSimpleText;
127		}
128
129		if($error_reporting & $errorLevel) // boolean &, not conditional &&
130		{
131			if($log_error)
132				static::log($errorSimpleText);
133
134			if($display_error)
135			{
136				switch($exception_format)
137				{
138					case 'text':
139						echo static::getAsText($e) . PHP_EOL . PHP_EOL;
140						break;
141					case 'simple':
142						echo $errorSimpleText . PHP_EOL . PHP_EOL;
143						break;
144
145					default:
146					case 'html':
147						echo static::getAsHtml($e) . PHP_EOL;
148						break;
149				}
150			}
151		}
152	}
153
154	/**
155	 * Logs the passed string using the php error logging functions. Anything passed here will end up in the PHP log,
156	 * whether that log is run by file, syslog, or anything else.
157	 *
158	 * @param string $logString The string to be logged.
159	 * @return bool Status of log attempt.
160	 */
161	static public function log($logString)
162	{
163		$logString = str_replace(PHP_EOL, ' ', $logString);
164		$program = defined('PROGRAM') ? '*' . PROGRAM . '*  ' : '';
165		$logText = $program . $logString;
166		return error_log($logText);
167	}
168
169	/**
170	 * Returns a single line description of the passed exception, suitable for sending to logging functions.
171	 *
172	 * @param Exception $e
173	 * @return string One line description of the passed exception.
174	 */
175	static public function getAsSimpleText(Exception $e)
176	{
177		$file = $e->getFile();
178		$line = $e->getLine();
179		$message = $e->getMessage();
180		$code = $e->getCode();
181		$errorClass = get_class($e);
182		$output = $$errorClass . '(' . $code . '): "' . $message;
183		$output .= '" in file: ' . $file . ':' . $line;
184		return $output;
185	}
186
187	/**
188	 * Returns an extended description of the exception, typically used for cli output although it can also be used
189	 * inside applications for extended logging.
190	 *
191	 * @param Exception $e
192	 * @return string Extended breakdown of exception, including the stack trace.
193	 */
194	static public function getAsText(Exception $e)
195	{
196		// Add header
197		$output = PHP_EOL . '*****' . PHP_EOL;;
198		$file = $e->getFile();
199		$line = $e->getLine();
200		$message = $e->getMessage();
201		$code = $e->getCode();
202		$errorClass = get_class($e);
203		$program = defined('PROGRAM') ? PROGRAM . ': ' : '';
204		$output .= '*  ' . $program . $errorClass . '(' . $code . '): ' . $message . PHP_EOL;
205		$output .= '*    in ' . $file . ' on line ' . $line . PHP_EOL;
206
207		// Add Call Stack
208		$stack = array_reverse($e->getTrace());
209		if(isset($stack[0]))
210		{
211			$output .= '*' . PHP_EOL;
212			$output .= '*   Call Stack:' . PHP_EOL;
213		}
214
215		foreach($stack as $index => $line)
216		{
217			$function = '';
218			if(isset($line['class']))
219				$function = $line['class'] . $line['type'];
220
221			$function .= $line['function'];
222
223			if(isset($line['args']) && count($line['args']) > 0)
224			{
225				$argString = '';
226				foreach($line['args'] as $argument)
227				{
228					$argString .= is_object($argument) ? get_class($argument) : $argument;
229					$argString .= ', ';
230				}
231				$argString = rtrim($argString, ', ');
232				$function .= '(' . $argString . ')';
233			}else{
234				$function .= '()';
235			}
236
237			$output .= '*      ' . ($index + 1) . '. ' . $function . PHP_EOL;
238
239			if(isset($line['file']) && isset($line['line']))
240				$output .= '*          ' . $line['file'] . ':' . $line['line'] . PHP_EOL;
241			$output .= '*' . PHP_EOL;
242		}
243
244		return $output . '*****';
245	}
246
247	/**
248	 * Returns an extended description of the exception formatted in html, typically used to output errors by the
249	 * handleError function when display logging is enabled.
250	 *
251	 * @param Exception $e
252	 * @return string Extended breakdown of exception formatted in html.
253	 */
254	static public function getAsHtml(Exception $e)
255	{
256		$file = $e->getFile();
257		$line = $e->getLine();
258		$message = $e->getMessage();
259		$code = $e->getCode();
260
261		$errorClass = get_class($e);
262		$output = "<font size='1'><table class='Core-error' dir='ltr' border='1' cellspacing='0' cellpadding='2'>
263<tr><th align='left' bgcolor='#f57900' colspan='4'>( ! ) " . $errorClass . ": {$message} in <br>{$file} on line <i>{$line}</i></th></tr>
264<tr>
265<td colspan='3' cellspacing='0' cellpadding='0'>
266	<table class='Core-error' dir='ltr' border='1' cellspacing='0' cellpadding='2' width='100%'>
267	<th align='left' bgcolor='#e9b96e' colspan='3'>Call Stack</th></tr>
268	<tr>
269		<th align='center' bgcolor='#eeeeec'>#</th>
270		<!--<th align='center' bgcolor='#eeeeec'>Time</th>-->
271		<th align='left' bgcolor='#eeeeec'>Function</th>
272		<th align='left' bgcolor='#eeeeec'>Location</th>
273	</tr>";
274
275		$stack = array_reverse($e->getTrace());
276
277		$x = 0;
278		foreach($stack as $traceLine)
279		{
280			$x++;
281
282			if(is_array($traceLine['args']))
283			{
284				$argValueShort = '';
285				$argString = '';
286				$argStringLong = '';
287				$comma = ' ';
288				foreach($traceLine['args'] as $argName => $argValue)
289				{
290					if(is_string($argValue))
291					{
292
293					}elseif(is_object($argValue)){
294						$argValue = get_class($argValue);
295					}
296
297					if(is_array($argValue))
298						$argValue = var_export($argValue, true);
299
300					$argString .= $comma .( (strlen($argValue) > '8') ? substr($argValue, '0', 6) . '..' : $argValue);
301					$argStringLong .= $comma . $argValue;
302					$comma = ', ';
303				}
304				$argString = rtrim($argString, ',');
305				$argStringLong = rtrim($argStringLong, ',');
306
307			}else{
308				$argString = ' ';
309			}
310
311			if((isset($traceLine['file'])))
312			{
313				$shortPath = defined('BASE_PATH') ? str_replace(BASE_PATH, '/', $traceLine['file']) : $traceLine['file'];
314			}else{
315				$shortPath = 'Global';
316				$traceLine['file'] = '';
317				$traceLine['line'] = '';
318			}
319
320			$functionName = '';
321
322			if(isset($traceLine['class']))
323				$functionName .= $traceLine['class'];
324
325			if(isset($traceLine['type']))
326				$functionName .= $traceLine['type'];
327
328			$functionName .= $traceLine['function'];
329
330			$output .= "<tr>
331	<td bgcolor='#eeeeec' align='center'>$x</td>
332	<!--<td bgcolor='#eeeeec' align='center'>Time</td>-->
333	<td title='{$functionName}({$argStringLong})' bgcolor='#eeeeec'>{$functionName}({$argString})</td>
334	<td title='{$traceLine['file']}' bgcolor='#eeeeec'>{$shortPath}<b>:</b>{$traceLine['line']}</td>
335</tr>";
336		}
337
338		$output .= '</table></font>
339		</td></tr></table>
340		<br>';
341
342		return $output;
343	}
344}
345
346
347/**
348 * MortarError
349 *
350 * This class corresponds to the E_ERROR error level in php, meaning that when E_ERROR is enabled by php (whether by the
351 * php.ini file or a runtime configuration change) then it will check to see if error logging or displaying are also
352 * activated, and if so will take the appropriate action.
353 */
354class MortarError extends MortarException { protected $errorType = E_ERROR; }
355
356/**
357 * MortarWarning
358 *
359 * This class corresponds to the E_WARNING error level in php, meaning that when E_WARNING is enabled by php (whether by
360 * the php.ini file or a runtime configuration change) then it will check to see if error logging or displaying are also
361 * activated, and if so will take the appropriate action.
362 */
363class MortarWarning extends MortarError { protected $errorType = E_WARNING; }
364
365/**
366 * MortarNotice
367 *
368 * This class corresponds to the E_NOTICE error level in php, meaning that when E_NOTICE is enabled by php (whether by
369 * the php.ini file or a runtime configuration change) then it will check to see if error logging or displaying are also
370 * activated, and if so will take the appropriate action.
371 */
372class MortarNotice extends MortarError { protected $errorType = E_NOTICE; }
373
374/**
375 * MortarDepreciated
376 *
377 * This class corresponds to the E_USER_DEPRECATED error level in php, meaning that when E_USER_DEPRECATED is enabled by
378 * php (whether by the php.ini file or a runtime configuration change) then it will check to see if error logging or
379 * displaying are also activated, and if so will take the appropriate action.
380 */
381class MortarDepreciated extends MortarError { protected $errorType = E_USER_DEPRECATED; }
382
383/**
384 * MortarUserError
385 *
386 * This class corresponds to the E_USER_ERROR error level in php, meaning that when E_USER_ERROR is enabled by php
387 * (whether by the php.ini file or a runtime configuration change) then it will check to see if error logging or
388 * displaying are also activated, and if so will take the appropriate action.
389 */
390class MortarUserError extends MortarError { protected $errorType = E_USER_ERROR; }
391
392/**
393 * MortarError
394 *
395 * This class corresponds to the E_USER_WARNING error level in php, meaning that when E_USER_WARNING is enabled by php
396 * (whether by the php.ini file or a runtime configuration change) then it will check to see if error logging or
397 * displaying are also activated, and if so will take the appropriate action.
398 */
399class MortarUserWarning extends MortarError { protected $errorType = E_USER_WARNING; }
400
401/**
402 * MortarUserNotice
403 *
404 * This class corresponds to the E_USER_NOTICE error level in php, meaning that when E_USER_NOTICE is enabled by php
405 * (whether by the php.ini file or a runtime configuration change) then it will check to see if error logging or
406 * displaying are also activated, and if so will take the appropriate action.
407 */
408class MortarUserNotice extends MortarError { protected $errorType = E_USER_NOTICE; }
409?>