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");
?>