close
很少寫 PHP script,這次要拆解小有份量的 Apache 記錄檔 (log),來練習一下。
用讀檔的模式來一行一行載入 log 檔後,用正規表示式來拆開 LOG,把它塞進資料庫裡,以便可以再運用。
首先,開一個資料表來放 log。
CREATE TABLE if not exists `access_log` (
`sid` bigint(20) unsigned NOT NULL auto_increment COMMENT '流水號',
`remote_host` varchar(300) NOT NULL COMMENT '連進來的IP (clinet IP)',
`logname` varchar(300) NOT NULL COMMENT '使用者是否透過apache的登入機制連線(identd)',
`user` varchar(300) NOT NULL COMMENT '登入時的user name (若前一項有的話)',
`time` varchar(300) NOT NULL COMMENT '連入時間',
`method` varchar(300) NULL comment '連線方法 (GET / POST ...etc.)',
`request` varchar(3000) NULL comment '網址',
`protocol` varchar(300) NULL comment '協訂',
`status` varchar(300) NOT NULL COMMENT 'HTTP status code (200/404/500...etc.)',
`bytes` varchar(300) NOT NULL comment '回傳的頁面大小',
`referer` varchar(300) NULL COMMENT '轉入此頁的前一頁',
`user_agent` varchar(255) null comment 'client browser',
`seclength` int NULL COMMENT '自訂的回應時間記錄 (秒)',
`microlength` int NULL COMMENT '自訂的回應時間記錄 (microsecond)',
`rawdata` varchar(1024) NOT NULL COMMENT '原始log內容(未拆解)',
`filename` varchar(100) not null comment '原始log檔檔名',
primary key (`sid`)
) default charset=utf8 comment='網站log記錄拆解結果';
然後來用 PHP 程式拆 log。我把程式放在 D:\Projects\a.php。
<?php
set_time_limit(0); //因為在 browser 裡會跑到一半就逾時,所以設這個,但感覺不管用XD
ini_set('max_execution_time', 0); //因為在 browser 裡會跑到一半就逾時,所以再設這個,但感覺還是不管用XD
//連線資料庫的 function
function getDbh($dbName=null, $host=null, $account=null, $password=null) {
//成功傳回 $dbh,失敗傳回 false
$dbh = false;
try{
$dsn = "mysql:host=".(empty($host) ? DB_HOST : $host).";dbname=".(empty($dbName) ? MAIN_DB : $dbName);
$dbh = new PDO($dsn,empty($account) ? DB_ACCOUNT : $account,empty($password) ? DB_PASSWORD : $password);
$dbh->exec("SET NAMES 'big5';");
}catch(Exception $ex){
}
return $dbh;
}
// 輸出 HTML 結構 (前半段)
$arr = Array(
"20161030-ssl-access.log",
"20161030-www-access.log"
);
// Apache log Parse Pattern
$pattern = '/^([^ ]+) ([^ ]+) ([^ ]+) \[([^\]]+)\] "(.*) (.*) (.*)" ([0-9\-]+) ([0-9\-]+) "(.*)" "(.*)" \*\*([0-9]*)\/([0-9]*)\*\*$/';
// db connection
$dbh = getDbh("logParse");
foreach ($arr as $filename) {
$rowCount = 0;
$handle = fopen("D:/Projects/convertLog/log/".$filename, "r") or die();
// 讀檔
while (! feof($handle)) {
// 逐行讀出
if ($str = trim(fgets($handle, 16384))) {
if (preg_match($pattern,$str,$matches)) {
list($whole_match,$remote_host,$logname,$user,$time,
$method,$request,$protocol,$status,$bytes,$referer,
$user_agent, $seclength, $microlength) = $matches;
if ($remote_host != "127.0.0.1") {// 我有跳過一些我不想要parse的IP不寫入
$sql = "insert into access_log (remote_host,logname,user,time,method,request,protocol,status,bytes,referer,user_agent, seclength, microlength, rawdata, filename) values (:remote_host,:logname,:user,:time,:method,:request,:protocol,:status,:bytes,:referer,:user_agent, :seclength, :microlength, :whole_match, :filename)";
$sth = $dbh->prepare($sql);
$sth->bindParam(':remote_host', $remote_host, PDO::PARAM_STR);
$sth->bindParam(':logname', $logname, PDO::PARAM_STR);
$sth->bindParam(':user', $user, PDO::PARAM_STR);
$sth->bindParam(':time', $time, PDO::PARAM_STR);
$sth->bindParam(':method', $method, PDO::PARAM_STR);
$sth->bindParam(':request', $request, PDO::PARAM_STR);
$sth->bindParam(':protocol', $protocol, PDO::PARAM_STR);
$sth->bindParam(':status', $status, PDO::PARAM_STR);
$sth->bindParam(':bytes', $bytes, PDO::PARAM_STR);
$sth->bindParam(':referer', $referer, PDO::PARAM_STR);
$sth->bindParam(':user_agent', $user_agent, PDO::PARAM_STR);
$sth->bindParam(':seclength', $seclength, PDO::PARAM_STR);
$sth->bindParam(':microlength', $microlength, PDO::PARAM_STR);
$sth->bindParam(':whole_match', $whole_match, PDO::PARAM_STR);
$sth->bindParam(':filename', $filename, PDO::PARAM_STR);
$sth->execute();
}
}
}
else {
echo "[Error Parsing]".$str;
}
$rowCount++;
echo $rowCount."\n";
}
fclose($handle);
}
// db connection close
$dbh= null;
然後在 DOS 視窗下,切到 PHP 的安裝目錄後,執行這支 PHP:
php -q D:\Projects\a.php
就可以順順的跑完,速度也比較好。
打完收工~
文章標籤
全站熱搜