很少寫 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

就可以順順的跑完,速度也比較好。

打完收工~

 

 

文章標籤

創作者介紹
創作者 fannys23 的頭像
fannys23

小攻城師的戰場筆記

fannys23 發表在 痞客邦 留言(0) 人氣()