管理系統的操作日志如何做成通用的模塊一直是個讓我頭疼的問題,不過看了博客園里的某篇文章后,現在基本解決了。
相關文章鏈接:《系統操作日志設計》
在開始做之前,必須把兩個日志分清楚,那就是普通操作日志和業務操作日志,這兩者有何區別?
在我理解,普通操作日志就是單表的操作記錄,而業務操作日志則就是一系列的普通操作日志的集合。
打個比方,用戶需要購買一樣寶貝,已經到了下單那步,下單就是個業務,這個業務背后就是一系列的業務,如:
生成訂單 → 生成商品快照 → 發送一條站內信 → 刪除購物車里對應寶貝
這樣一個下單操作就包含了4部分,可以把這4部分看成是4張表,分別對這4張表進行對應的操作,就實現了業務。
但今天我要講的不是業務操作日志,因為不同項目的業務不盡相同,所以它無法做成通用模塊,而我要講的,就是普通操作日志。
上面解釋了一大段,下面干貨就要亮相了,先洗把臉清醒下。
……
首先,哪些地方需要記錄操作日志?執行insert、update、delete這3個操作的時候,就需要進行日志,而日志執行的先后順序如下
| insert | 在insert后執行 |
| update | 在update前后都要執行,操作前獲取操作前數據,操作后獲取操作后數據 |
| delete | 在delete前執行 |
順序清楚后,就來看下我寫的一份日志操作類吧,第一版隨便寫寫的,重復代碼有點多,還未來得及優化。
class LOG{
protected $primaryid;
protected $tbid;
protected $tbname;
protected $keys;
protected $values;
/**
* 參數說明
* int $tbid 查詢指定表的id
* string $tbname 數據庫表名
*/
public function insert($tbid, $tbname){
global $db;
//查詢表注釋
$db->query('show table status where name = "'.$tbname.'"');
$tb = $db->fetch();
//插入日志主表
$returnid = $db->insert(0, 2, 'tb_log', array(
'adminid = '.$_SESSION['admin']['id'],
'type = 1',
'tableid = '.$tbid,
'tablename = "'.$tbname.'"',
'comment = "'.$tb['Comment'].'"',
'dt = now()'
));
//查詢字段注釋
$db->query('show full columns from '.$tbname);
$tb = $db->fetchAll();
foreach($tb as $v){
$commentArray[$v['Field']] = $v['Comment'];
}
//查詢所有字段信息,插入日志從表
$rs = $db->select(0, 1, $tbname, '*', 'and tbid = '.$tbid);
$keys = array_keys($rs);
$values = array_values($rs);
for($i = 0; $i < count($keys); $i++){
$db->insert(0, 0, 'tb_log_content', array(
'logid = '.$returnid,
'tbkey = "'.$keys[$i].'"',
'tbvalue = "'.$values[$i].'"',
'comment = "'.$commentArray[$keys[$i]].'"'
));
}
}
public function updateStart($tbid, $tbname){
global $db;
//查詢表注釋
$db->query('show table status where name = "'.$tbname.'"');
$tb = $db->fetch();
//插入日志主表
$returnid = $db->insert(0, 2, 'tb_log', array(
'adminid = '.$_SESSION['admin']['id'],
'type = 2',
'tableid = '.$tbid,
'tablename = "'.$tbname.'"',
'comment = "'.$tb['Comment'].'"',
'dt = now()'
));
//查詢修改前數據信息
$rs = $db->select(0, 1, $tbname, '*', 'and tbid = '.$tbid);
$keys = array_keys($rs);
$values = array_values($rs);
$this->primaryid = $returnid;
$this->tbid = $tbid;
$this->tbname = $tbname;
$this->keys = $keys;
$this->values = $values;
}
public function updateEnd(){
global $db;
//查詢字段注釋
$db->query('show full columns from '.$this->tbname);
$tb = $db->fetchAll();
foreach($tb as $v){
$commentArray[$v['Field']] = $v['Comment'];
}
//查詢修改后數據信息
$rs = $db->select(0, 1, $this->tbname, '*', 'and tbid = '.$this->tbid);
$currentvalues = array_values($rs);
//前后信息進行比較
for($i = 0; $i < count($currentvalues); $i++){
if($this->values[$i] !== $currentvalues[$i]){
$db->insert(0, 0, 'tb_log_content', array(
'logid = '.$this->primaryid,
'tbkey = "'.$this->keys[$i].'"',
'tbvalue = "'.$this->values[$i].'"',
'currenttbvalue = "'.$currentvalues[$i].'"',
'comment = "'.$commentArray[$this->keys[$i]].'"'
));
}
}
}
public function delete($tbid, $tbname){
global $db;
//查詢表注釋
$db->query('show table status where name = "'.$tbname.'"');
$tb = $db->fetch();
//插入日志主表
$returnid = $db->insert(0, 2, 'tb_log', array(
'adminid = '.$_SESSION['admin']['id'],
'type = 3',
'tableid = '.$tbid,
'tablename = "'.$tbname.'"',
'comment = "'.$tb['Comment'].'"',
'dt = now()'
));
//查詢字段注釋
$db->query('show full columns from '.$tbname);
$tb = $db->fetchAll();
foreach($tb as $v){
$commentArray[$v['Field']] = $v['Comment'];
}
//查詢所有字段信息,插入日志從表
$rs = $db->select(0, 1, $tbname, '*', 'and tbid = '.$tbid);
$keys = array_keys($rs);
$values = array_values($rs);
for($i = 0; $i < count($keys); $i++){
$db->insert(0, 0, 'tb_log_content', array(
'logid = '.$returnid,
'tbkey = "'.$keys[$i].'"',
'tbvalue = "'.$values[$i].'"',
'comment = "'.$commentArray[$keys[$i]].'"'
));
}
}
}
使用前,需要引入數據庫操作類,這是我之前寫的一份,可參考《全新的PDO數據庫操作類(僅適用Mysql)》。
引入之后,就可以開始使用了。
select
$log->insert(82, 'tb_member');
update
$log->updateStart(82, 'tb_member'); //中間放更新操作代碼 $log->updateEnd();
delete
$log->delete(82, 'tb_member');
可以看到,一共只需要兩個參數即可,分別是表ID(主鍵)和表名稱。
另外需要強調一點,表注釋和字段注釋一定要完整,因為記錄的信息包含注釋,目的就是為了查閱的時候能清楚哪個字段是干什么用的。
下面就看下成品吧


最后把表結構分享下,一共2張表,一張主表一張從表,主表記錄操作表及操作人等信息,從表記錄操作的表字段信息。
-- ---------------------------- -- Table structure for `tb_log` -- ---------------------------- CREATE TABLE `tb_log` ( `tbid` bigint(20) NOT NULL AUTO_INCREMENT, `adminid` bigint(20) DEFAULT NULL COMMENT '管理員id', `type` tinyint(4) DEFAULT '1' COMMENT '操作類型:1新增2修改3刪除', `tableid` bigint(20) DEFAULT NULL, `tablename` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '表名', `comment` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `dt` datetime DEFAULT NULL, PRIMARY KEY (`tbid`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- ---------------------------- -- Table structure for `tb_log_content` -- ---------------------------- CREATE TABLE `tb_log_content` ( `tbid` bigint(20) NOT NULL AUTO_INCREMENT, `logid` bigint(20) DEFAULT NULL, `tbkey` longtext COLLATE utf8_unicode_ci, `tbvalue` longtext COLLATE utf8_unicode_ci, `currenttbvalue` longtext COLLATE utf8_unicode_ci, `comment` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`tbid`) ) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
