PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/error.php

http://github.com/fuel/core
PHP | 274 lines | 182 code | 39 blank | 53 comment | 24 complexity | 6ce74bc8aefb6054942a36f266b37d04 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2012 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. class Error
  14. {
  15. public static $levels = array(
  16. 0 => 'Error',
  17. E_ERROR => 'Error',
  18. E_WARNING => 'Warning',
  19. E_PARSE => 'Parsing Error',
  20. E_NOTICE => 'Notice',
  21. E_CORE_ERROR => 'Core Error',
  22. E_CORE_WARNING => 'Core Warning',
  23. E_COMPILE_ERROR => 'Compile Error',
  24. E_COMPILE_WARNING => 'Compile Warning',
  25. E_USER_ERROR => 'User Error',
  26. E_USER_WARNING => 'User Warning',
  27. E_USER_NOTICE => 'User Notice',
  28. E_STRICT => 'Runtime Notice'
  29. );
  30. public static $fatal_levels = array(E_PARSE, E_ERROR, E_USER_ERROR, E_COMPILE_ERROR);
  31. public static $count = 0;
  32. public static $non_fatal_cache = array();
  33. /**
  34. * Native PHP shutdown handler
  35. *
  36. * @return string
  37. */
  38. public static function shutdown_handler()
  39. {
  40. $last_error = error_get_last();
  41. // Only show valid fatal errors
  42. if ($last_error AND in_array($last_error['type'], static::$fatal_levels))
  43. {
  44. $severity = static::$levels[$last_error['type']];
  45. logger(\Fuel::L_ERROR, $severity.' - '.$last_error['message'].' in '.$last_error['file'].' on line '.$last_error['line']);
  46. $error = new \ErrorException($last_error['message'], $last_error['type'], 0, $last_error['file'], $last_error['line']);
  47. if (\Fuel::$env != \Fuel::PRODUCTION)
  48. {
  49. static::show_php_error($error);
  50. }
  51. else
  52. {
  53. static::show_production_error($error);
  54. }
  55. exit(1);
  56. }
  57. }
  58. /**
  59. * PHP Exception handler
  60. *
  61. * @param Exception $e the exception
  62. * @return bool
  63. */
  64. public static function exception_handler(\Exception $e)
  65. {
  66. if (method_exists($e, 'handle'))
  67. {
  68. return $e->handle();
  69. }
  70. $severity = ( ! isset(static::$levels[$e->getCode()])) ? $e->getCode() : static::$levels[$e->getCode()];
  71. logger(\Fuel::L_ERROR, $severity.' - '.$e->getMessage().' in '.$e->getFile().' on line '.$e->getLine());
  72. if (\Fuel::$env != \Fuel::PRODUCTION)
  73. {
  74. static::show_php_error($e);
  75. }
  76. else
  77. {
  78. static::show_production_error($e);
  79. }
  80. }
  81. /**
  82. * PHP Error handler
  83. *
  84. * @param int $severity the severity code
  85. * @param string $message the error message
  86. * @param string $filepath the path to the file throwing the error
  87. * @param int $line the line number of the error
  88. * @return bool whether to continue with execution
  89. */
  90. public static function error_handler($severity, $message, $filepath, $line)
  91. {
  92. if (static::$count <= Config::get('errors.throttling', 10))
  93. {
  94. logger(\Fuel::L_ERROR, $severity.' - '.$message.' in '.$filepath.' on line '.$line);
  95. if (\Fuel::$env != \Fuel::PRODUCTION and ($severity & error_reporting()) == $severity)
  96. {
  97. static::$count++;
  98. static::show_php_error(new \ErrorException($message, $severity, 0, $filepath, $line));
  99. }
  100. }
  101. elseif (\Fuel::$env != \Fuel::PRODUCTION
  102. and static::$count == (\Config::get('error_throttling', 10) + 1)
  103. and ($severity & error_reporting()) == $severity)
  104. {
  105. static::$count++;
  106. static::notice('Error throttling threshold was reached, no more full error reports are shown.', true);
  107. }
  108. return true;
  109. }
  110. /**
  111. * Shows an error. It will stop script execution if the error code is not
  112. * in the errors.continue_on whitelist.
  113. *
  114. * @param Exception $e the exception to show
  115. * @return void
  116. */
  117. public static function show_php_error(\Exception $e)
  118. {
  119. $fatal = (bool)( ! in_array($e->getCode(), \Config::get('errors.continue_on', array())));
  120. $data = static::prepare_exception($e, $fatal);
  121. if ($fatal)
  122. {
  123. $data['contents'] = ob_get_contents();
  124. while (ob_get_level() > 0)
  125. {
  126. ob_end_clean();
  127. }
  128. ob_start(\Config::get('ob_callback', null));
  129. }
  130. else
  131. {
  132. static::$non_fatal_cache[] = $data;
  133. }
  134. if (\Fuel::$is_cli)
  135. {
  136. \Cli::write(\Cli::color($data['severity'].' - '.$data['message'].' in '.\Fuel::clean_path($data['filepath']).' on line '.$data['error_line'], 'red'));
  137. return;
  138. }
  139. if ($fatal)
  140. {
  141. if ( ! headers_sent())
  142. {
  143. $protocol = \Input::server('SERVER_PROTOCOL') ? \Input::server('SERVER_PROTOCOL') : 'HTTP/1.1';
  144. header($protocol.' 500 Internal Server Error');
  145. }
  146. $data['non_fatal'] = static::$non_fatal_cache;
  147. try
  148. {
  149. exit(\View::forge('errors'.DS.'php_fatal_error', $data, false));
  150. }
  151. catch (\FuelException $view_exception)
  152. {
  153. exit($data['severity'].' - '.$data['message'].' in '.\Fuel::clean_path($data['filepath']).' on line '.$data['error_line']);
  154. }
  155. }
  156. try
  157. {
  158. echo \View::forge('errors'.DS.'php_error', $data, false);
  159. }
  160. catch (\FuelException $e)
  161. {
  162. echo $e->getMessage().'<br />';
  163. }
  164. }
  165. /**
  166. * Shows a small notice error, only when not in production or when forced.
  167. * This is used by several libraries to notify the developer of certain things.
  168. *
  169. * @param string $msg the message to display
  170. * @param bool $always_show whether to force display the notice or not
  171. * @return void
  172. */
  173. public static function notice($msg, $always_show = false)
  174. {
  175. $trace = array_merge(array('file' => '(unknown)', 'line' => '(unknown)'), \Arr::element(debug_backtrace(), 1));
  176. logger(\Fuel::L_DEBUG, 'Notice - '.$msg.' in '.$trace['file'].' on line '.$trace['line']);
  177. if (\Fuel::$is_test or ( ! $always_show and (\Fuel::$env == \Fuel::PRODUCTION or \Config::get('errors.notices', true) === false)))
  178. {
  179. return;
  180. }
  181. $data['message'] = $msg;
  182. $data['type'] = 'Notice';
  183. $data['filepath'] = \Fuel::clean_path($trace['file']);
  184. $data['line'] = $trace['line'];
  185. $data['function'] = $trace['function'];
  186. echo \View::forge('errors'.DS.'php_short', $data, false);
  187. }
  188. /**
  189. * Shows the errors/production view and exits. This only gets
  190. * called when an error occurs in production mode.
  191. *
  192. * @return void
  193. */
  194. public static function show_production_error(\Exception $e)
  195. {
  196. // when we're on CLI, always show the php error
  197. if (\Fuel::$is_cli)
  198. {
  199. return static::show_php_error($e);
  200. }
  201. if ( ! headers_sent())
  202. {
  203. $protocol = \Input::server('SERVER_PROTOCOL') ? \Input::server('SERVER_PROTOCOL') : 'HTTP/1.1';
  204. header($protocol.' 500 Internal Server Error');
  205. }
  206. exit(\View::forge('errors'.DS.'production'));
  207. }
  208. protected static function prepare_exception(\Exception $e, $fatal = true)
  209. {
  210. $data = array();
  211. $data['type'] = get_class($e);
  212. $data['severity'] = $e->getCode();
  213. $data['message'] = $e->getMessage();
  214. $data['filepath'] = $e->getFile();
  215. $data['error_line'] = $e->getLine();
  216. $data['backtrace'] = $e->getTrace();
  217. $data['severity'] = ( ! isset(static::$levels[$data['severity']])) ? $data['severity'] : static::$levels[$data['severity']];
  218. foreach ($data['backtrace'] as $key => $trace)
  219. {
  220. if ( ! isset($trace['file']))
  221. {
  222. unset($data['backtrace'][$key]);
  223. }
  224. elseif ($trace['file'] == COREPATH.'classes/error.php')
  225. {
  226. unset($data['backtrace'][$key]);
  227. }
  228. }
  229. $data['debug_lines'] = \Debug::file_lines($data['filepath'], $data['error_line'], $fatal);
  230. $data['orig_filepath'] = $data['filepath'];
  231. $data['filepath'] = \Fuel::clean_path($data['filepath']);
  232. $data['filepath'] = str_replace("\\", "/", $data['filepath']);
  233. return $data;
  234. }
  235. }