ApacheのRefererログの解析

postanalogとかanalogurldecode.plとか色々試してみたんだけど、いくつか気に入らない点(集計がいまいちとか文字コードの制約とか)があったのと、decodeに失敗したりするのがイヤで、自前でphpで書いてみた。
ただし、urlエンコードすべきところをhtmlのエンティティか何かにエンコードするブラウザだかがあるようで、その部分の対策はまだですけどね。
使い方としては、crontabで午前1時頃に回すのが良いかと思いますけど、適宜カスタマイズしてください。

<?php
    //written by rio@rio.st
    //Apacheのcombinedログに対応しています。
    //CustomLog '|/usr/sbin/rotatelogs /var/log/httpd/access_log.%Y%m%d 86400 540' combined
    //上記設定では毎日0:00(JST)にログを回します。
    //analog5.0.2以上(文字コードに関して)
//昨日の日付を取得
function get_yesterday(){
    return date(DATE_FORMAT, mktime()-86400);
}

    if(!$this = basename($_SERVER["SCRIPT_FILENAME"])){
        $this = $_SERVER["argv"][0];
    }
    $usage = <<<EOF
Usage : $this [-i path_to_decode] [-o path_to_output] [-D t/y] [-d YYYYMMDD] [-C e/s/j/u]
  -D select 't'oday or 'y'esterday log to decode
  -d log suffix ex. 'access_log.YYYYMMDD'
  -C EUC-JP/SJIS/JIS/UTF-8

EOF;    define("DEF_INPUT_FILE", "/var/log/httpd/access_log"); //デフォルトの入力ファイル
    define("DEF_OUTPUT_FILE", "/var/log/httpd/access_log_decoded"); //デフォルトの出力ファイル
    define("DATE_FORMAT", "Ymd"); //日付の書式=apacheの%Y%m%d
    define("FLD_NO", 10); //combinedログでのリファラフィールドの位置 0 originでカウントします。
    //引数のチェック
    switch($_SERVER["argc"]){
    case 1:
    case 3:
    case 5:
    case 7:
    case 9:
    case 11:
        break;
    default:
        exit($usage);
    }
    $option = getopt("i:o:D:d:C:");
    $input = $option["i"];
    $output = $option["o"];
    if($day_switch = $option["D"]){
        if($day_switch != "t" && $day_switch != "y"){
            exit($this." : day switch is 't' or 'y'\n");
        }
    }
    if($date = $option["d"]){
        $year = substr($_SERVER["argv"][3], 0, 4);
        $month = substr($_SERVER["argv"][3], 4, 2);
        $day = substr($_SERVER["argv"][3], 6, 2);
        if(checkdate($month, $day, $year)){
            $date = $year.$month.$day;
        } else {
            exit($this." : illegal time format '".$date."'\n");
        }
    }
    switch($char = $option["C"]){
    case "":
        if($ret = exec("analog -settings | grep 'Language file'", $res)){
            switch(basename($res[0])){
            case "jpe.lng":
                $charset = "EUC-JP";
                break;
            case "jps.lng":
                $char = "SJIS";
                break;
            case "jpj.lng":
                $char = "JIS";
                break;
            case "jpu.lng":
                $char = "UTF-8";
                break;
            default:
                $charset = ini_get("mbstring.http_output");
            }
        } else {
            $charset = ini_get("mbstring.http_output");
        }
        break;
    case "e":
    case "E":
        $charset = "EUC-JP";
        break;
    case "s":
    case "S":
        $charset = "SJIS";
        break;
    case "j":
    case "J":
        $charset = "JIS";
        break;
    case "u":
    case "U":
        $charset = "UTF-8";
        break;
    default:
        exit($this." : selected charset is not supported!\n");
    }
    if($input && $output){ //ファイル名だけで処理 $input -> $output
    } else if($input && $output && $day_switch){ //ファイル名と当日あるいは昨日を処理 $input.YYYYMMDD -> $output.YYYYMMDD
        if($day_switch == "t"){
            $d = ".".date(DATE_FORMAT);
        } else {
            $d = ".".get_yesterday(DATE_FORMAT);
        }
    } else if($input && $output && $date){ //ファイル名と日付のsuffixで処理 $input.$date -> $output.$date
        $d = ".".$date;
    } else if(!$input && !$output && $day_switch){ //defineされたファイルと当日あるいは昨日のみで処理
        $input = DEF_INPUT_FILE;
        $output = DEF_OUTPUT_FILE;
        if($day_switch == "t"){
            $d = ".".date(DATE_FORMAT);
        } else {
            $d = ".".get_yesterday(DATE_FORMAT);
        }
    } else if(!$input && !$output && !$day_switch && !$date){ //defineされたファイルのみで処理、昨日のファイルを処理
        $input = DEF_INPUT_FILE;
        $output = DEF_OUTPUT_FILE;
        $d = ".".get_yesterday(DATE_FORMAT);
    } else {
        exit($usage);
    }

    $input .= $d;
    $output .= $d;

    if(!file_exists($input)){
        exit($this." : file ".$input." can't be found!\n");
    }
    if(!$fp = fopen($output, "w")){
        exit($this." : file ".$output." can't be created!\n");
    }

    if($file = file($input)){
        foreach($file as $line){
            $wk = explode(" ", $line);
            $tmp = urldecode($wk[FLD_NO]);
            if($enc = mb_detect_encoding($tmp){
                $wk[FLD_NO] = strtolower(mb_convert_encoding($tmp, $charset, $enc));
                fwrite($fp, implode(" ", $wk));
            }
        }
    }
    fclose($fp);
    exec("/usr/bin/analog");
?>
タイトルとURLをコピーしました