PHP系统异常处理类程序

以前我们用过的异常处理函数都是单个的,下面我找到一个非常的不错的异常处理类系统,不但可以控制错误还能给出好的界面哦.

PHP系统异常处理类程序代码如下:

  1. <?php
  2. // 自定义异常函数
  3. set_exception_handler('handle_exception');
  4. // 自定义错误函数
  5. set_error_handler('handle_error');
  6. /**
  7. * 异常处理
  8. *
  9. * @param mixed $exception 异常对象
  10. * @author www.phpfensi.com
  11. */
  12. function handle_exception($exception) {
  13. Error::exceptionError($exception);
  14. }
  15. /**
  16. * 错误处理
  17. *
  18. * @param string $errNo 错误代码
  19. * @param string $errStr 错误信息
  20. * @param string $errFile 出错文件
  21. * @param string $errLine 出错行
  22. * @author www.phpfensi.com
  23. */
  24. function handle_error($errNo, $errStr, $errFile, $errLine) {
  25. if ($errNo) {
  26. Error::systemError($errStr, false, true, false);
  27. }
  28. }
  29. /**
  30. * 系统错误处理
  31. *
  32. * @author www.phpfensi.com
  33. */
  34. class Error {
  35. public static function systemError($message, $show = true, $save = true, $halt = true) {
  36. list($showTrace, $logTrace) = self::debugBacktrace();
  37. if ($save) {
  38. $messageSave = '<b>' . $message . '</b><br /><b>PHP:</b>' . $logTrace;
  39. self::writeErrorLog($messageSave);
  40. }
  41. if ($show) {
  42. self::showError('system', "<li>$message</li>", $showTrace, 0);
  43. }
  44. if ($halt) {
  45. exit();
  46. } else {
  47. return $message;
  48. }
  49. }
  50. /**
  51. * 代码执行过程回溯信息
  52. *
  53. * @static
  54. * @access public
  55. */
  56. public static function debugBacktrace() {
  57. $skipFunc[] = 'Error->debugBacktrace';
  58. $show = $log = '';
  59. $debugBacktrace = debug_backtrace();
  60. ksort($debugBacktrace);
  61. foreach ($debugBacktrace as $k => $error) {
  62. if (!isset($error['file'])) {
  63. // 利用反射API来获取方法/函数所在的文件和行数
  64. try {
  65. if (isset($error['class'])) {
  66. $reflection = new ReflectionMethod($error['class'], $error['function']);
  67. } else {
  68. $reflection = new ReflectionFunction($error['function']);
  69. }
  70. $error['file'] = $reflection->getFileName();
  71. $error['line'] = $reflection->getStartLine();
  72. } catch (Exception $e) {
  73. continue;
  74. }
  75. }
  76. $file = str_replace(SITE_PATH, '', $error['file']);
  77. $func = isset($error['class']) ? $error['class'] : '';
  78. $func .= isset($error['type']) ? $error['type'] : '';
  79. $func .= isset($error['function']) ? $error['function'] : '';
  80. if (in_array($func, $skipFunc)) {
  81. break;
  82. }
  83. $error['line'] = sprintf('%04d', $error['line']);
  84. $show .= '<li>[Line: ' . $error['line'] . ']' . $file . '(' . $func . ')</li>';
  85. $log .= !emptyempty($log) ? ' -> ' : '';
  86. $log .= $file . ':' . $error['line'];
  87. }
  88. return array($show, $log);
  89. }
  90. /**
  91. * 异常处理
  92. *
  93. * @static
  94. * @access public
  95. * @param mixed $exception
  96. */
  97. public static function exceptionError($exception) {
  98. if ($exception instanceof DbException) {
  99. $type = 'db';
  100. } else {
  101. $type = 'system';
  102. }
  103. if ($type == 'db') {
  104. $errorMsg = '(' . $exception->getCode() . ') ';
  105. $errorMsg .= self::sqlClear($exception->getMessage(), $exception->getDbConfig());
  106. if ($exception->getSql()) {
  107. $errorMsg .= '<div class="sql">';
  108. $errorMsg .= self::sqlClear($exception->getSql(), $exception->getDbConfig());
  109. $errorMsg .= '</div>';
  110. }
  111. } else {
  112. $errorMsg = $exception->getMessage();
  113. }
  114. $trace = $exception->getTrace();
  115. krsort($trace);
  116. $trace[] = array('file' => $exception->getFile(), 'line' => $exception->getLine(), 'function' => 'break');
  117. $phpMsg = array();
  118. foreach ($trace as $error) {
  119. if (!emptyempty($error['function'])) {
  120. $fun = '';
  121. if (!emptyempty($error['class'])) {
  122. $fun .= $error['class'] . $error['type'];
  123. }
  124. $fun .= $error['function'] . '(';
  125. if (!emptyempty($error['args'])) {
  126. $mark = '';
  127. foreach ($error['args'] as $arg) {
  128. $fun .= $mark;
  129. if (is_array($arg)) {
  130. $fun .= 'Array';
  131. } elseif (is_bool($arg)) {
  132. $fun .= $arg ? 'true' : 'false';
  133. } elseif (is_int($arg)) {
  134. $fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? $arg : '%d';
  135. } elseif (is_float($arg)) {
  136. $fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? $arg : '%f';
  137. } else {
  138. $fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? ''' . htmlspecialchars(substr(self::clear($arg), 0, 10)) . (strlen($arg) > 10 ? ' ...' : '') . ''' : '%s';
  139. }
  140. $mark = ', ';
  141. }
  142. }
  143. $fun .= ')';
  144. $error['function'] = $fun;
  145. }
  146. if (!isset($error['line'])) {
  147. continue;
  148. }
  149. $phpMsg[] = array('file' => str_replace(array(SITE_PATH, '\'), array('', '/'), $error['file']), 'line' => $error['line'], 'function' => $error['function']);
  150. }
  151. self::showError($type, $errorMsg, $phpMsg);
  152. exit();
  153. }
  154. /**
  155. * 记录错误日志
  156. *
  157. * @static
  158. * @access public
  159. * @param string $message
  160. */
  161. public static function writeErrorLog($message) {
  162. return false; // 暂时不写入 www.phpfensi.com
  163. $message = self::clear($message);
  164. $time = time();
  165. $file = LOG_PATH . '/' . date('Y.m.d') . '_errorlog.php';
  166. $hash = md5($message);
  167. $userId = 0;
  168. $ip = get_client_ip();
  169. $user = '<b>User:</b> user; IP=' . $ip . '; RIP:' . $_SERVER['REMOTE_ADDR'];
  170. $uri = 'Request: ' . htmlspecialchars(self::clear($_SERVER['REQUEST_URI']));
  171. $message = "<?php exit;?> {$time} $message $hash $user $uri ";
  172. // 判断该$message是否在时间间隔$maxtime内已记录过,有,则不用再记录了
  173. if (is_file($file)) {
  174. $fp = @fopen($file, 'rb');
  175. $lastlen = 50000; // 读取最后的 $lastlen 长度字节内容
  176. $maxtime = 60 * 10; // 时间间隔:10分钟
  177. $offset = filesize($file) - $lastlen;
  178. if ($offset > 0) {
  179. fseek($fp, $offset);
  180. }
  181. if ($data = fread($fp, $lastlen)) {
  182. $array = explode(" ", $data);
  183. if (is_array($array))
  184. foreach ($array as $key => $val) {
  185. $row = explode(" ", $val);
  186. if ($row[0] != '<?php exit;?>') {
  187. continue;
  188. }
  189. if ($row[3] == $hash && ($row[1] > $time - $maxtime)) {
  190. return;
  191. }
  192. }
  193. }
  194. }
  195. error_log($message, 3, $file);
  196. }
  197. /**
  198. * 清除文本部分字符
  199. *
  200. * @param string $message
  201. */
  202. public static function clear($message) {
  203. return str_replace(array(" ", " ", " "), " ", $message);
  204. }
  205. /**
  206. * sql语句字符清理
  207. *
  208. * @static
  209. * @access public
  210. * @param string $message
  211. * @param string $dbConfig
  212. */
  213. public static function sqlClear($message, $dbConfig) {
  214. $message = self::clear($message);
  215. if (!(defined('SITE_DEBUG') && SITE_DEBUG)) {
  216. $message = str_replace($dbConfig['database'], '***', $message);
  217. //$message = str_replace($dbConfig['prefix'], '***', $message);
  218. $message = str_replace(C('DB_PREFIX'), '***', $message);
  219. }
  220. $message = htmlspecialchars($message);
  221. return $message;
  222. }
  223. /**
  224. * 显示错误
  225. *
  226. * @static
  227. * @access public
  228. * @param string $type 错误类型 db,system
  229. * @param string $errorMsg
  230. * @param string $phpMsg
  231. */
  232. public static function showError($type, $errorMsg, $phpMsg = '') {
  233. global $_G;
  234. $errorMsg = str_replace(SITE_PATH, '', $errorMsg);
  235. ob_end_clean();
  236. $host = $_SERVER['HTTP_HOST'];
  237. $title = $type == 'db' ? 'Database' : 'System';
  238. echo <<<EOT
  239. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  240. <html>
  241. <head>
  242. <title>$host - $title Error</title>
  243. <meta http-equiv="Content-Type" content="text/html; charset={$_G['config']['output']['charset']}" />
  244. <meta name="ROBOTS" content="NOINDEX,NOFOLLOW,NOARCHIVE" />
  245. <style type="text/css">
  246. <!--
  247. body { background-color: white; color: black; font: 9pt/11pt verdana, arial, sans-serif;}
  248. #container {margin: 10px;}
  249. #message {width: 1024px; color: black;}
  250. .red {color: red;}
  251. a:link {font: 9pt/11pt verdana, arial, sans-serif; color: red;}
  252. a:visited {font: 9pt/11pt verdana, arial, sans-serif; color: #4e4e4e;}
  253. h1 {color: #FF0000; font: 18pt "Verdana"; margin-bottom: 0.5em;}
  254. .bg1 {background-color: #FFFFCC;}
  255. .bg2 {background-color: #EEEEEE;}
  256. .table {background: #AAAAAA; font: 11pt Menlo,Consolas,"Lucida Console"}
  257. .info {
  258. background: none repeat scroll 0 0 #F3F3F3;
  259. border: 0px solid #aaaaaa;
  260. border-radius: 10px 10px 10px 10px;
  261. color: #000000;
  262. font-size: 11pt;
  263. line-height: 160%;
  264. margin-bottom: 1em;
  265. padding: 1em;
  266. }
  267. .help {
  268. background: #F3F3F3;
  269. border-radius: 10px 10px 10px 10px;
  270. font: 12px verdana, arial, sans-serif;
  271. text-align: center;
  272. line-height: 160%;
  273. padding: 1em;
  274. }
  275. .sql {
  276. background: none repeat scroll 0 0 #FFFFCC;
  277. border: 1px solid #aaaaaa;
  278. color: #000000;
  279. font: arial, sans-serif;
  280. font-size: 9pt;
  281. line-height: 160%;
  282. margin-top: 1em;
  283. padding: 4px;
  284. }
  285. -->
  286. </style>
  287. </head>
  288. <body>
  289. <div >
  290. <h1>$title Error</h1>
  291. <div class='info'>$errorMsg</div>
  292. EOT;
  293. if (!emptyempty($phpMsg)) {
  294. echo '<div class="info">';
  295. echo '<p><strong>PHP Debug</strong></p>';
  296. echo '<table cellpadding="5" cellspacing="1" width="100%" class="table"><tbody>';
  297. if (is_array($phpMsg)) {
  298. echo '<tr class="bg2"><td>No.</td><td>File</td><td>Line</td><td>Code</td></tr>';
  299. foreach ($phpMsg as $k => $msg) {
  300. $k++;
  301. echo '<tr class="bg1">';
  302. echo '<td>' . $k . '</td>';
  303. echo '<td>' . $msg['file'] . '</td>';
  304. echo '<td>' . $msg['line'] . '</td>';
  305. echo '<td>' . $msg['function'] . '</td>';
  306. echo '</tr>';
  307. }
  308. } else {
  309. echo '<tr><td><ul>' . $phpMsg . '</ul></td></tr>';
  310. }
  311. echo '</tbody></table></div>';
  312. }
  313. echo <<<EOT
  314. </div>
  315. </body>
  316. </html>
  317. EOT;
  318. exit();
  319. }
  320. }
  321. /**
  322. * DB异常类
  323. *
  324. * @author www.phpfensi.com
  325. */
  326. class DbException extends Exception {
  327. protected $sql;
  328. protected $dbConfig; // 当前数据库配置信息
  329. public function __construct($message, $code = 0, $sql = '', $dbConfig = array()) {
  330. $this->sql = $sql;
  331. $this->dbConfig = $dbConfig;
  332. parent::__construct($message, $code);
  333. }//开源代码phpfensi.com
  334. public function getSql() {
  335. return $this->sql;
  336. }
  337. public function getDbConfig() {
  338. return $this->dbConfig;
  339. }
  340. }
  341. ?>