PageRenderTime 49ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/fuel/core/classes/error.php

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