#!/usr/local/bin/perl
# ↑この行をプロバイダの環境にあわせて変更してください。
# たとえば BIGLOBE の場合は #!/usr/mesh/bin/perl となります。
# #! の前には空行もスペース文字も入れないようにしてください。
#==================================================================
# 名称: wwwcount.cgi Ver2.7
# 作者: とほほ ( s-hasei@mtg.biglobe.ne.jp )
# 最新版入手先: http://www2e.biglobe.ne.jp/~s-hasei/
# 取り扱い: フリーソフト。利用/改造/再配布可能。確認不要。
#==================================================================
#==================================================================
# 使いかた:
#==================================================================
# (書式1) wwwcount.cgi
# CGIが使用できるかテストを行う。
#
# (書式2) wwwcount.cgi?text
# カウントアップを行い、カウンタをテキストで表示する。
#
# (書式3) wwwcount.cgi?gif
# カウントアップを行い、カウンタをGIFで表示する。
#
# (書式4) wwwcount.cgi?hide+xxx.gif
# カウントアップを行い、xxx.gifを表示する。
#==================================================================
# 履歴:
#==================================================================
# 1997.03.16 Ver1.0
# ・初版
# 1997.04.10 Ver1.1
# ・スクリプトが途中で停止してもロックファイルが残らないように
# シグナル処理を追加した。
# 1997.04.28 Ver2.0
# ・大幅改造
# ・テスト機能を付加した。
# ・GIFファイルを連結して表示するようにした。
# 1997.05.08 Ver2.1
# ・ロックファイルが残ってしまうバグを修正。
# 1997.05.11 Ver2.2
# ・%7E や \~ を ~ と表示するようにした。
# ・自分自身のURLからのFROMは表示しない機能を追加した。
# 1997.07.06 Ver2.3
# ・10分以上古いロックファイルを消すようにした。
# 1997.09.14 Ver2.4
# ・前日アクセスした人が再アクセスするとカウントアップされない
# ことがあるというバグを修正。
# ・メールのサブジェクトに前日のアクセス件数を表示するようにした。
# 1997.10.19 Ver2.5
# ・自己診断機能の強化。
# 1998.02.15 Ver2.6
# ・セキュリティ改善。hide+で.gifしか読み取れないようにした。
# 1998.09.20 Ver2.7
# ・SSIで使用する際に text の引数を不要とした
#==================================================================
# カスタマイズ:
#==================================================================
#
# SSIのテキストモードで使用する場合は、$mode = "text"; としてください。
#
$mode = "";
#
# 表示桁数を例えば5桁に指定する場合は「$figure = 5;」のように指定する。
# 自動調整するには「$figure = 0;」と指定する。
#
$figure = 5;
#
# ファイルロック機能をオンにする場合は「$do_file_lock = 1;」とする。
# ファイルロック機能をオフにする場合は「$do_file_lock = 0;」とする。
#
$do_file_lock = 1;
#
# 同アドレスチェック機能をオンにする場合は「$do_address_check = 1;」とする。
# 同アドレスチェック機能をオフにする場合は「$do_address_check = 0;」とする。
#
$do_address_check = 0;
#
# レポート機能を使う場合は「$mailto = "abc@xxx.yyy.zzz";」のように自分の
# メールアドレスを設定する。また、/usr/local/bin/nkf, /usr/lib/sendmail
# が存在することを確認しておく。別の場所にある場合は、$nkf, $sendmail も
# 適切に変更する。詳細メールの場合は「$account_detail = 1;」とし、アクセ
# ス件数のみをメールする場合は「$account_detail = 0;」とする。
#
$mailto = '';
$nkf = '/usr/local/bin/nkf';
$sendmail = '/usr/lib/sendmail';
$account_detail = 1;
#
# このアドレスにマッチするサイトからの FROM は表示しない。
#
$my_url = '';
#==================================================================
# 処理部:
#==================================================================
#
# 関連するファイルを洗い出しておく
# このCGIスクリプトのファイル名の拡張子を変更したものになる。
#
$file_count = "wwwcount.cnt";
$file_date = "wwwcount.dat";
$file_access = "wwwcount.acc";
$file_lock = "lock/wwwcount.loc";
#
# CGIが使用できるかテストを行う。
#
if ($ARGV[0] eq "test") {
print "Content-type: text/html\n";
print "\n";
print "\n";
print "
Test\n";
print "\n";
print "OK. CGIスクリプトは動作可能です。\n";
print "
\n";
if ($mailto ne "") {
if (! -f $nkf) {
print "
NG. $nkf が存在しません。\n";
}
if (! -f $sendmail) {
print "
NG. $sendmail が存在しません。\n";
}
}
if (-d $file_lock) {
print "
NG. $file_lock が残っています。\n";
}
if (! -r $file_count) {
print "
NG. $file_count が存在しません。\n";
} elsif (! -w $file_count) {
print "
NG. $file_count が書き込み可能ではありません。\n";
}
if (! -r $file_date) {
print "
NG. $file_date が存在しません。\n";
} elsif (! -w $file_date) {
print "
NG. $file_date が書き込み可能ではありません。\n";
}
if (! -r $file_access) {
print "
NG. $file_access が存在しません。\n";
} elsif (! -w $file_access) {
print "
NG. $file_access が書き込み可能ではありません。\n";
}
print "\n";
print "\n";
exit(0);
}
#
# 引数を解釈する
#
for ($i = 0; $i <= $#ARGV; $i++) {
if ($ARGV[$i] eq "text") {
$mode = "text";
} elsif ($ARGV[$i] eq "gif") {
$mode = "gif";
} elsif ($ARGV[$i] eq "hide") {
$mode = "hide";
$giffile = $ARGV[++$i];
if (!($giffile =~ /\.gif$/i)) {
exit(1);
}
if ($giffile =~ /[<>|&]/) {
exit(1);
}
} elsif ($ARGV[$i] eq "ref") {
$reffile = $ARGV[++$i];
}
}
#
# 環境変数TZを日本時間に設定する
#
$ENV{'TZ'} = "JST-9";
#
# 途中で終了してもロックファイルが残らないようにする
#
sub sigexit { rmdir($file_lock); exit(0); }
$SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = "sigexit";
#
# ロック権を得る
#
if ($do_file_lock) {
foreach $i ( 1, 2, 3, 4, 5, 6 ) {
if (mkdir("$file_lock", 755)) {
# ロック成功。次の処理へ。
last;
} elsif ($i == 1) {
# 10分以上古いロックファイルは削除する。
($mtime) = (stat($file_lock))[9];
if ($mtime < time() - 600) {
rmdir($file_lock);
}
} elsif ($i < 6) {
# ロック失敗。1秒待って再トライ。
sleep(1);
} else {
# 何度やってもロック失敗。あきらめる。
exit(1);
}
}
}
#
# カウンターファイルからカウンター値を読み出す。
#
open(IN, "< $file_count");
$count = ;
close(IN);
#
# 日付ファイルから最終アクセス日付を読み出す。
#
open(IN, "< $file_date");
$date_log = ;
close(IN);
#
# 今日の日付を得る
#
($sec, $min, $hour, $mday, $mon, $year) = localtime(time());
$date_now = sprintf("%02d/%02d/%02d", $year, $mon + 1, $mday);
$time_now = sprintf("%02d:%02d:%02d", $hour, $min, $sec);
#
# 日付が異なる、つまり、今日初めてのアクセスであれば
#
if ("$date_log" ne "$date_now") {
#
# アクセスログをメールで送信する
#
if ($mailto ne "") {
$tmp_count = 0;
open(IN, "< $file_access");
while () {
if (/^COUNT/) {
$tmp_count++;
}
}
close(IN);
open(OUT, "| $nkf -j | $sendmail $mailto");
print OUT "To: $mailto\n";
print OUT "From: wwwcount\n";
print OUT "Subject: ACCESS $date_log $tmp_count\n";
print OUT "\n";
if ($account_detail) {
open(IN, "< $file_access");
while () {
print OUT $_;
}
close(IN);
} else {
print OUT "Access = $tmp_count\n";
}
close(OUT);
}
#
# アクセスログを初期化する
#
open(OUT, "> $file_access");
close(OUT);
#
# 今日の日付を日付ログファイルに書き出す
#
open(OUT, "> $file_date");
print(OUT "$date_now");
close(OUT);
}
#
# すでに同アドレスからのアクセスがあればカウントアップしない
#
$count_up = 1;
if ($do_address_check) {
open(IN, "$file_access");
while () {
if ($_ eq "ADDR = [ $ENV{'REMOTE_ADDR'} ]\n") {
$count_up = 0;
last;
}
}
close(IN);
}
#
# カウントアップ処理
#
if ($count_up == 1) {
#
# カウンタをひとつインクリメントする
#
$count++;
#
# %7E や \~ などを処理する
#
$referer = $ENV{'HTTP_REFERER'};
$referer =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg;
$reffile =~ s/\\//g;
#
# アクセスログを記録する
#
open(OUT, ">> $file_access");
print(OUT "COUNT = [ $count ]\n");
print(OUT "TIME = [ $time_now ]\n");
print(OUT "ADDR = [ $ENV{'REMOTE_ADDR'} ]\n");
if ($ENV{'REMOTE_HOST'} ne $ENV{'REMOTE_ADDR'}) {
print(OUT "HOST = [ $ENV{'REMOTE_HOST'} ]\n");
}
print(OUT "AGENT = [ $ENV{'HTTP_USER_AGENT'} ]\n");
print(OUT "REFER = [ $referer ]\n");
if ($reffile && (!$my_url || ($reffile !~ /$my_url/))) {
print(OUT "FROM = [ $reffile ]\n");
}
print(OUT "\n");
close(OUT);
#
# カウンタをカウンタファイルに書き戻す
#
open(OUT, "> $file_count");
print(OUT "$count");
close(OUT);
}
#
# CGIスクリプトの結果としてカウンターを書き出す
#
$count += 0;
if ($figure != 0) {
$cntstr = sprintf(sprintf("%%0%dld", $figure), $count);
} else {
$cntstr = sprintf("%ld", $count);
}
if ($mode eq "text") {
printf("Content-type: text/html\n");
printf("\n");
printf("$cntstr\n");
} elsif ($mode eq "gif") {
printf("Content-type: image/gif\n");
printf("\n");
for ($i = 0; $i < length($cntstr); $i++) {
$n = substr($cntstr, $i, 1);
push(@files, "$n.gif");
}
require "gifcat.pl";
binmode(STDOUT);
print &gifcat'gifcat(@files);
} elsif ($mode eq "hide") {
printf("Content-type: image/gif\n");
printf("\n");
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev,
$size, $atime, $mtime, $ctime, $blksize, $blocks)
= stat($giffile);
open(IN, $giffile);
binmode(IN);
binmode(STDOUT);
read(IN, $buf, $size);
print $buf;
close(IN);
}
#
# ロック権を開放する
#
if ($do_file_lock) {
rmdir($file_lock);
}