_options['errorLevel'])) { $level = $this->_options['errorLevel']; } error_reporting($level); set_error_handler([$this, 'handleError'], $level); set_exception_handler([$this, 'handleException']); register_shutdown_function(function () { if (PHP_SAPI === 'cli') { return; } $error = error_get_last(); if (!is_array($error)) { return; } $fatals = [ E_USER_ERROR, E_ERROR, E_PARSE, ]; if (!in_array($error['type'], $fatals, true)) { return; } $this->handleFatalError( $error['type'], $error['message'], $error['file'], $error['line'] ); }); } /** * Set as the default error handler by CakePHP. * * Use config/error.php to customize or replace this error handler. * This function will use Debugger to display errors when debug > 0. And * will log errors to Log, when debug == 0. * * You can use the 'errorLevel' option to set what type of errors will be handled. * Stack traces for errors can be enabled with the 'trace' option. * * @param int $code Code of error * @param string $description Error description * @param string|null $file File on which error occurred * @param int|null $line Line that triggered the error * @param array|null $context Context * @return bool True if error was handled */ public function handleError($code, $description, $file = null, $line = null, $context = null) { if (error_reporting() === 0) { return false; } list($error, $log) = $this->mapErrorCode($code); if ($log === LOG_ERR) { return $this->handleFatalError($code, $description, $file, $line); } $data = [ 'level' => $log, 'code' => $code, 'error' => $error, 'description' => $description, 'file' => $file, 'line' => $line, ]; $debug = Configure::read('debug'); if ($debug) { $data += [ 'context' => $context, 'start' => 3, 'path' => Debugger::trimPath($file) ]; } $this->_displayError($data, $debug); $this->_logError($log, $data); return true; } /** * Handle uncaught exceptions. * * Uses a template method provided by subclasses to display errors in an * environment appropriate way. * * @param \Exception $exception Exception instance. * @return void * @throws \Exception When renderer class not found * @see http://php.net/manual/en/function.set-exception-handler.php */ public function handleException(\Exception $exception) { $this->_displayException($exception); $this->_logException($exception); $this->_stop($exception->getCode() ?: 1); } /** * Stop the process. * * Implemented in subclasses that need it. * * @param int $code Exit code. * @return void */ protected function _stop($code) { // Do nothing. } /** * Display/Log a fatal error. * * @param int $code Code of error * @param string $description Error description * @param string $file File on which error occurred * @param int $line Line that triggered the error * @return bool */ public function handleFatalError($code, $description, $file, $line) { $data = [ 'code' => $code, 'description' => $description, 'file' => $file, 'line' => $line, 'error' => 'Fatal Error', ]; $this->_logError(LOG_ERR, $data); $this->handleException(new FatalErrorException($description, 500, $file, $line)); return true; } /** * Log an error. * * @param string $level The level name of the log. * @param array $data Array of error data. * @return bool */ protected function _logError($level, $data) { $message = sprintf( '%s (%s): %s in [%s, line %s]', $data['error'], $data['code'], $data['description'], $data['file'], $data['line'] ); if (!empty($this->_options['trace'])) { $trace = Debugger::trace([ 'start' => 1, 'format' => 'log' ]); $message .= "\nTrace:\n" . $trace . "\n"; } $message .= "\n\n"; return Log::write($level, $message); } /** * Handles exception logging * * @param \Exception $exception Exception instance. * @return bool */ protected function _logException(\Exception $exception) { $config = $this->_options; if (empty($config['log'])) { return false; } if (!empty($config['skipLog'])) { foreach ((array)$config['skipLog'] as $class) { if ($exception instanceof $class) { return false; } } } return Log::error($this->_getMessage($exception)); } /** * Generates a formatted error message * * @param \Exception $exception Exception instance * @return string Formatted message */ protected function _getMessage(\Exception $exception) { $message = sprintf( "[%s] %s", get_class($exception), $exception->getMessage() ); if (method_exists($exception, 'getAttributes')) { $attributes = $exception->getAttributes(); if ($attributes) { $message .= "\nException Attributes: " . var_export($exception->getAttributes(), true); } } if (PHP_SAPI !== 'cli') { $request = Router::getRequest(); if ($request) { $message .= "\nRequest URL: " . $request->here(); } } $message .= "\nStack Trace:\n" . $exception->getTraceAsString() . "\n\n"; return $message; } /** * Map an error code into an Error word, and log location. * * @param int $code Error code to map * @return array Array of error word, and log location. */ public static function mapErrorCode($code) { $levelMap = [ E_PARSE => 'error', E_ERROR => 'error', E_CORE_ERROR => 'error', E_COMPILE_ERROR => 'error', E_USER_ERROR => 'error', E_WARNING => 'warning', E_USER_WARNING => 'warning', E_COMPILE_WARNING => 'warning', E_RECOVERABLE_ERROR => 'warning', E_NOTICE => 'notice', E_USER_NOTICE => 'notice', E_STRICT => 'strict', E_DEPRECATED => 'deprecated', E_USER_DEPRECATED => 'deprecated', ]; $logMap = [ 'error' => LOG_ERR, 'warning' => LOG_WARNING, 'notice' => LOG_NOTICE, 'strict' => LOG_NOTICE, 'deprecated' => LOG_NOTICE, ]; $error = $levelMap[$code]; $log = $logMap[$error]; return [ucfirst($error), $log]; } }