#!/usr/local/bin/perl
#
#############################################################
###
### CGIカウンター SDcount ログ表示 Ver.1.00
### (SDcountシリーズ対応)
###
### (C) 2001 Sentora Dori
### http://lowpower.iis.u-tokyo.ac.jp/~hat
###
#############################################################
#
#################### 変数設定 ####################
# ログファイルのあるディレクトリのパス
$basedir = ".";
# 管理用のパスワード(何も書かないとパスワードなしでログを見れる)
$validpass = 'wanitanma';
# 棒グラフの最大の幅(値が全体の100%のときの幅)
$graphwidth = 500;
# 棒グラフの高さ
$graphheight = 15;
# 1:ホスト別、ドメイン別のログをアクセス回数順に並び替えて表示する 0:並びかえない
$usesort = 1;
# 1:ホスト別、ドメイン別のログを並びかえるためのボタンを表示する 0:表示しない
$showsort = 0;
# post: postメソッド get: getメソッド
$method = 'post';
# 2: flockを使用する 1: ロックファイルでロックする 0: ロックしない (通常は変更必要なし)
$uselock = 2;
#################### 変数設定(ここまで) ####################
# 各ログデータの区切り記号 (変更必要なし)
$delimiter ="---nextlog---\n";
# flockを使用しないロックのときのロックファイル名のベース (変更必要なし)
$baselockfile = './SDlock';
# このファイル名
$thisurl = 'SDcountlog.cgi';
# タイトル
$title = 'SDcountログ表示';
@logtitle = ("アクセス順ログ", "日にち別ログ", "ホスト別ログ", "ドメイン別ログ");
### data format ###
&init_form();
$countname = $form{'countname'};
$logtype = $form{'logtype'};
$pass = $form{'pass'};
$command = $form{'command'};
$logfile = "$basedir/$countname.log";
if ($logtype eq 'total') {
$showlog = 4;
$lognumber = 0;
} elsif ($logtype eq 'simple') {
$showlog = 1;
$lognumber = 0;
} elsif ($logtype eq 'day') {
$showlog = 1;
$lognumber = 1;
} elsif ($logtype eq 'host') {
$showlog = 1;
$lognumber = 2;
} elsif ($logtype eq 'domain') {
$showlog = 1;
$lognumber = 3;
} else {
$showlog = 0;
}
##### branch #####
if ($command eq 'sort') {
&do_sort;
}
if ($validpass ne '') {
if ($command ne '') {
if ($validpass eq $pass) {
&show_log;
} else {
&print_error('[password mismatch]');
}
} else {
&do_showpass;
}
} else {
&show_log;
}
exit(0);
#----- パスワード入力画面表示 -----
sub do_showpass {
print "Content-type: text/plain\n\n";
print <<"END_SHOWPASS";
$title
$title - パスワード入力
END_SHOWPASS
}
#----- ログ表示 -----
sub show_log {
local($i, $j);
local(@logaddr, @logname, @logtime, @logvalue, @domain);
local(@bakip, @bakname, @bakvalue);
local(@bak, @line, @cutname);
if ($showlog) {
if (!open(LOGF, "$logfile")) {
&print_error('[log file not found]');
}
}
@logf = ;
$txtlist = join('', @logf);
@loglist = split(/$delimiter/, $txtlist);
# ヘッダ表示
print "Content-type: text/plain\n\n";
print <<"END_SHOWLOG_1";
$title
$title
カウンタ名: $countname
END_SHOWLOG_1
$print_sort = <<"END_SHOWSORT";
END_SHOWSORT
# 日にち別ログの総アクセス数取得
$totalvalue1 = 1;
@eachlog = split(/\n/, $loglist[1]);
for ($i = 0; $i < @eachlog; $i++) {
($logday, $logvalue) = split(/,/, $eachlog[$i]);
$totalvalue1 += $logvalue;
}
# ホスト別ログの総アクセス数取得
$totalvalue2 = 1;
@eachlog = split(/\n/, $loglist[2]);
for ($i = 0; $i < @eachlog; $i++) {
($logaddr, $logname, $logvalue) = split(/,/, $eachlog[$i]);
$totalvalue2 += $logvalue;
}
# ログ表示ループ
for ($i = 0; $i < $showlog; $i++) {
if (($logtype eq 'total' && $i == 0) || $logtype eq 'simple') {
@eachlog = split(/\n/, $loglist[0]);
} elsif (($logtype eq 'total' && $i == 1) || $logtype eq 'day') {
@eachlog = split(/\n/, $loglist[1]);
} elsif (($logtype eq 'total' && $i == 2) || $logtype eq 'host') {
@eachlog = split(/\n/, $loglist[2]);
@eachlog = &sort_log(@eachlog) if ($usesort);
} elsif (($logtype eq 'total' && $i == 3) || $logtype eq 'domain') {
@eachlog = split(/\n/, $loglist[2]);
for ($k = 0; $k < @eachlog; $k++) {
($logaddr[$k], $logname[$k], $logvalue[$k]) = split(/,/, $eachlog[$k]);
@cutname = split(/\./, $logname[$k]);
$bak[2] = pop(@cutname);
$bak[1] = pop(@cutname);
$bak[0] = pop(@cutname);
$logname = join('.', @bak);
$findaddr = 0;
for ($l = 0; $l < @bakname; $l++) {
if ($logname eq $bakname[$l]) {
$bakvalue[$l] += $logvalue[$k];
$findaddr = 1;
last;
}
}
if (!$findaddr) {
push (@bakname, $logname);
push (@bakvalue, $logvalue[$k]);
}
}
for ($k = 0; $k < @bakname; $k++) {
@line = ($bakaddr[$k], $bakname[$k], $bakvalue[$k]);
@domain[$k] = join(',', @line);
}
@eachlog = @domain;
@eachlog = &sort_log(@eachlog) if ($usesort);
}
# 実際にログ表示
print "$logtitle[$lognumber]
";
if (($logtype eq 'total' && $i == 2) || $logtype eq 'host') {
print $print_sort if ($showsort);
}
print "";
if (($logtype eq 'total' && $i == 0) || $logtype eq 'simple') {
print"| カウンタ値 | アクセス時間 | IPアドレス | ドメイン |
";
} elsif (($logtype eq 'total' && $i == 1) || $logtype eq 'day') {
print"| 日付け | アクセス回数 |
";
} elsif (($logtype eq 'total' && $i == 2) || $logtype eq 'host') {
print"| IPアドレス | ドメイン | アクセス回数 |
";
} elsif (($logtype eq 'total' && $i == 3) || $logtype eq 'domain') {
print"| ドメイン | アクセス回数 |
";
}
for ($j = 0; $j < @eachlog; $j++) {
# アクセス順
if (($logtype eq 'total' && $i == 0) || $logtype eq 'simple') {
($logvalue, $timelog, $logaddr, $logname) = split(/,/, $eachlog[$j]);
print "| $logvalue | $timelog | $logaddr | $logname |
";
}
# 日にち別
elsif (($logtype eq 'total' && $i == 1) || $logtype eq 'day') {
($logday, $logvalue) = split(/,/, $eachlog[$j]);
$width = int(($logvalue/$totalvalue1)*$graphwidth);
print "| $logday | $logvalue | ";
print " |
";
}
# ホスト別
elsif (($logtype eq 'total' && $i == 2) || $logtype eq 'host') {
($logaddr, $logname, $logvalue) = split(/,/, $eachlog[$j]);
$width = int(($logvalue/$totalvalue2)*$graphwidth);
print "| $logaddr | $logname | $logvalue | ";
print " |
";
}
# ドメイン別
elsif (($logtype eq 'total' && $i == 3) || $logtype eq 'domain') {
($logaddr, $logname, $logvalue) = split(/,/, $eachlog[$j]);
$width = int(($logvalue/$totalvalue2)*$graphwidth);
print "| $logname | $logvalue | ";
print " |
";
}
}
print "
";
$lognumber++;
}
print "";
}
#----- ログファイル中のホスト別ログのソート -----
sub do_sort {
if (!open(LOGF, "+<$logfile")) {
&print_error('[log file not found]');
}
if (!&lock_file(LOGF)) {
&print_error('[log file lock error]');
}
@logf = ;
$txtlist = join('', @logf);
@loglist = split(/$delimiter/, $txtlist);
@eachlog = split(/\n/, $loglist[2]);
@eachlog = &sort_log(@eachlog);
$loglist[2] = join("\n", @eachlog)."\n";
$txtlist = join("$delimiter", @loglist);
seek(LOGF, 0, 0);
print LOGF $txtlist;
&unlock_file(LOGF);
close(LOG);
}
#----- ホスト別、ドメイン別のログのソート -----
sub sort_log {
local(@list) = @_;
local($k, $l);
local(@addr, @name, @value, @line);
local($bakip, $bakname, $bakvalue);
for ($k = 0; $k < @list; $k++) {
($ip[$k], $name[$k], $value[$k]) = split(/,/, $list[$k]);
}
for ($k = 0; $k < @list - 1; $k++) {
for ($l = $k + 1; $l < @list; $l++) {
if ($value[$k] < $value[$l]) {
$bakip = $ip[$k]; $bakname = $name[$k]; $bakvalue = $value[$k];
$ip[$k] = $ip[$l]; $name[$k] = $name[$l]; $value[$k] = $value[$l];
$ip[$l] = $bakip; $name[$l] = $bakname; $value[$l] = $bakvalue;
}
}
}
for ($k = 0; $k < @list; $k++) {
@line = ($ip[$k], $name[$k], $value[$k]);
$list[$k] = join(',', @line);
}
return @list;
}
#----- ブラウザへの入力データの取得 -----
sub init_form {
local($query, @dataarray, $method, $property, $value);
$method = $ENV{'REQUEST_METHOD'};
$method =~ tr/A-Z/a-z/;
if ($method eq 'post') {
read(STDIN, $query, $ENV{'CONTENT_LENGTH'});
} else {
$query = $ENV{'QUERY_STRING'};
}
@dataarray = split(/&/, $query);
foreach $data (@dataarray) {
($property, $value) = split(/=/, $data);
$form{$property} = $value;
}
}
#----- ファイルロック -----
sub lock_file {
local($FILE) = @_;
local($LOCK) = "LOCK$FILE";
local($lockfile) = "$baselockfile$FILE";
local($retry) = 10;
if ($uselock == 2) {
eval(flock($FILE, 2));
if ($@) {
return 0;
} else {
return 1;
}
} elsif ($uselock == 1) {
while (-f $lockfile) {
sleep(0.3);
return 0 if (--$retry <= 0);
}
open($LOCK, ">$lockfile") || return 0;
close($LOCK);
return 1;
} else {
return 1;
}
}
#----- ファイルアンロック -----
sub unlock_file {
local($FILE) = @_;
local($lockfile) = "$baselockfile$FILE";
if ($uselock == 2) {
flock($FILE, 8);
} elsif ($uselock == 1) {
unlink($lockfile);
}
}
##### エラー処理 #####
#----- エラー文を出力し終了 -----
sub print_error {
local($msg) = @_;
print "Content-type: text/plain\n\n";
print $msg;
exit(0);
}