Chap-4. アクセスカウンターを作ろう

 あちこちにフリーのアクセスカウンターがあるので、これも今更って感じではあります。ただし、フリーの物は広告バナーを強制的に貼らされたり、アクセス回数がお世話になるサイトで管理されていて、もしもそのサイトに何かトラブルがあるとカウンター数が吹っ飛んでしまったり、、、それなりにリスクと制限があります。 自作だと、数は自分で管理できるし、自分のサイトが吹っ飛ばない限り数は安全だし、広告バナーを貼る必要もありません。速度は遅いですが、自作のメリットも、多少はあるのです。ということで、 まあ、、、、練習だと思って自分で作ってみましょうか。ほんのちょいと perl が使えれば簡単です。もちろん perl だけじゃなくて、他のスクリプトでも骨組みは作れますが、肝心の画像表示部分は人様の関数を使わせてもらうので perl を使います。
なお、以下のツールは、、、あくまでカウンターを表示するだけ。機能的に全然、優れたカウンターじゃありません。あしからず。


2014-11-xx
初稿は 2005 年頃です。2005 年頃はカウンターが流行ってました。でも、最近はあまり誰もやってません。
カウンターを使おうとすると以前は CGI を動かして画像を表示するのが普通でした。その後、CGI はセキュリティー上は好ましくないと考えるようになりました。
それに、そもそも私のサイトには検索ロボットくらいしか訪ねて来ません。こんな暇なサイトで、セキュリティー上の危険を冒してまで CGI を動かす意味がありません。一年くらい使っただけで、その後、カウンターはやめています。

2019-11-20
14年ぶりにアクセスカウンターを付けてみました。今は CGI 使わないでテキスト形式表示するのが普通になってきたみたいです。うちもそんな感じでテキスト形式でやってみました。ただし、2001年以来の累計数があるわけじゃないので、初期値はとてもいい加減です。



Sec-1. カウンターって何だ?

--- 以下は 2005年初稿のままです(画像形式で表示するタイプの解説です。テキスト形式のカウンターではありません) ---



カウンターの動作を一言で言えば?

アクセスカウンターは画像表示である。

ご存じのように画像をhtmlで表示するには

<img src="hoge.jpg">

 とします。これで hoge.jpg が画面に表示されます。アクセスカウンターはこれを利用します。つまり、今の記述と同様に

<img src="http://hogehoge/count.pl">

 等としておいて、画像表示の指定箇所に cgi スクリプトを指定します。ここでは便宜上 count.pl としています。一応 perl スクリプトと仮定します。そのスクリプトの中でカウンターの数字を画像に変換したものを表示するわけです。従ってこの count.pl の仕事は

となるわけで、基本的にはそれだけです。ではこれから具体的に作っていきます。


Sec-2. 保存してあるファイルから、カウント値をを読み出す

以下のとおりです。

open HD, "+<", $datafile || die;
flock (HD, 2) || die;
$count = <HD>;
$count++;
seek (HD, 0, 0) || die;
truncate (HD, 0) || die;
print HD $count;
close HD || die;

本当は、もう少し処理が入るのですが、ここでは基本のところだけ見てもらいます。

簡単ですね。



Sec-3. カウント値を画像に変換する

 とりあえず、次の処理に入ります。次にやることは、いま読み出した $count なる数字を画像に変換することです。 画像は0から9まで10個の画像ファイルを用意します。たいていどこかのサイトに画像ファイルがあります。著作権上の問題があるなら、私のように書物を買うと良いでしょう。書物に画像表示プログラムと数字の画像ファイルがついてきました。

$count = sprintf ( "%06d", $count);

for ( $i = 0; $i<length($count); $i++){
  $n = substr($count, $i, 1);
  push( @gif_files, "$imagepath$n.gif");
}

