簡単なカウンターを実現するスクリプトを紹介します。サーバーに下記のファイルを用意してください。
ファイル | 説明 |
---|---|
count.cgi | カウンタースクリプト本体。 |
count.txt | カウンター値を保存するファイル。 |
gifcat.pl | GIF画像連結ライブラリ。 |
0.gif~9.gif | 0~9 それぞれの画像ファイル。 |
count.txt は、カウンターの初期値を記述したテキストファイルです。CGI 実行ユーザが書き込みできるように、Windows + IIS であれば IUSER_マシン名 への書き込み権を与え、UNIX であればファイルのパーミッションを 666(rw-rw-rw)または 644(rw-r--r--)にしてください。例えば、カウンター値を 12345 から始めたい場合は以下のような内容にしてください。
12345
gifcat.pl は GIF画像連結用のライブラリです。下記の場所からダウンロードしたものを解凍して利用してください。FTP でサーバーに転送する場合は、テキストモードで転送してください。
0.gif ~ 9.gif は画像ファイルです。大きさが統一された GIF ファイルであれば、どんなものでも構いません。例えば以下の場所などからダウンロードしてください。
スクリプトの内容を以下に示します。機能を抑えているので、とてもシンプルです。
#!/usr/bin/perl # GIF画像連結ライブラリを読みこむ require "gifcat.pl"; # カウンターファイルを読み込み、加算して書きこむ open(FILE, "+< count.txt"); # 読み書きモードでオープン seek(FILE, 0, 0); # ポインタを先頭に移動 $count = <FILE>; # カウンタ値を読み出す $count++; # ひとつ加算する seek(FILE, 0, 0); # ポインタを先頭に戻す print FILE "$count\n"; # 加算した値を書き戻す close(FILE); # ファイルを閉じる # 5桁の0埋め数値に変換 $count = sprintf("%05d", $count); # GIF画像のリストを得る for ($i = 0; $i < length($count); $i++) { $n = substr($count, $i, 1); # $i桁目の値$nを取り出し、 push(@files, "$n.gif"); # $n.gif のファイル名を配列に追加 } # GIF画像を書き出す print "Content-type: image/gif\n"; # イメージを書き出す print "\n"; binmode(STDOUT); # 出力はバイナリモードで print gifcat'gifcat(@files); # GIF画像を連結して書き出す
同時に複数の人がアクセスをすると、カウンターファイル count.txt の内容が破壊されてしまうことがあります。せっかくアクセス数が増えてきたのに、カウンターファイルが壊れて 0 に戻ってしまうなんてこともあります。これを極力防ぐには、ファイルのロックを行います。
flock() が使えるシステムでは、open() の次の行に flock() を追加してください。ファイルがクローズされると自動的にアンロックされるので、flock(FILE, LOCK_UN) は不要です。
use Fcntl ':flock'; # モジュールを読み込む # カウンターファイルを読み込み、加算して書きこむ open(FILE, "+< count.txt"); # 読み書きモードでオープン flock(FILE, LOCK_SH); # ファイルをロック : : close(FILE);
flock() を使えないシステムでは、lock という名前のフォルダをパーミッション 777 で作成しておき、open()~close() の前に LockFile() と UnlockFile() によるロック処理を加えてください。
# カウンターファイルを読み込み、加算して書きこむ LockFile("lock/count.loc") || ErrorExit("ロック失敗"); open(FILE, "+< count.txt"); # 読み書きモードでオープン : : close(FILE); UnlockFile();
アクセスログを記録するには、count.cgi の最後に下記のような処理を追加してください。アクセス数、日付、アクセス元アドレスなどの情報が count.log ファイルに蓄積されます。count.log は count.cgi と同じフォルダにあらかじめ作成しておき、パーミッションを 666(rw-rw-rw)または 644(rw-r--r--)にしておいてください。
# アクセスログを記録する ($sec, $min, $hour, $mday, $mon, $year) = localtime(); $datetime = sprintf("%04d/%02d/%02d %02d:%02d:%02d", $year + 1900, $mon + 1, $mday, $hour, $min, $sec); open(OUT, ">> count.log"); print OUT "COUNT = $count\n"; print OUT "DATE_TIME = $datetime\n"; print OUT "REMOTE_ADDR = $ENV{'REMOTE_ADDR'}\n"; print OUT "REMOTE_HOST = $ENV{'REMOTE_HOST'}\n"; print OUT "HTTP_USER_AGENT = $ENV{'HTTP_USER_AGENT'}\n"; print OUT "HTTP_REFERER = $ENV{'HTTP_REFERER'}\n"; print OUT "\n"; close(OUT);
REMOTE_HOST には通常 xxx.yyy.zzz のような、アクセス元のホスト名が表示されますが、サーバーの負荷を軽減するために、最近は REMOTE_HOST の値が IPアドレスの形式で返されたり、取得じたいできないプロバイダが増えてきました。
REMOTE_ADDR = 10.25.113.78 REMOTE_HOST = 10.25.113.78
しかし、やはり、どんなサイトから見に来てくれたかを知るために、IPアドレスではなく、ホスト名の情報でロギングしたくなるかと思います。
REMOTE_ADDR = 10.25.113.78 REMOTE_HOST = mypc.xxx.yyy.zzz
REMOTE_ADDR に設定されたアクセス元の IPアドレスからホスト名を逆引きするには下記のようにします。これを、print で REMOTE_HOST をログファイルに書き込むより前に実行させてください。(→ IPアドレスの変換(ホスト名形式←→ドット形式))
use Socket; # IPアドレスからホスト名を求める $addr = pack("C4", split(/\./, $ENV{'REMOTE_ADDR'}); $ENV{'REMOTE_HOST'} = gethostbyaddr($addr, PF_INET);