Perl/CGI研究室 'PERL-LABO'

Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

アクセスカウンター

研究内容

CGIプログラムの定番、アクセスカウンターを作りましょう。

詳細

今回作るアクセスカウンター

簡単なアクセスカウンターはここまでの知識で作ることができます。 もっとも簡単なアクセスカウンターは、CGIプログラムが呼び出されるごとに カウンターの値を1つ増やすというものです。 以前、リンクのクリック回数をカウントする研究をしましたが、 その仕組みがアクセスカウンターになります。

実際に使用されているアクセスカウンターは、 IPアドレスやクッキーを使った同じ人のアクセスを重複してカウントしない仕組みが付いていたり、 昨日、今日、トータルを表示したり、 日、週、月で時系列に過去のアクセス数を見ることができたりします。 単にCGIプログラムが呼び出された回数をカウントするタイプのものは アクセスカウンターとは言えないようなシンプルなものですが、 最初ですからそこから始めましょう。

結果

処理の流れ

「ファイルをロックする」→ 「ファイルを開く」→ 「ファイルを読む」→ 「ファイルを閉じる」→ 「カウントを増やす」→ 「ファイルを開く」→ 「ファイルに書き込む」→ 「ファイルを閉じる」→ 「ファイルのロックを解除する」→ 「カウンターの値を出力する」ですね。

カウンターの値を画面に表示するには

カウンターの値を画面に表示するには普通、画像を使いますよね。 あらかじめ用意しておいた 0〜9 の数字の画像ファイルを並べて表示するというものが多いです。 でもそれ、やり方がまだ分からないし、テキストで画面に表示するようにしましょう。 テキストで表示するために、CGIプログラムはHTMLのIFRAMEタグで呼び出すことにします。

作成したCGIプログラム

counter.cgi
#!/usr/bin/perl

require 'lock.pl';

print "Content-type: text/html\n\n";
print "<body style=\"margin:0;font-size:15px;\"><tt>";

$lockdir   = "lockdir";
$countfile = "count.cgi";

# ファイルをロックする
if (! plab::lock($lockdir)) {
	error();
}

# ファイルを開く
open(FILE, "< $countfile");

# カウントを読み込む
$count = <FILE>;

# ファイル閉じる
close FILE;

# カウントを増やす
++$count;

# ファイルを開く
if (! open(FILE, "> $countfile")) {
	plab::unlock($lockdir);
	error();
}

# カウントを書き込む
print FILE $count;

# ファイル閉じる
close FILE;

# ロックを解除する
plab::unlock($lockdir);

# カウントを出力する
$txt = sprintf("%05d", $count);
print $txt;
exit;

sub error
{
	print "?????";
	exit;
}

実行結果

カウンターです。このページが表示された回数です。

次のようなIFRAMEタグで表示しています。

<iframe src=counter.cgi width=45 height=20 frameborder=0></iframe>

解説

動きました

ほぼ、最初に考えた処理の流れの通りに作りました。 思ったとおりに動くと嬉しいですね! それに、アクセスカウンターを作れるようになったことが嬉しい (^^ この記事を読んでくださっている訪問者様、ここまでの記事を全部読めば、 貴方もアクセスカウンターを作れるようになりますよ!

プログラムの解説です

さてプログラムについて少々解説をしておきます。

最初の例の Content-type〜 のところですが、今までは print 文を2行書いて改行を2回しているっていうのを強調していたんですが、 \n\n と2回連続で改行するようにして、print 文1行にまとめています。 改行してないじゃん?!と思われた方はごめんなさい。分かりにくいので説明しておきました。

その次、bodyタグとttタグを出力しています。 これは、IFRAMEでカウンターを表示させる関係上、 余分なマージンを消したいのと、フォントサイズを固定にしないと IFRAMEのサイズが定まらないのと、数字を固定幅にしたい(ttタグの働きです)のとで このようにしました。

次はロックですが、ロック処理は失敗することがあるので 必ずエラー処理が必要です。ここでは、エラーが起きたら ????? という文字を出力することにしました。 それに、後で同じようにエラーが発生する箇所があったので、エラー発生時の ????? の 出力を別関数にしました。同じ処理が複数のところで必要になる場合は、 こうやって関数にしてまとめておくといいです。

カウントを読むところですが、$count = <FILE> というのは ファイルから1行読み込むという意味になります。これは以前も while 文の中で でてきた 行入力演算子 < > の働きですね。 このファイルには数字が1行書き込まれているだけなので、while 文などを使って ファイルの終わりまで読まなくてもいいわけです。 あと、初めてこのCGIプログラムを実行したときには、 カウントを保存しているファイルって存在していませんよね。 その辺の処理を省略しちゃってますが、ファイルが存在していないと open 関数は失敗して、ファイルハンドル FILE も無効だし、$count にはなにも入りません。 でもこの状態で、次の ++$count で $count が 1 になるので、結果的にこれでOKでした。

ファイルの書き込みオープンのところでは、 エラー発生がもしかしたらあるかなと思ってエラーの検出をしています。 エラーが発生したらエラー用関数を呼び出しますが、ここで注意! ファイルのロックをしたら、かならずロックの解除をしなくちゃいけません。 ロックの解除をせずにプログラムを終了してしまうと、 同時に起動した他のプロセスがロックのところで固まってしまいます。 一定時間経てば強制的にロックが解除されるので、永久に固まってしまう わけではないですが、とにかくロックしたら必ず解除することを忘れないようにしましょう。 ということで、エラー関数はプログラムを終了させてしまうので、エラー関数を呼び出す前に ロックを解除しています。 エラー関数の中でロック解除するのがロック解除のし忘れを防ぐという意味では 一番いいのですが、最初のロックに失敗したところでもエラー関数を呼んでいるので、 エラー関数の中でロック解除すると他のプロセスのロックを解除してしまうことになり かねません。ですので、ここではエラー関数を呼び出す前にロック解除するようにしました。

あとは、最後のところで、sprintf 関数で数字を5桁で表示するようにしています。 %05d というやつですね。

さらに改良を

こうして、初めてのアクセスカウンターは無事動きました。 これを元にして、もっと高機能なアクセスカウンターに進みましょう!

分かったこと

  1. bodyタグでマージンを 0 にすると画面ピッタリにテキストを表示できます。
  2. ttタグで等幅フォントにできます。
  3. < > は 行入力演算子 というんだそうです。
  4. ロックしたら必ずロック解除しましょう。
Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

Copyright (c) 'PERL-LABO' All Rights Reserved.  リンクフリーです。