一个显示效果非常不错的PHP错误、异常处理类
一、效果图:
二、实现代码
//自定义异常函数
set_exception_handler("handle_exception");
//自定义错误函数
set_error_handler("handle_error");
/**
*异常处理
*
*@parammixed$exception异常对象
*@authorblog.snsgou.com
*/
functionhandle_exception($exception){
Error::exceptionError($exception);
}
/**
*错误处理
*
*@paramstring$errNo错误代码
*@paramstring$errStr错误信息
*@paramstring$errFile出错文件
*@paramstring$errLine出错行
*@authorblog.snsgou.com
*/
functionhandle_error($errNo,$errStr,$errFile,$errLine){
if($errNo){
Error::systemError($errStr,false,true,false);
}
}
/**
*系统错误处理
*
*@authorblog.snsgou.com
*/
classError{
publicstaticfunctionsystemError($message,$show=true,$save=true,$halt=true){
list($showTrace,$logTrace)=self::debugBacktrace();
if($save){
$messageSave="<b>".$message."</b><br/><b>PHP:</b>".$logTrace;
self::writeErrorLog($messageSave);
}
if($show){
self::showError("system","<li>$message</li>",$showTrace,0);
}
if($halt){
exit();
}else{
return$message;
}
}
/**
*代码执行过程回溯信息
*
*@static
*@accesspublic
*/
publicstaticfunctiondebugBacktrace(){
$skipFunc[]="Error->debugBacktrace";
$show=$log="";
$debugBacktrace=debug_backtrace();
ksort($debugBacktrace);
foreach($debugBacktraceas$k=>$error){
if(!isset($error["file"])){
//利用反射API来获取方法/函数所在的文件和行数
try{
if(isset($error["class"])){
$reflection=newReflectionMethod($error["class"],$error["function"]);
}else{
$reflection=newReflectionFunction($error["function"]);
}
$error["file"]=$reflection->getFileName();
$error["line"]=$reflection->getStartLine();
}catch(Exception$e){
continue;
}
}
$file=str_replace(SITE_PATH,"",$error["file"]);
$func=isset($error["class"])?$error["class"]:"";
$func.=isset($error["type"])?$error["type"]:"";
$func.=isset($error["function"])?$error["function"]:"";
if(in_array($func,$skipFunc)){
break;
}
$error["line"]=sprintf("%04d",$error["line"]);
$show.="<li>[Line:".$error["line"]."]".$file."(".$func.")</li>";
$log.=!empty($log)?"->":"";
$log.=$file.":".$error["line"];
}
returnarray($show,$log);
}
/**
*异常处理
*
*@static
*@accesspublic
*@parammixed$exception
*/
publicstaticfunctionexceptionError($exception){
if($exceptioninstanceofDbException){
$type="db";
}else{
$type="system";
}
if($type=="db"){
$errorMsg="(".$exception->getCode().")";
$errorMsg.=self::sqlClear($exception->getMessage(),$exception->getDbConfig());
if($exception->getSql()){
$errorMsg.="<divclass="sql">";
$errorMsg.=self::sqlClear($exception->getSql(),$exception->getDbConfig());
$errorMsg.="</div>";
}
}else{
$errorMsg=$exception->getMessage();
}
$trace=$exception->getTrace();
krsort($trace);
$trace[]=array("file"=>$exception->getFile(),"line"=>$exception->getLine(),"function"=>"break");
$phpMsg=array();
foreach($traceas$error){
if(!empty($error["function"])){
$fun="";
if(!empty($error["class"])){
$fun.=$error["class"].$error["type"];
}
$fun.=$error["function"]."(";
if(!empty($error["args"])){
$mark="";
foreach($error["args"]as$arg){
$fun.=$mark;
if(is_array($arg)){
$fun.="Array";
}elseif(is_bool($arg)){
$fun.=$arg?"true":"false";
}elseif(is_int($arg)){
$fun.=(defined("SITE_DEBUG")&&SITE_DEBUG)?$arg:"%d";
}elseif(is_float($arg)){
$fun.=(defined("SITE_DEBUG")&&SITE_DEBUG)?$arg:"%f";
}else{
$fun.=(defined("SITE_DEBUG")&&SITE_DEBUG)?"\"".htmlspecialchars(substr(self::clear($arg),0,10)).(strlen($arg)>10?"...":"")."\"":"%s";
}
$mark=",";
}
}
$fun.=")";
$error["function"]=$fun;
}
if(!isset($error["line"])){
continue;
}
$phpMsg[]=array("file"=>str_replace(array(SITE_PATH,"\\"),array("","/"),$error["file"]),"line"=>$error["line"],"function"=>$error["function"]);
}
self::showError($type,$errorMsg,$phpMsg);
exit();
}
/**
*记录错误日志
*
*@static
*@accesspublic
*@paramstring$message
*/
publicstaticfunctionwriteErrorLog($message){
returnfalse;//暂时不写入
$message=self::clear($message);
$time=time();
$file=LOG_PATH."/".date("Y.m.d")."_errorlog.php";
$hash=md5($message);
$userId=0;
$ip=get_client_ip();
$user="<b>User:</b>userId=".intval($userId).";IP=".$ip.";RIP:".$_SERVER["REMOTE_ADDR"];
$uri="Request:".htmlspecialchars(self::clear($_SERVER["REQUEST_URI"]));
$message="<?phpexit;?>\t{$time}\t$message\t$hash\t$user$uri\n";
//判断该$message是否在时间间隔$maxtime内已记录过,有,则不用再记录了
if(is_file($file)){
$fp=@fopen($file,"rb");
$lastlen=50000; //读取最后的$lastlen长度字节内容
$maxtime=60*10; //时间间隔:10分钟
$offset=filesize($file)-$lastlen;
if($offset>0){
fseek($fp,$offset);
}
if($data=fread($fp,$lastlen)){
$array=explode("\n",$data);
if(is_array($array))
foreach($arrayas$key=>$val){
$row=explode("\t",$val);
if($row[0]!="<?phpexit;?>"){
continue;
}
if($row[3]==$hash&&($row[1]>$time-$maxtime)){
return;
}
}
}
}
error_log($message,3,$file);
}
/**
*清除文本部分字符
*
*@paramstring$message
*/
publicstaticfunctionclear($message){
returnstr_replace(array("\t","\r","\n"),"",$message);
}
/**
*sql语句字符清理
*
*@static
*@accesspublic
*@paramstring$message
*@paramstring$dbConfig
*/
publicstaticfunctionsqlClear($message,$dbConfig){
$message=self::clear($message);
if(!(defined("SITE_DEBUG")&&SITE_DEBUG)){
$message=str_replace($dbConfig["database"],"***",$message);
//$message=str_replace($dbConfig["prefix"],"***",$message);
$message=str_replace(C("DB_PREFIX"),"***",$message);
}
$message=htmlspecialchars($message);
return$message;
}
/**
*显示错误
*
*@static
*@accesspublic
*@paramstring$type错误类型db,system
*@paramstring$errorMsg
*@paramstring$phpMsg
*/
publicstaticfunctionshowError($type,$errorMsg,$phpMsg=""){
global$_G;
$errorMsg=str_replace(SITE_PATH,"",$errorMsg);
ob_end_clean();
$host=$_SERVER["HTTP_HOST"];
$title=$type=="db"?"Database":"System";
echo<<<EOT
<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>$host-$titleError</title>
<metahttp-equiv="Content-Type"content="text/html;charset={$_G["config"]["output"]["charset"]}"/>
<metaname="ROBOTS"content="NOINDEX,NOFOLLOW,NOARCHIVE"/>
<styletype="text/css">
<!--
body{background-color:white;color:black;font:9pt/11ptverdana,arial,sans-serif;}
#container{margin:10px;}
#message{width:1024px;color:black;}
.red{color:red;}
a:link{font:9pt/11ptverdana,arial,sans-serif;color:red;}
a:visited{font:9pt/11ptverdana,arial,sans-serif;color:#4e4e4e;}
h1{color:#FF0000;font:18pt"Verdana";margin-bottom:0.5em;}
.bg1{background-color:#FFFFCC;}
.bg2{background-color:#EEEEEE;}
.table{background:#AAAAAA;font:11ptMenlo,Consolas,"LucidaConsole"}
.info{
background:nonerepeatscroll00#F3F3F3;
border:0pxsolid#aaaaaa;
border-radius:10px10px10px10px;
color:#000000;
font-size:11pt;
line-height:160%;
margin-bottom:1em;
padding:1em;
}
.help{
background:#F3F3F3;
border-radius:10px10px10px10px;
font:12pxverdana,arial,sans-serif;
text-align:center;
line-height:160%;
padding:1em;
}
.sql{
background:nonerepeatscroll00#FFFFCC;
border:1pxsolid#aaaaaa;
color:#000000;
font:arial,sans-serif;
font-size:9pt;
line-height:160%;
margin-top:1em;
padding:4px;
}
-->
</style>
</head>
<body>
<divid="container">
<h1>$titleError</h1>
<divclass="info">$errorMsg</div>
EOT;
if(!empty($phpMsg)){
echo"<divclass="info">";
echo"<p><strong>PHPDebug</strong></p>";
echo"<tablecellpadding="5"cellspacing="1"width="100%"class="table"><tbody>";
if(is_array($phpMsg)){
echo"<trclass="bg2"><td>No.</td><td>File</td><td>Line</td><td>Code</td></tr>";
foreach($phpMsgas$k=>$msg){
$k++;
echo"<trclass="bg1">";
echo"<td>".$k."</td>";
echo"<td>".$msg["file"]."</td>";
echo"<td>".$msg["line"]."</td>";
echo"<td>".$msg["function"]."</td>";
echo"</tr>";
}
}else{
echo"<tr><td><ul>".$phpMsg."</ul></td></tr>";
}
echo"</tbody></table></div>";
}
echo<<<EOT
</div>
</body>
</html>
EOT;
exit();
}
}
/**
*DB异常类
*
*@authorblog.snsgou.com
*/
classDbExceptionextendsException{
protected$sql;
protected$dbConfig; //当前数据库配置信息
publicfunction__construct($message,$code=0,$sql="",$dbConfig=array()){
$this->sql=$sql;
$this->dbConfig=$dbConfig;
parent::__construct($message,$code);
}
publicfunctiongetSql(){
return$this->sql;
}
publicfunctiongetDbConfig(){
return$this->dbConfig;
}
}
相关文章
- 2022-08-31:以下go语言代码输出什么?A:江苏;B:v[“province“]取值错误;C:m.Store存储错误;D:不知道。 package ma
- php拼接循环拼接字符串数组,PHP数组拼接
- 【错误记录】Flutter 构建报错 ( Because xxx requires SDK version >=2.12.0-0 <3.0.0, versio | Dart SDK 版本低 )
- 【错误记录】IntelliJ IDEA 编译 Groovy 报错 ( GroovyRuntimeException: This script or class could not be run. )
- SQLServer 错误 21898 发布服务器“%s”使用的是分发数据库“%s”,而不是“%s”(后者是承载发布数据库“%s”所需的)。 请在分发服务器“%s”上运行 sp_changedistpublisher,以将发布服务器使用的分发数据库更改为“%s”。 故障 处理 修复 支持远程
- 深入PHP:实现MySQL数据库更新(php更新mysql)
- PHP自定义错误和异常详解编程语言
- PHP中如何连接MySQL数据库?(php怎么连接mysql数据库)
- 关于服务器PHP错误日志详解
- 解决PHP读取MSSQL数据库乱码问题(php读mssql乱码)
- PHP连接MSSQL数据库发生错误解决方法(php mssql 错误)
- 使用PHP操作MSSQL -命令行之路(php mssql 命令)
- PHP如何连接MySQL数据库?(php如何连接mysql数据库)
- PHP实现华丽丽的图片上传 MySQL储存精妙记录(php上传图片mysql)
- Redis面试题与PHP配合(redis面试题 php)
- 中的应用使用Redis,提升PHP程序效率(redis缓存在php)
- 创建数据库php代码用PHP写出自己的BLOG系统
- PHP程序员最常犯的11个MySQL错误小结
- PHP的异常处理、错误的抛出及回调函数等面向对象的错误处理方法
- PHPPDOStatement:bindParam插入数据错误问题分析
- win8下IIS8.5下设置404错误页