Error_Handler.class.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Holds class PMA_Error_Handler
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. /**
  12. *
  13. */
  14. require_once './libraries/Error.class.php';
  15. /**
  16. * handling errors
  17. *
  18. * @package PhpMyAdmin
  19. */
  20. class PMA_Error_Handler
  21. {
  22. /**
  23. * holds errors to be displayed or reported later ...
  24. *
  25. * @var array of PMA_Error
  26. */
  27. protected $errors = array();
  28. /**
  29. * Constructor - set PHP error handler
  30. *
  31. */
  32. public function __construct()
  33. {
  34. /**
  35. * Do not set ourselves as error handler in case of testsuite.
  36. *
  37. * This behavior is not tested there and breaks other tests as they
  38. * rely on PHPUnit doing it's own error handling which we break here.
  39. */
  40. if (!defined('TESTSUITE')) {
  41. set_error_handler(array($this, 'handleError'));
  42. }
  43. }
  44. /**
  45. * Destructor
  46. *
  47. * stores errors in session
  48. *
  49. */
  50. public function __destruct()
  51. {
  52. if (isset($_SESSION)) {
  53. if (! isset($_SESSION['errors'])) {
  54. $_SESSION['errors'] = array();
  55. }
  56. // remember only not displayed errors
  57. foreach ($this->errors as $key => $error) {
  58. /**
  59. * We don't want to store all errors here as it would
  60. * explode user session.
  61. */
  62. if (count($_SESSION['errors']) >= 10) {
  63. $error = new PMA_Error(
  64. 0,
  65. __('Too many error messages, some are not displayed.'),
  66. __FILE__,
  67. __LINE__
  68. );
  69. $_SESSION['errors'][$error->getHash()] = $error;
  70. break;
  71. } else if (($error instanceof PMA_Error)
  72. && ! $error->isDisplayed()
  73. ) {
  74. $_SESSION['errors'][$key] = $error;
  75. }
  76. }
  77. }
  78. }
  79. /**
  80. * returns array with all errors
  81. *
  82. * @return array PMA_Error_Handler::$_errors
  83. */
  84. protected function getErrors()
  85. {
  86. $this->checkSavedErrors();
  87. return $this->errors;
  88. }
  89. /**
  90. * Error handler - called when errors are triggered/occurred
  91. *
  92. * This calls the addError() function, escaping the error string
  93. *
  94. * @param integer $errno error number
  95. * @param string $errstr error string
  96. * @param string $errfile error file
  97. * @param integer $errline error line
  98. *
  99. * @return void
  100. */
  101. public function handleError($errno, $errstr, $errfile, $errline)
  102. {
  103. $this->addError($errstr, $errno, $errfile, $errline, true);
  104. }
  105. /**
  106. * Add an error; can also be called directly (with or without escaping)
  107. *
  108. * The following error types cannot be handled with a user defined function:
  109. * E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR,
  110. * E_COMPILE_WARNING,
  111. * and most of E_STRICT raised in the file where set_error_handler() is called.
  112. *
  113. * Do not use the context parameter as we want to avoid storing the
  114. * complete $GLOBALS inside $_SESSION['errors']
  115. *
  116. * @param string $errstr error string
  117. * @param integer $errno error number
  118. * @param string $errfile error file
  119. * @param integer $errline error line
  120. * @param boolean $escape whether to escape the error string
  121. *
  122. * @return void
  123. */
  124. public function addError($errstr, $errno, $errfile, $errline, $escape = true)
  125. {
  126. if ($escape) {
  127. $errstr = htmlspecialchars($errstr);
  128. }
  129. // create error object
  130. $error = new PMA_Error(
  131. $errno,
  132. $errstr,
  133. $errfile,
  134. $errline
  135. );
  136. // do not repeat errors
  137. $this->errors[$error->getHash()] = $error;
  138. switch ($error->getNumber()) {
  139. case E_USER_NOTICE:
  140. case E_USER_WARNING:
  141. case E_STRICT:
  142. case E_DEPRECATED:
  143. case E_NOTICE:
  144. case E_WARNING:
  145. case E_CORE_WARNING:
  146. case E_COMPILE_WARNING:
  147. case E_USER_ERROR:
  148. case E_RECOVERABLE_ERROR:
  149. // just collect the error
  150. // display is called from outside
  151. break;
  152. case E_ERROR:
  153. case E_PARSE:
  154. case E_CORE_ERROR:
  155. case E_COMPILE_ERROR:
  156. default:
  157. // FATAL error, display it and exit
  158. $this->dispFatalError($error);
  159. exit;
  160. break;
  161. }
  162. }
  163. /**
  164. * log error to configured log facility
  165. *
  166. * @param PMA_Error $error the error
  167. *
  168. * @return bool
  169. *
  170. * @todo finish!
  171. */
  172. protected function logError($error)
  173. {
  174. return error_log($error->getMessage());
  175. }
  176. /**
  177. * trigger a custom error
  178. *
  179. * @param string $errorInfo error message
  180. * @param integer $errorNumber error number
  181. * @param string $file file name
  182. * @param integer $line line number
  183. *
  184. * @return void
  185. */
  186. public function triggerError($errorInfo, $errorNumber = null,
  187. $file = null, $line = null
  188. ) {
  189. // we could also extract file and line from backtrace
  190. // and call handleError() directly
  191. trigger_error($errorInfo, $errorNumber);
  192. }
  193. /**
  194. * display fatal error and exit
  195. *
  196. * @param PMA_Error $error the error
  197. *
  198. * @return void
  199. */
  200. protected function dispFatalError($error)
  201. {
  202. if (! headers_sent()) {
  203. $this->dispPageStart($error);
  204. }
  205. $error->display();
  206. $this->dispPageEnd();
  207. exit;
  208. }
  209. /**
  210. * Displays user errors not displayed
  211. *
  212. * @return void
  213. */
  214. public function dispUserErrors()
  215. {
  216. echo $this->getDispUserErrors();
  217. }
  218. /**
  219. * Renders user errors not displayed
  220. *
  221. * @return string
  222. */
  223. public function getDispUserErrors()
  224. {
  225. $retval = '';
  226. foreach ($this->getErrors() as $error) {
  227. if ($error->isUserError() && ! $error->isDisplayed()) {
  228. $retval .= $error->getDisplay();
  229. }
  230. }
  231. return $retval;
  232. }
  233. /**
  234. * display HTML header
  235. *
  236. * @param PMA_error $error the error
  237. *
  238. * @return void
  239. */
  240. protected function dispPageStart($error = null)
  241. {
  242. PMA_Response::getInstance()->disable();
  243. echo '<html><head><title>';
  244. if ($error) {
  245. echo $error->getTitle();
  246. } else {
  247. echo 'phpMyAdmin error reporting page';
  248. }
  249. echo '</title></head>';
  250. }
  251. /**
  252. * display HTML footer
  253. *
  254. * @return void
  255. */
  256. protected function dispPageEnd()
  257. {
  258. echo '</body></html>';
  259. }
  260. /**
  261. * renders errors not displayed
  262. *
  263. * @return string
  264. */
  265. public function getDispErrors()
  266. {
  267. $retval = '';
  268. if ($GLOBALS['cfg']['Error_Handler']['display']) {
  269. foreach ($this->getErrors() as $error) {
  270. if ($error instanceof PMA_Error) {
  271. if (! $error->isDisplayed()) {
  272. $retval .= $error->getDisplay();
  273. }
  274. } else {
  275. ob_start();
  276. var_dump($error);
  277. $retval .= ob_get_contents();
  278. ob_end_clean();
  279. }
  280. }
  281. } else {
  282. $retval .= $this->getDispUserErrors();
  283. }
  284. return $retval;
  285. }
  286. /**
  287. * displays errors not displayed
  288. *
  289. * @return void
  290. */
  291. public function dispErrors()
  292. {
  293. echo $this->getDispErrors();
  294. }
  295. /**
  296. * look in session for saved errors
  297. *
  298. * @return void
  299. */
  300. protected function checkSavedErrors()
  301. {
  302. if (isset($_SESSION['errors'])) {
  303. // restore saved errors
  304. foreach ($_SESSION['errors'] as $hash => $error) {
  305. if ($error instanceof PMA_Error && ! isset($this->errors[$hash])) {
  306. $this->errors[$hash] = $error;
  307. }
  308. }
  309. //$this->errors = array_merge($_SESSION['errors'], $this->errors);
  310. // delete stored errors
  311. $_SESSION['errors'] = array();
  312. unset($_SESSION['errors']);
  313. }
  314. }
  315. /**
  316. * return count of errors
  317. *
  318. * @return integer number of errors occoured
  319. */
  320. public function countErrors()
  321. {
  322. return count($this->getErrors());
  323. }
  324. /**
  325. * return count of user errors
  326. *
  327. * @return integer number of user errors occoured
  328. */
  329. public function countUserErrors()
  330. {
  331. $count = 0;
  332. if ($this->countErrors()) {
  333. foreach ($this->getErrors() as $error) {
  334. if ($error->isUserError()) {
  335. $count++;
  336. }
  337. }
  338. }
  339. return $count;
  340. }
  341. /**
  342. * whether use errors occurred or not
  343. *
  344. * @return boolean
  345. */
  346. public function hasUserErrors()
  347. {
  348. return (bool) $this->countUserErrors();
  349. }
  350. /**
  351. * whether errors occurred or not
  352. *
  353. * @return boolean
  354. */
  355. public function hasErrors()
  356. {
  357. return (bool) $this->countErrors();
  358. }
  359. /**
  360. * number of errors to be displayed
  361. *
  362. * @return integer number of errors to be displayed
  363. */
  364. public function countDisplayErrors()
  365. {
  366. if ($GLOBALS['cfg']['Error_Handler']['display']) {
  367. return $this->countErrors();
  368. } else {
  369. return $this->countUserErrors();
  370. }
  371. }
  372. /**
  373. * whether there are errors to display or not
  374. *
  375. * @return boolean
  376. */
  377. public function hasDisplayErrors()
  378. {
  379. return (bool) $this->countDisplayErrors();
  380. }
  381. }
  382. ?>