カウンターを作る

■ 簡単なカウンター

◆ 用意するファイル

簡単なカウンターを実現するスクリプトを紹介します。サーバーに下記のファイルを用意してください。

ファイル説明
count.cgiカウンタースクリプト本体。
count.txtカウンター値を保存するファイル。
gifcat.plGIF画像連結ライブラリ。
0.gif~9.gif0~9 それぞれの画像ファイル。
◆ カウンター値データファイル - count.txt

count.txt は、カウンターの初期値を記述したテキストファイルです。CGI 実行ユーザが書き込みできるように、Windows + IIS であれば IUSER_マシン名 への書き込み権を与え、UNIX であればファイルのパーミッションを 666(rw-rw-rw)または 644(rw-r--r--)にしてください。例えば、カウンター値を 12345 から始めたい場合は以下のような内容にしてください。

12345
◆ GIF画像連結ライブラリ - gifcat.pl

gifcat.pl は GIF画像連結用のライブラリです。下記の場所からダウンロードしたものを解凍して利用してください。FTP でサーバーに転送する場合は、テキストモードで転送してください。

◆ 画像ファイル - 0.gif~9.gif

0.gif ~ 9.gif は画像ファイルです。大きさが統一された GIF ファイルであれば、どんなものでも構いません。例えば以下の場所などからダウンロードしてください。

◆ スクリプトファイル - count.cgi

スクリプトの内容を以下に示します。機能を抑えているので、とてもシンプルです。

#!/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()によるファイルのロック

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);
◆ 関連情報

■ IPアドレスからアクセス元のホスト名を求める

◆ REMOTE_HOST の中身

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
◆ IPアドレスからホスト名への変換

REMOTE_ADDR に設定されたアクセス元の IPアドレスからホスト名を逆引きするには下記のようにします。これを、print で REMOTE_HOST をログファイルに書き込むより前に実行させてください。(→ IPアドレスの変換(ホスト名形式←→ドット形式)

use Socket;

# IPアドレスからホスト名を求める
$addr = pack("C4", split(/\./, $ENV{'REMOTE_ADDR'});
$ENV{'REMOTE_HOST'} = gethostbyaddr($addr, PF_INET);

Copyright (C) 2002 杜甫々