Teknik is a suite of services with attractive and functional interfaces. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Error.php 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik;
  10. use Piwik\Common;
  11. use Piwik\Log;
  12. use Piwik\Piwik;
  13. use Piwik\Version;
  14. require_once PIWIK_INCLUDE_PATH . '/core/Log.php';
  15. /**
  16. * Holds PHP error information (non-exception errors). Also contains log formatting logic
  17. * for PHP errors and Piwik's error handler function.
  18. */
  19. class Error
  20. {
  21. /**
  22. * The backtrace string to use when testing.
  23. *
  24. * @var string
  25. */
  26. public static $debugBacktraceForTests = null;
  27. /**
  28. * The error number. See http://php.net/manual/en/errorfunc.constants.php#errorfunc.constants.errorlevels
  29. *
  30. * @var int
  31. */
  32. public $errno;
  33. /**
  34. * The error message.
  35. *
  36. * @var string
  37. */
  38. public $errstr;
  39. /**
  40. * The file in which the error occurred.
  41. *
  42. * @var string
  43. */
  44. public $errfile;
  45. /**
  46. * The line number on which the error occurred.
  47. *
  48. * @var int
  49. */
  50. public $errline;
  51. /**
  52. * The error backtrace.
  53. *
  54. * @var string
  55. */
  56. public $backtrace;
  57. /**
  58. * Constructor.
  59. *
  60. * @param int $errno
  61. * @param string $errstr
  62. * @param string $errfile
  63. * @param int $errline
  64. * @param string $backtrace
  65. */
  66. public function __construct($errno, $errstr, $errfile, $errline, $backtrace)
  67. {
  68. $this->errno = $errno;
  69. $this->errstr = $errstr;
  70. $this->errfile = $errfile;
  71. $this->errline = $errline;
  72. $this->backtrace = $backtrace;
  73. }
  74. /**
  75. * Returns a string description of a PHP error number.
  76. *
  77. * @param int $errno `E_ERROR`, `E_WARNING`, `E_PARSE`, etc.
  78. * @return string
  79. */
  80. public static function getErrNoString($errno)
  81. {
  82. switch ($errno) {
  83. case E_ERROR:
  84. return "Error";
  85. case E_WARNING:
  86. return "Warning";
  87. case E_PARSE:
  88. return "Parse Error";
  89. case E_NOTICE:
  90. return "Notice";
  91. case E_CORE_ERROR:
  92. return "Core Error";
  93. case E_CORE_WARNING:
  94. return "Core Warning";
  95. case E_COMPILE_ERROR:
  96. return "Compile Error";
  97. case E_COMPILE_WARNING:
  98. return "Compile Warning";
  99. case E_USER_ERROR:
  100. return "User Error";
  101. case E_USER_WARNING:
  102. return "User Warning";
  103. case E_USER_NOTICE:
  104. return "User Notice";
  105. case E_STRICT:
  106. return "Strict Notice";
  107. case E_RECOVERABLE_ERROR:
  108. return "Recoverable Error";
  109. case E_DEPRECATED:
  110. return "Deprecated";
  111. case E_USER_DEPRECATED:
  112. return "User Deprecated";
  113. default:
  114. return "Unknown error ($errno)";
  115. }
  116. }
  117. public static function formatFileAndDBLogMessage(&$message, $level, $tag, $datetime, $log)
  118. {
  119. if ($message instanceof Error) {
  120. $message = $message->errfile . '(' . $message->errline . '): ' . Error::getErrNoString($message->errno)
  121. . ' - ' . $message->errstr . "\n" . $message->backtrace;
  122. $message = $log->formatMessage($level, $tag, $datetime, $message);
  123. }
  124. }
  125. public static function formatScreenMessage(&$message, $level, $tag, $datetime, $log)
  126. {
  127. if ($message instanceof Error) {
  128. $errno = $message->errno & error_reporting();
  129. // problem when using error_reporting with the @ silent fail operator
  130. // it gives an errno 0, and in this case the objective is to NOT display anything on the screen!
  131. // is there any other case where the errno is zero at this point?
  132. if ($errno == 0) {
  133. $message = false;
  134. return;
  135. }
  136. Common::sendHeader('Content-Type: text/html; charset=utf-8');
  137. $htmlString = '';
  138. $htmlString .= "\n<div style='word-wrap: break-word; border: 3px solid red; padding:4px; width:70%; background-color:#FFFF96;'>
  139. <strong>There is an error. Please report the message (Piwik " . (class_exists('Piwik\Version') ? Version::VERSION : '') . ")
  140. and full backtrace in the <a href='?module=Proxy&action=redirect&url=http://forum.piwik.org' target='_blank'>Piwik forums</a> (please do a Search first as it might have been reported already!).<br /><br/>
  141. ";
  142. $htmlString .= Error::getErrNoString($message->errno);
  143. $htmlString .= ":</strong> <em>{$message->errstr}</em> in <strong>{$message->errfile}</strong>";
  144. $htmlString .= " on line <strong>{$message->errline}</strong>\n";
  145. $htmlString .= "<br /><br />Backtrace --&gt;<div style=\"font-family:Courier;font-size:10pt\"><br />\n";
  146. $htmlString .= str_replace("\n", "<br />\n", $message->backtrace);
  147. $htmlString .= "</div><br />";
  148. $htmlString .= "\n </pre></div><br />";
  149. $message = $htmlString;
  150. }
  151. }
  152. public static function setErrorHandler()
  153. {
  154. Piwik::addAction('Log.formatFileMessage', array('\\Piwik\\Error', 'formatFileAndDBLogMessage'));
  155. Piwik::addAction('Log.formatDatabaseMessage', array('\\Piwik\\Error', 'formatFileAndDBLogMessage'));
  156. Piwik::addAction('Log.formatScreenMessage', array('\\Piwik\\Error', 'formatScreenMessage'));
  157. set_error_handler(array('\\Piwik\\Error', 'errorHandler'));
  158. }
  159. public static function errorHandler($errno, $errstr, $errfile, $errline)
  160. {
  161. // if the error has been suppressed by the @ we don't handle the error
  162. if (error_reporting() == 0) {
  163. return;
  164. }
  165. $backtrace = '';
  166. if (empty(self::$debugBacktraceForTests)) {
  167. $bt = @debug_backtrace();
  168. if ($bt !== null && isset($bt[0])) {
  169. foreach ($bt as $i => $debug) {
  170. $backtrace .= "#$i "
  171. . (isset($debug['class']) ? $debug['class'] : '')
  172. . (isset($debug['type']) ? $debug['type'] : '')
  173. . (isset($debug['function']) ? $debug['function'] : '')
  174. . '(...) called at ['
  175. . (isset($debug['file']) ? $debug['file'] : '') . ':'
  176. . (isset($debug['line']) ? $debug['line'] : '') . ']' . "\n";
  177. }
  178. }
  179. } else {
  180. $backtrace = self::$debugBacktraceForTests;
  181. }
  182. $error = new Error($errno, $errstr, $errfile, $errline, $backtrace);
  183. Log::error($error);
  184. switch ($errno) {
  185. case E_ERROR:
  186. case E_PARSE:
  187. case E_CORE_ERROR:
  188. case E_CORE_WARNING:
  189. case E_COMPILE_ERROR:
  190. case E_COMPILE_WARNING:
  191. case E_USER_ERROR:
  192. exit;
  193. break;
  194. case E_WARNING:
  195. case E_NOTICE:
  196. case E_USER_WARNING:
  197. case E_USER_NOTICE:
  198. case E_STRICT:
  199. case E_RECOVERABLE_ERROR:
  200. case E_DEPRECATED:
  201. case E_USER_DEPRECATED:
  202. default:
  203. // do not exit
  204. break;
  205. }
  206. }
  207. }