#!/usr/local/bin/perl # ↑この行をプロバイダの環境にあわせて変更してください。 # #! の前には空行もスペース文字も入れないようにしてください。 #================================================================== # 名称: wwwcount.cgi Ver3.07 # 作者: とほほ # 最新版入手先: http://wakusei.cplaza.ne.jp/twn/wwwcount.htm # 取り扱い: フリーソフト。利用/改造/再配布可能。確認メール不要。 #================================================================== #================================================================== # 使いかた: #================================================================== # (書式1) wwwcount.cgi # CGIが使用できるかテストを行う。 # # (書式2) wwwcount.cgi?text # カウントアップを行い、カウンタをテキストで表示する。 # # (書式3) wwwcount.cgi?gif # カウントアップを行い、カウンタをGIFで表示する。 # # (書式4) wwwcount.cgi?hide+xxx.gif # カウントアップを行い、xxx.gifを表示する。 #================================================================== # 履歴: #================================================================== # 日付 Ver # 1997.03.16 1.00 初版 # 1997.04.10 1.10 シグナル処理の追加 # 1997.04.28 2.00 大幅改造/テスト機能追加/GIF連結機能 # 1997.05.08 2.10 ロックファイルが残ってしまうバグを修正 # 1997.05.11 2.20 %7E や \~ を ~ に変換/自URLは表示しないようにした # 1997.07.06 2.30 10分以上古いロックファイルを消すようにした # 1997.09.14 2.40 メールのサブジェクトに前日のアクセス件数を表示 # 1997.10.19 2.50 自己診断機能の強化 # 1998.02.15 2.60 セキュリティ改善。hide+で.gifしか読み取れないようにした。 # 1998.09.20 2.70 SSIで使用する際に text の引数を不要とした # 1998.11.29 2.80 複数カウンターに対応した # 1998.12.20 2.81 カウンター破壊対処/SIGPIPE対応 # 1999.01.17 2.91 複数カウンターのバグ対応 # 1999.01.17 2.92 日付ファイルが空だとレポートが送れないバグ対応 # 1999.05.30 3.00 nkfを使用しないようにした # 1999.06.06 3.01 ロックファイルのパーミッションを755から0755に修正 # 1999.06.27 3.02 同一アドレスチェック機能の初期値をオフに修正 # 1999.10.03 3.03 誤ってロックファイルを消してしまうことがあるバグを修正 # 1999.10.03 3.04 nameオプションのセキュリティホールに対処 # 1999.10.03 3.05 時刻も記録するよう変更 # 1999.12.12 3.06 nameオプションのセキュリティホール対処が誤っていた # 2000.01.03 3.07 2000年問題対応 #================================================================== # カスタマイズ: #================================================================== # # SSIのテキストモードで使用する場合は、$mode = "text"; としてください。 # $mode = ""; # # 表示桁数を例えば5桁に指定する場合は「$figure = 5;」のように指定する。 # 自動調整するには「$figure = 0;」と指定する。 # $figure = 6; # # ファイルロック機能をオンにする場合は「$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/lib/sendmailが存在することを確認 # しておく。別の場所にある場合は、$sendmail も適切に変更する。詳細メール # の場合は「$account_detail = 1;」とし、アクセス件数のみをメールする場合 # は「$account_detail = 0;」とする。 # $mailto = ''; $sendmail = '/usr/lib/sendmail'; $account_detail = 1; # # このアドレスにマッチするサイトからの FROM は表示しない。 # $my_url = ''; # # カウンター名 # $count_name = "wwwcount"; #================================================================== # 処理部: #================================================================== # # 関連するファイルを洗い出しておく # このCGIスクリプトのファイル名の拡張子を変更したものになる。 # $file_count = "$count_name" . ".cnt"; $file_date = "$count_name" . ".dat"; $file_access = "$count_name" . ".acc"; $file_lock = "lock/$count_name" . ".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 $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 "name") { $count_name = $ARGV[++$i]; if ($count_name !~ /^[a-zA-Z0-9]+$/) { exit(1); } $file_count = "$count_name" . ".cnt"; $file_date = "$count_name" . ".dat"; $file_access = "$count_name" . ".acc"; } elsif ($ARGV[$i] eq "ref") { $reffile = $ARGV[++$i]; } } # # 環境変数TZを日本時間に設定する # $ENV{'TZ'} = "JST-9"; # # ロック権を得る # if ($do_file_lock) { foreach $i ( 1, 2, 3, 4, 5, 6 ) { if (mkdir("$file_lock", 0755)) { # ロック成功。次の処理へ。 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); } } } # # 途中で終了してもロックファイルが残らないようにする # sub sigexit { rmdir($file_lock); exit(0); } $SIG{'PIPE'} = $SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = "sigexit"; # # カウンターファイルからカウンター値を読み出す。 # if (open(IN, "< $file_count")) { $count = ; close(IN); } else { $count = -1; } # # 日付ファイルから最終アクセス日付を読み出す。 # if (open(IN, "< $file_date")) { $date_log = ; close(IN); } else { $date_log = ""; } # # 今日の日付を得る # ($sec, $min, $hour, $mday, $mon, $year) = localtime(time()); $date_now = sprintf("%04d/%02d/%02d", 1900 + $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); $msg = ""; $msg .= "To: $mailto\n"; $msg .= "From: $count_name\n"; $msg .= "Subject: ACCESS $date_log $tmp_count\n"; $msg .= "\n"; if ($account_detail) { open(IN, "< $file_access"); while () { $msg .= $_; } close(IN); } else { $msg .= "Access = $tmp_count\n"; } open(OUT, "| $sendmail $mailto"); print OUT $msg; 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 >= 0) && ($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); # # カウンタをカウンタファイルに書き戻す # if (open(OUT, "> $file_count")) { print(OUT "$count"); close(OUT); } } # # CGIスクリプトの結果としてカウンターを書き出す # if ($count == -1) { $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"); $size = -s $giffile; open(IN, $giffile); binmode(IN); binmode(STDOUT); read(IN, $buf, $size); print $buf; close(IN); } # # ロック権を開放する # if ($do_file_lock) { rmdir($file_lock); }