1行目で $count を6桁の数字に変えます。例えばカウンターが 1233 の場合、これを 001233 にするわけです。ようするに、カウンターを表示したときの見栄えです。
次の for ループで6桁分の画像ファイルを @gif_files という配列に保存します。substr は文字列から部分列を取り出す関数です。画像ファイルは /imgpath/$n.gif です。これをとりだして配列に push しています。例えば 0 という数字の画像ファイルなら 0.gif です。
ここでは、6桁なのでこのループを6回まわしています。
これで @gif_files という配列に、カウンター表示に必要な画像が入ったことになります。
次は、この画像を表示するだけです。

print "content-type:image/gif\n\n";
binmode(STDOUT);
print &gifcat::gifcat(@gif_files);

ここの1行目はご存じ、html の記法で、「次は画像だ」ということを知らせます。2行目でモードをチェンジします。画像表示関数 gifcat のソースにはコメントがあって、そこにはこの binmode は Win 用と書かれていますが、私はそのまま UNIX 系でも使っています。3行目でようやく画像がかかれます。
この gifcat という関数は人様が使ったファイルをそのまま、そっくり使いました。難しそうなのです。だからこの部分は自作していません。ようするにN個の画像ファイルを並べて表示する関数です。



Sec-4. 連続アクセスに反応しないようにする

 基本的な骨組みはこれだけです。最後に、このスクリプトに一つ安全装置を組み込みます。既にファイルをロックする安全装置は組み込んでいます。後、それ以外にほしい機能は、「立て続けに同じ人がアクセスしても、カウンターが上がらないようにする。」というものです。要するに「カウンター値へのいたずら」防止ですね。
では、次にこの機能を組み込んでみます。

$time_file = "./data/time-log"; 
$ip_file = "./data/ip-log"; 
$delta = (5 * 60); 
 
$now_t = time; 
open FH, "+<", $time_file || die; 
flock FH, 2 || die; 
$last_t = <FH>; 
seek (FH, 0, 0) || die; 
truncate (FH, 0) || die; 
print FH $now_t; 
close FH || die; 
 
 
$now_ip = $ENV{'REMOTE_ADDR'}; 
open FH, "+<", $ip_file || die; 
flock FH, 2 || die; 
$last_ip = <FH>; 
seek (FH, 0, 0) || die; 
truncate (FH, 0) || die; 
print FH $now_ip; 
close FH || die; 
 
if(($now_t - $last_t) >= $delta){ 
  $inc = 1; 
}elsif($now_ip ne $last_ip){ 
  $inc = 1; 
}else{ 
  $inc = 0; 
} 

前にアクセスのあった時刻を保存するファイルが time-log 、前にアクセスのあったアドレスが ip-log というファイルです。まず time コマンドで今のアクセスタイムを調べます。次に time-log を開き、このファイルから前回のアクセスタイムを読み出します。ここでも作業中はこのファイルをロックしています。いったんそのファイルを空にしてから、今回のアクセスタイムを保存しファイルを閉じています。
2行あけて、次に今回アクセスしてきたアドレスを環境変数から読み出しています。次に前回のアクセス IP を保存している ip-file を開き、このファイルから前回アクセスのIPアドレスを読み出します。ここでもいったんファイルをロックし、次にファイルを空にしてから、今回のアクセスIPアドレスを保存します。
ここまででチェックの準備がすんだので次は、if 文でチェックします。考え方は、

カウンター更新するかどうかを、変数$incが0か1かで表しています。「1ならカウンターを更新する。0なら更新しない。」という具合です。
さて、以上で出来上がりです。ここ counter-perl-srcipt にファイルをおいておきます。ご自由にお使い下さい。使い方は以下のとおりです。

これに興味を覚えたら、もっと高機能な物を自作してください。なお、ゴーグル検索すると高機能なカウンタースクリプトが相当数あります。ま、本当は、作るまでもないのですが・・・・


なおこの中で、画像表示用部分 gifcat.pl は以下の書物にCD-ROMで入っていた物です。ファイルの先頭に著作権表示がありますので、これに従ってください。
書物名:「Perl/CGI」   著者:ハーシー著   出版社:毎日コミュニケーションズ