Cake/Error/ErrorHandler.php
| 1 | <?php |
|---|---|
| 2 | /** |
| 3 | * Error handler |
| 4 | * |
| 5 | * Provides Error Capturing for Framework errors. |
| 6 | * |
| 7 | * PHP 5 |
| 8 | * |
| 9 | * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) |
| 10 | * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) |
| 11 | * |
| 12 | * Licensed under The MIT License |
| 13 | * Redistributions of files must retain the above copyright notice. |
| 14 | * |
| 15 | * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) |
| 16 | * @link http://cakephp.org CakePHP(tm) Project |
| 17 | * @package Cake.Error |
| 18 | * @since CakePHP(tm) v 0.10.5.1732 |
| 19 | * @license MIT License (http://www.opensource.org/licenses/mit-license.php) |
| 20 | */ |
| 21 | |
| 22 | App::uses('Debugger', 'Utility'); |
| 23 | App::uses('CakeLog', 'Log'); |
| 24 | App::uses('ExceptionRenderer', 'Error'); |
| 25 | App::uses('AppController', 'Controller'); |
| 26 | |
| 27 | /** |
| 28 | * |
| 29 | * Error Handler provides basic error and exception handling for your application. It captures and |
| 30 | * handles all unhandled exceptions and errors. Displays helpful framework errors when debug > 1. |
| 31 | * |
| 32 | * ### Uncaught exceptions |
| 33 | * |
| 34 | * When debug < 1 a CakeException will render 404 or 500 errors. If an uncaught exception is thrown |
| 35 | * and it is a type that ErrorHandler does not know about it will be treated as a 500 error. |
| 36 | * |
| 37 | * ### Implementing application specific exception handling |
| 38 | * |
| 39 | * You can implement application specific exception handling in one of a few ways. Each approach |
| 40 | * gives you different amounts of control over the exception handling process. |
| 41 | * |
| 42 | * - Set Configure::write('Exception.handler', 'YourClass::yourMethod'); |
| 43 | * - Create AppController::appError(); |
| 44 | * - Set Configure::write('Exception.renderer', 'YourClass'); |
| 45 | * |
| 46 | * #### Create your own Exception handler with `Exception.handler` |
| 47 | * |
| 48 | * This gives you full control over the exception handling process. The class you choose should be |
| 49 | * loaded in your app/Config/bootstrap.php, so its available to handle any exceptions. You can |
| 50 | * define the handler as any callback type. Using Exception.handler overrides all other exception |
| 51 | * handling settings and logic. |
| 52 | * |
| 53 | * #### Using `AppController::appError();` |
| 54 | * |
| 55 | * This controller method is called instead of the default exception rendering. It receives the |
| 56 | * thrown exception as its only argument. You should implement your error handling in that method. |
| 57 | * Using AppController::appError(), will supersede any configuration for Exception.renderer. |
| 58 | * |
| 59 | * #### Using a custom renderer with `Exception.renderer` |
| 60 | * |
| 61 | * If you don't want to take control of the exception handling, but want to change how exceptions are |
| 62 | * rendered you can use `Exception.renderer` to choose a class to render exception pages. By default |
| 63 | * `ExceptionRenderer` is used. Your custom exception renderer class should be placed in app/Lib/Error. |
| 64 | * |
| 65 | * Your custom renderer should expect an exception in its constructor, and implement a render method. |
| 66 | * Failing to do so will cause additional errors. |
| 67 | * |
| 68 | * #### Logging exceptions |
| 69 | * |
| 70 | * Using the built-in exception handling, you can log all the exceptions |
| 71 | * that are dealt with by ErrorHandler by setting `Exception.log` to true in your core.php. |
| 72 | * Enabling this will log every exception to CakeLog and the configured loggers. |
| 73 | * |
| 74 | * ### PHP errors |
| 75 | * |
| 76 | * Error handler also provides the built in features for handling php errors (trigger_error). |
| 77 | * While in debug mode, errors will be output to the screen using debugger. While in production mode, |
| 78 | * errors will be logged to CakeLog. You can control which errors are logged by setting |
| 79 | * `Error.level` in your core.php. |
| 80 | * |
| 81 | * #### Logging errors |
| 82 | * |
| 83 | * When ErrorHandler is used for handling errors, you can enable error logging by setting `Error.log` to true. |
| 84 | * This will log all errors to the configured log handlers. |
| 85 | * |
| 86 | * #### Controlling what errors are logged/displayed |
| 87 | * |
| 88 | * You can control which errors are logged / displayed by ErrorHandler by setting `Error.level`. Setting this |
| 89 | * to one or a combination of a few of the E_* constants will only enable the specified errors. |
| 90 | * |
| 91 | * e.g. `Configure::write('Error.level', E_ALL & ~E_NOTICE);` |
| 92 | * |
| 93 | * Would enable handling for all non Notice errors. |
| 94 | * |
| 95 | * @package Cake.Error |
| 96 | * @see ExceptionRenderer for more information on how to customize exception rendering. |
| 97 | */ |
| 98 | class ErrorHandler { |
| 99 | |
| 100 | /** |
| 101 | * Set as the default exception handler by the CakePHP bootstrap process. |
| 102 | * |
| 103 | * This will either use custom exception renderer class if configured, |
| 104 | * or use the default ExceptionRenderer. |
| 105 | * |
| 106 | * @param Exception $exception |
| 107 | * @return void |
| 108 | * @see http://php.net/manual/en/function.set-exception-handler.php |
| 109 | */ |
| 110 | public static function handleException(Exception $exception) { |
| 111 | $config = Configure::read('Exception'); |
| 112 | if (!empty($config['log'])) { |
| 113 | $message = sprintf("[%s] %s\n%s", |
| 114 | get_class($exception), |
| 115 | $exception->getMessage(), |
| 116 | $exception->getTraceAsString() |
| 117 | ); |
| 118 | CakeLog::write(LOG_ERR, $message); |
| 119 | } |
| 120 | $renderer = $config['renderer']; |
| 121 | if ($renderer !== 'ExceptionRenderer') { |
| 122 | list($plugin, $renderer) = pluginSplit($renderer, true); |
| 123 | App::uses($renderer, $plugin . 'Error'); |
| 124 | } |
| 125 | try { |
| 126 | $error = new $renderer($exception); |
| 127 | $error->render(); |
| 128 | } catch (Exception $e) { |
| 129 | set_error_handler(Configure::read('Error.handler')); // Should be using configured ErrorHandler |
| 130 | Configure::write('Error.trace', false); // trace is useless here since it's internal |
| 131 | $message = sprintf("[%s] %s\n%s", // Keeping same message format |
| 132 | get_class($e), |
| 133 | $e->getMessage(), |
| 134 | $e->getTraceAsString() |
| 135 | ); |
| 136 | trigger_error($message, E_USER_ERROR); |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | /** |
| 141 | * Set as the default error handler by CakePHP. Use Configure::write('Error.handler', $callback), to use your own |
| 142 | * error handling methods. This function will use Debugger to display errors when debug > 0. And |
| 143 | * will log errors to CakeLog, when debug == 0. |
| 144 | * |
| 145 | * You can use Configure::write('Error.level', $value); to set what type of errors will be handled here. |
| 146 | * Stack traces for errors can be enabled with Configure::write('Error.trace', true); |
| 147 | * |
| 148 | * @param integer $code Code of error |
| 149 | * @param string $description Error description |
| 150 | * @param string $file File on which error occurred |
| 151 | * @param integer $line Line that triggered the error |
| 152 | * @param array $context Context |
| 153 | * @return boolean true if error was handled |
| 154 | */ |
| 155 | public static function handleError($code, $description, $file = null, $line = null, $context = null) { |
| 156 | if (error_reporting() === 0) { |
| 157 | return false; |
| 158 | } |
| 159 | $errorConfig = Configure::read('Error'); |
| 160 | list($error, $log) = self::mapErrorCode($code); |
| 161 | |
| 162 | $debug = Configure::read('debug'); |
| 163 | if ($debug) { |
| 164 | $data = array( |
| 165 | 'level' => $log, |
| 166 | 'code' => $code, |
| 167 | 'error' => $error, |
| 168 | 'description' => $description, |
| 169 | 'file' => $file, |
| 170 | 'line' => $line, |
| 171 | 'context' => $context, |
| 172 | 'start' => 2, |
| 173 | 'path' => Debugger::trimPath($file) |
| 174 | ); |
| 175 | return Debugger::getInstance()->outputError($data); |
| 176 | } else { |
| 177 | $message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'; |
| 178 | if (!empty($errorConfig['trace'])) { |
| 179 | $trace = Debugger::trace(array('start' => 1, 'format' => 'log')); |
| 180 | $message .= "\nTrace:\n" . $trace . "\n"; |
| 181 | } |
| 182 | return CakeLog::write($log, $message); |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Map an error code into an Error word, and log location. |
| 188 | * |
| 189 | * @param integer $code Error code to map |
| 190 | * @return array Array of error word, and log location. |
| 191 | */ |
| 192 | public static function mapErrorCode($code) { |
| 193 | $error = $log = null; |
| 194 | switch ($code) { |
| 195 | case E_PARSE: |
| 196 | case E_ERROR: |
| 197 | case E_CORE_ERROR: |
| 198 | case E_COMPILE_ERROR: |
| 199 | case E_USER_ERROR: |
| 200 | $error = 'Fatal Error'; |
| 201 | $log = LOG_ERROR; |
| 202 | break; |
| 203 | case E_WARNING: |
| 204 | case E_USER_WARNING: |
| 205 | case E_COMPILE_WARNING: |
| 206 | case E_RECOVERABLE_ERROR: |
| 207 | $error = 'Warning'; |
| 208 | $log = LOG_WARNING; |
| 209 | break; |
| 210 | case E_NOTICE: |
| 211 | case E_USER_NOTICE: |
| 212 | $error = 'Notice'; |
| 213 | $log = LOG_NOTICE; |
| 214 | break; |
| 215 | case E_STRICT: |
| 216 | $error = 'Strict'; |
| 217 | $log = LOG_NOTICE; |
| 218 | break; |
| 219 | case E_DEPRECATED: |
| 220 | case E_USER_DEPRECATED: |
| 221 | $error = 'Deprecated'; |
| 222 | $log = LOG_NOTICE; |
| 223 | break; |
| 224 | } |
| 225 | return array($error, $log); |
| 226 | } |
| 227 | |
| 228 | } |
| 229 | |
| 230 |
