#! /usr/bin/perl # # Webalizer に食わせる combined ログの漢字コードを統一するスクリプト # by HIRAMOTO Kouji (http://flatray.com/) # # カスタマイズ部分: # $webalizer_conf # #IgnoreSite の所の、無視するクライアント # (この例では *.example.com と *.example.net からのアクセスを無視) # #HideReferrer の所の、無視するリファラー # (この例では http://example.com/〜 と http://www.example.com/〜 からの # アクセスを無視) use strict; use Jcode; # # webalizer設定ファイルのフルパスを指定。 # my $webalizer_conf = "/etc/webalizer.conf"; my %Engine = (); my @EngineName = (); my $tr_from = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz "; my $tr_to = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+"; # # SearchEngineディレクティブの読み込み。 # open(IN, "<", $webalizer_conf) or die "Cannot open for read: $webalizer_conf"; while () { next unless (/^SearchEngine/i); split(/\s+/); $Engine{$_[1]} = $_[2]; } close(IN) or die "Cannot close: $webalizer_conf"; # #よく利用されるサーチエンジンから先にマッチングを行うよう細工する。 #(効果は薄いが一応速くはなる) # my %engine_checked = (); my $key; #まずGoogle foreach $key (keys %Engine) { next if ($engine_checked{$key}); if ($key =~ /google/) { $engine_checked{$key} = 1; push(@EngineName, $key); } } #次にYahoo! foreach $key (keys %Engine) { next if ($engine_checked{$key}); if ($key =~ /yahoo/) { $engine_checked{$key} = 1; push(@EngineName, $key); } } #本当なら次はmsnだが、今のところ襲来数少ないのでやめとく #次に国内エンジン foreach $key (keys %Engine) { next if ($engine_checked{$key}); if ($key =~ /\.jp$/) { $engine_checked{$key} = 1; push(@EngineName, $key); } } #最後に残ったやつ(webalizer.confに標準で入ってるやつとか) foreach $key (keys %Engine) { next if ($engine_checked{$key}); push(@EngineName, $key); } while (<>) { # #webalizerのIgnoreURLで何故かindex.rdfを除外できないので、ここで取り除く。 #webalizerで対応できない特定のUser-Agentもここで。 # (短かいエージェント名の完全一致とか、MSソフトのOPTIONでのアクセスとか) # if (#index.rdf m| \"GET /index.rdf HTTP/| #短いエージェント名 or m| \"ozi"$| #OPTIONリクエストを吐いてくる or m|Microsoft Data Access Internet Publishing Provider Protocol| ) { next; } # #IgnoreSiteやHideReferrerで指定しているものはスキップ。(これが一番効く) # if (#IgnoreSite m|^\S\.example\.com | or m|^\S\.example\.net | #HideReferrer or m| "http://example\.com/| or m| "http://www\.example\.com/| ) { print $_; next; } my($pre, $ref, $post) = /^(.*".*" \d+ \S+ ")(.*)(" ".*")$/; # #仮に上の正規表現マッチに失敗してたら、そのまま出力しておく。 # unless ($pre and $ref and $post) { print $_; next; } # #リファラーがない場合はそのまま出力。(これが二番目に効く) # if ($ref eq "-") { print $_; next; } my $code = ""; #Googleの引数ie=を抽出。 if ($ref =~ /&ie=([^&]+)&?/i) { my $c = lc($1); if ($c eq "shift_jis" or $c eq "sjis") { $code = "sjis"; } elsif ($c eq "euc-jp") { $code = "euc"; } elsif ($c eq "iso-2022-jp") { $code = "jis"; } elsif ($c eq "utf-8") { $code = "utf8"; } } #自動判別に失敗すると分かっている文字列についてケア。 if (!$code and ($ref =~ /%E5%9B%BA%E5%AE%9A/i # "固定" or $ref =~ /%E7%84%A1%E7%B7%9A/i # "無線" or $ref =~ /%E5%A4%89%E6%9B%B4/i # "変更" ) ) { $code = "utf8"; } #utf-8って書いてあるならそうする if (!$code and $ref =~ /utf-?8/i) { $code = "utf8"; } #デコードして $ref =~ s/(%|\\x)([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($2))/eg; #漢字コード変換 if ($code) { #$codeが設定されていたらそうする $ref = Jcode->new($ref, $code)->tr($tr_from, $tr_to)->euc; } else { #分からない場合はJcode.pmに任せる $ref = Jcode->new($ref)->tr($tr_from, $tr_to)->euc; } # #サーチエンジンとマッチングさせて、キーワードの英字を小文字に統一 #(これやりたくない場合は、$ref はとにかく lc() で処理して # webalizer.confのSearchEngineの引数も小文字にするという手もある) # # foreach my $engine (keys %Engine) { foreach my $engine (@EngineName) { if ($ref =~ m|(http://[^/]*$engine/.*[\?&]$Engine{$engine})([^&]*)(.*)$|) { my $x = $1; my $y = $2; my $z = $3; #キーワードのアルファベットを小文字に統一し、キーワードをソート。 $y = join "+", sort split /\+/, lc($y); $ref = "$x$y$z"; last; } } #最後に出力 $ref =~ s/\"/%22/g; print "$pre$ref$post\n"; }