/fuel/core/classes/error.php
PHP | 306 lines | 201 code | 40 blank | 65 comment | 26 complexity | 07d1b62b27ba4b93ad64474c22f0b766 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, LGPL-2.1
- <?php
- /**
- * Part of the Fuel framework.
- *
- * @package Fuel
- * @version 1.6
- * @author Fuel Development Team
- * @license MIT License
- * @copyright 2010 - 2013 Fuel Development Team
- * @link http://fuelphp.com
- */
- namespace Fuel\Core;
- /**
- * Exception class for standard PHP errors, this will make them catchable
- */
- class PhpErrorException extends \ErrorException
- {
- public static $count = 0;
- /**
- * Allow the error handler from recovering from error types defined in the config
- */
- public function recover()
- {
- // handle the error based on the config and the environment we're in
- if (static::$count <= Config::get('errors.throttle', 10))
- {
- logger(\Fuel::L_ERROR, $this->code.' - '.$this->message.' in '.$this->file.' on line '.$this->line);
- if (\Fuel::$env != \Fuel::PRODUCTION and ($this->code & error_reporting()) == $this->code)
- {
- static::$count++;
- \Error::show_php_error(new \ErrorException($this->message, $this->code, 0, $this->file, $this->line));
- }
- }
- elseif (\Fuel::$env != \Fuel::PRODUCTION
- and static::$count == (\Config::get('errors.throttle', 10) + 1)
- and ($this->severity & error_reporting()) == $this->severity)
- {
- static::$count++;
- \Error::notice('Error throttling threshold was reached, no more full error reports are shown.', true);
- }
- }
- }
- /**
- *
- */
- class Error
- {
- public static $levels = array(
- 0 => 'Error',
- 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'
- );
- public static $fatal_levels = array(E_PARSE, E_ERROR, E_USER_ERROR, E_COMPILE_ERROR);
- public static $non_fatal_cache = array();
- /**
- * Native PHP shutdown handler
- *
- * @return string
- */
- public static function shutdown_handler()
- {
- $last_error = error_get_last();
- // Only show valid fatal errors
- if ($last_error AND in_array($last_error['type'], static::$fatal_levels))
- {
- $severity = static::$levels[$last_error['type']];
- logger(\Fuel::L_ERROR, $severity.' - '.$last_error['message'].' in '.$last_error['file'].' on line '.$last_error['line']);
- $error = new \ErrorException($last_error['message'], $last_error['type'], 0, $last_error['file'], $last_error['line']);
- if (\Fuel::$env != \Fuel::PRODUCTION)
- {
- static::show_php_error($error);
- }
- else
- {
- static::show_production_error($error);
- }
- exit(1);
- }
- }
- /**
- * PHP Exception handler
- *
- * @param Exception $e the exception
- * @return bool
- */
- public static function exception_handler(\Exception $e)
- {
- if (method_exists($e, 'handle'))
- {
- return $e->handle();
- }
- $severity = ( ! isset(static::$levels[$e->getCode()])) ? $e->getCode() : static::$levels[$e->getCode()];
- logger(\Fuel::L_ERROR, $severity.' - '.$e->getMessage().' in '.$e->getFile().' on line '.$e->getLine());
- if (\Fuel::$env != \Fuel::PRODUCTION)
- {
- static::show_php_error($e);
- }
- else
- {
- static::show_production_error($e);
- }
- }
- /**
- * PHP Error handler
- *
- * @param int $severity the severity code
- * @param string $message the error message
- * @param string $filepath the path to the file throwing the error
- * @param int $line the line number of the error
- * @return bool whether to continue with execution
- */
- public static function error_handler($severity, $message, $filepath, $line)
- {
- // don't do anything if error reporting is disabled
- if (error_reporting() !== 0)
- {
- $fatal = (bool)( ! in_array($severity, \Config::get('errors.continue_on', array())));
- if ($fatal)
- {
- throw new \PhpErrorException($message, $severity, 0, $filepath, $line);
- }
- else
- {
- // non-fatal, recover from the error
- $e = new \PhpErrorException($message, $severity, 0, $filepath, $line);
- $e->recover();
- }
- }
- return true;
- }
- /**
- * Shows an error. It will stop script execution if the error code is not
- * in the errors.continue_on whitelist.
- *
- * @param Exception $e the exception to show
- * @return void
- */
- public static function show_php_error(\Exception $e)
- {
- $fatal = (bool)( ! in_array($e->getCode(), \Config::get('errors.continue_on', array())));
- $data = static::prepare_exception($e, $fatal);
- if ($fatal)
- {
- $data['contents'] = ob_get_contents();
- while (ob_get_level() > 0)
- {
- ob_end_clean();
- }
- ob_start(\Config::get('ob_callback', null));
- }
- else
- {
- static::$non_fatal_cache[] = $data;
- }
- if (\Fuel::$is_cli)
- {
- \Cli::write(\Cli::color($data['severity'].' - '.$data['message'].' in '.\Fuel::clean_path($data['filepath']).' on line '.$data['error_line'], 'red'));
- return;
- }
- if ($fatal)
- {
- if ( ! headers_sent())
- {
- $protocol = \Input::server('SERVER_PROTOCOL') ? \Input::server('SERVER_PROTOCOL') : 'HTTP/1.1';
- header($protocol.' 500 Internal Server Error');
- }
- $data['non_fatal'] = static::$non_fatal_cache;
- try
- {
- exit(\View::forge('errors'.DS.'php_fatal_error', $data, false));
- }
- catch (\FuelException $view_exception)
- {
- exit($data['severity'].' - '.$data['message'].' in '.\Fuel::clean_path($data['filepath']).' on line '.$data['error_line']);
- }
- }
- try
- {
- echo \View::forge('errors'.DS.'php_error', $data, false);
- }
- catch (\FuelException $e)
- {
- echo $e->getMessage().'<br />';
- }
- }
- /**
- * Shows a small notice error, only when not in production or when forced.
- * This is used by several libraries to notify the developer of certain things.
- *
- * @param string $msg the message to display
- * @param bool $always_show whether to force display the notice or not
- * @return void
- */
- public static function notice($msg, $always_show = false)
- {
- $trace = array_merge(array('file' => '(unknown)', 'line' => '(unknown)'), \Arr::get(debug_backtrace(), 1));
- logger(\Fuel::L_DEBUG, 'Notice - '.$msg.' in '.$trace['file'].' on line '.$trace['line']);
- if (\Fuel::$is_test or ( ! $always_show and (\Fuel::$env == \Fuel::PRODUCTION or \Config::get('errors.notices', true) === false)))
- {
- return;
- }
- $data['message'] = $msg;
- $data['type'] = 'Notice';
- $data['filepath'] = \Fuel::clean_path($trace['file']);
- $data['line'] = $trace['line'];
- $data['function'] = $trace['function'];
- echo \View::forge('errors'.DS.'php_short', $data, false);
- }
- /**
- * Shows the errors/production view and exits. This only gets
- * called when an error occurs in production mode.
- *
- * @return void
- */
- public static function show_production_error(\Exception $e)
- {
- // when we're on CLI, always show the php error
- if (\Fuel::$is_cli)
- {
- return static::show_php_error($e);
- }
- if ( ! headers_sent())
- {
- $protocol = \Input::server('SERVER_PROTOCOL') ? \Input::server('SERVER_PROTOCOL') : 'HTTP/1.1';
- header($protocol.' 500 Internal Server Error');
- }
- exit(\View::forge('errors'.DS.'production'));
- }
- protected static function prepare_exception(\Exception $e, $fatal = true)
- {
- $data = array();
- $data['type'] = get_class($e);
- $data['severity'] = $e->getCode();
- $data['message'] = $e->getMessage();
- $data['filepath'] = $e->getFile();
- $data['error_line'] = $e->getLine();
- $data['backtrace'] = $e->getTrace();
- $data['severity'] = ( ! isset(static::$levels[$data['severity']])) ? $data['severity'] : static::$levels[$data['severity']];
- foreach ($data['backtrace'] as $key => $trace)
- {
- if ( ! isset($trace['file']))
- {
- unset($data['backtrace'][$key]);
- }
- elseif ($trace['file'] == COREPATH.'classes/error.php')
- {
- unset($data['backtrace'][$key]);
- }
- }
- $data['debug_lines'] = \Debug::file_lines($data['filepath'], $data['error_line'], $fatal);
- $data['orig_filepath'] = $data['filepath'];
- $data['filepath'] = \Fuel::clean_path($data['filepath']);
- $data['filepath'] = str_replace("\\", "/", $data['filepath']);
- return $data;
- }
- }