MyErrorHandler.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. App::uses('ErrorHandler', 'Error');
  3. App::uses('CakeRequest', 'Network');
  4. App::uses('Router', 'Routing');
  5. App::uses('Utility', 'Tools.Utility');
  6. class MyErrorHandler extends ErrorHandler {
  7. /**
  8. * @var array
  9. */
  10. protected static $whitelist = [
  11. 'MissingControllerException',
  12. 'MissingActionException',
  13. 'MissingViewException',
  14. 'PrivateActionException',
  15. 'NotFoundException',
  16. ];
  17. /**
  18. * Override core one with the following enhancements/fixes:
  19. * - 404s log to a different domain
  20. * - IP, Referer and Browser-Infos are added for better error debugging/tracing
  21. */
  22. public static function handleException($exception) {
  23. $config = Configure::read('Exception');
  24. if (!empty($config['log'])) {
  25. $message = sprintf("[%s] %s\n%s\n%s",
  26. get_class($exception),
  27. $exception->getMessage(),
  28. $exception->getTraceAsString(),
  29. static::traceDetails()
  30. );
  31. $log = LOG_ERR;
  32. $exceptions = static::$whitelist;
  33. if (CakePlugin::loaded('Shim')) {
  34. $exceptions[] = 'RecordNotFoundException';
  35. }
  36. if (in_array(get_class($exception), $exceptions)) {
  37. $log = '404';
  38. }
  39. CakeLog::write($log, $message);
  40. }
  41. $renderer = $config['renderer'];
  42. if ($renderer !== 'ExceptionRenderer') {
  43. list($plugin, $renderer) = pluginSplit($renderer, true);
  44. App::uses($renderer, $plugin . 'Error');
  45. }
  46. try {
  47. $error = new $renderer($exception);
  48. $error->render();
  49. } catch (Exception $e) {
  50. set_error_handler(Configure::read('Error.handler')); // Should be using configured ErrorHandler
  51. Configure::write('Error.trace', false); // trace is useless here since it's internal
  52. $message = sprintf("[%s] %s\n%s\n%s", // Keeping same message format
  53. get_class($e),
  54. $e->getMessage(),
  55. $e->getTraceAsString(),
  56. static::traceDetails()
  57. );
  58. trigger_error($message, E_USER_ERROR);
  59. }
  60. }
  61. /**
  62. * Override core one with the following enhancements/fixes:
  63. * - 404s log to a different domain
  64. * - IP, Referer and Browser-Infos are added for better error debugging/tracing
  65. */
  66. public static function handleError($code, $description, $file = null, $line = null, $context = null) {
  67. if (error_reporting() === 0) {
  68. return false;
  69. }
  70. $errorConfig = Configure::read('Error');
  71. list($error, $log) = static::mapErrorCode($code);
  72. if ($log === LOG_ERR) {
  73. return static::handleFatalError($code, $description, $file, $line);
  74. }
  75. $debug = Configure::read('debug');
  76. if ($debug) {
  77. $data = [
  78. 'level' => $log,
  79. 'code' => $code,
  80. 'error' => $error,
  81. 'description' => $description,
  82. 'file' => $file,
  83. 'line' => $line,
  84. 'context' => $context,
  85. 'start' => 2,
  86. 'path' => Debugger::trimPath($file)
  87. ];
  88. return Debugger::getInstance()->outputError($data);
  89. } else {
  90. $message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']';
  91. if (!empty($errorConfig['trace'])) {
  92. $trace = Debugger::trace(['start' => 1, 'format' => 'log']);
  93. $message .= "\nTrace:\n" . $trace . "\n";
  94. $message .= static::traceDetails();
  95. }
  96. return CakeLog::write($log, $message);
  97. }
  98. }
  99. /**
  100. * Generate an error page when some fatal error happens.
  101. *
  102. * @param int $code Code of error
  103. * @param string $description Error description
  104. * @param string $file File on which error occurred
  105. * @param int $line Line that triggered the error
  106. * @return bool
  107. */
  108. public static function handleFatalError($code, $description, $file, $line) {
  109. $logMessage = 'Fatal Error (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']';
  110. CakeLog::write(LOG_ERR, $logMessage);
  111. $exceptionHandler = Configure::read('Exception.handler');
  112. if (!is_callable($exceptionHandler)) {
  113. return false;
  114. }
  115. if (ob_get_level()) {
  116. ob_end_clean();
  117. }
  118. if (Configure::read('debug')) {
  119. call_user_func($exceptionHandler, new FatalErrorException($description, 500, $file, $line));
  120. } else {
  121. call_user_func($exceptionHandler, new InternalErrorException());
  122. }
  123. return false;
  124. }
  125. /**
  126. * Append some more infos to better track down the error
  127. *
  128. * @return string
  129. */
  130. public static function traceDetails() {
  131. if (empty($_SERVER['REQUEST_URI']) || strpos($_SERVER['REQUEST_URI'], '/test.php?') === 0) {
  132. return '';
  133. }
  134. if (!class_exists('Utility') || !class_exists('Router')) {
  135. return '';
  136. }
  137. $currentUrl = Router::url(); //isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'n/a';
  138. $refererUrl = Utility::getReferer(); //Router::getRequest()->url().'
  139. $uid = (!empty($_SESSION) && !empty($_SESSION['Auth']['User']['id'])) ? $_SESSION['Auth']['User']['id'] : null;
  140. $data = [
  141. Utility::getClientIp(),
  142. $currentUrl . (!empty($refererUrl) ? (' (' . $refererUrl . ')') : ''),
  143. $uid,
  144. env('HTTP_USER_AGENT')
  145. ];
  146. return implode(' - ', $data);
  147. }
  148. }