Perl/CGI研究室 'PERL-LABO'

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

日毎アクセスを記録するカウンタの研究

研究内容

その日のアクセス、トータルアクセスを記録するようにアクセスカウンターを改良します。 さらに日々のアクセス数をあとで参照できるように別ファイルに記録していくようにします。

結果

必要なデータ

今まではトータルのアクセス数だけをカウントしていましたから、 データはトータルのアクセス数、それに重複カウントを除くための IPアドレスの2つでした。 これに加えて、日々のアクセス数を記録していくにはどのようなデータが必要でしょうか?

まず、日毎のアクセスを記録するわけですから、 トータルアクセスに加えて、その日1日のアクセス数を保存しておく必要がありますね。

もう1つ。 1日の終わりに、その日のアクセスを別のファイルに保存するようにして 過去の日毎のアクセスを残しておきたいです。 ここが、今回の研究のキモですね。 1日に1回だけ、なにか特別な処理をするっていう感じのことを実現しないといけません。 で、その日最後のアクセスというのはどうやったら知ることができるでしょうか? これ、できそうもありません。 そのかわり、1日の最初のアクセスっていうのは知ることができそうです。 どうやってやるかというと、 前回アクセスのあった日付を記録しておいて、 前回のアクセスの日付と、現在の日付を比べて変わっていたら、 次の日になったということで、処理を行うっていうやり方です。 このやり方でトライしてみます。

あと、せっかくですから、「昨日のアクセス数」を保存しておくことにしましょう。 昨日のアクセス数は、別ファイルに保存されている日毎のアクセスを読めば分かりますが、 昨日のアクセス数を知るために別ファイルを読みに行くのも面倒な話ですから。

まとめると、処理するデータとしては「トータルアクセス数」「その日のアクセス数」 「昨日のアクセス数」「前回のアクセス日付」「重複チェック用IPアドレス」の5つとなります。 処理するデータが決まったところで、CGIプログラムの作成にかかりました。

作成したCGIプログラム

counter.cgi
#!/usr/bin/perl

require 'lock.pl';
require 'cookie.pl';

# クッキーで重複チェック。重複なら 1 になります。
$visit = checkvisitbycookie();

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

# ファイル名など
$ip        = $ENV{'REMOTE_ADDR'};
$lockdir   = "lockdir";
$countfile = "count.cgi";
$dayfile   = "count_day.cgi";

# ロック
if (! plab::lock($lockdir)) {
	error();
}

# 読み込み
open FILE, "< $countfile";
$line = <FILE>;
close FILE;

($totalcount, $todaycount, $yestcount, $prevday, $previp) = split('<>', $line);

# 前回と今回でIPアドレスが異なっていて、かつ、
# クッキーに前回訪問の記録が残っていなかったらカウントします
if ($previp ne $ip && ! $visit)
{
	$day = gettoday();
	if ($prevday ne "" && $prevday ne $day) {
		# 日付が変わりました
		# 昨日のアクセス数を別ファイルに移し日付カウントをリセットします
		open DAYFILE, ">> $dayfile";
		print DAYFILE "$prevday<>$todaycount\n";
		close DAYFILE;
		$yestcount  = $todaycount;
		$todaycount = 0;
	}

	++$totalcount;
	++$todaycount;
	
	if (! open(FILE, "> $countfile")) {
		plab::unlock($lockdir);
		error();
	}

	print FILE "$totalcount<>$todaycount<>$yestcount<>$day<>$ip";
	close FILE;
}

plab::unlock($lockdir);

# カウンタ表示
$txt = sprintf(
	"<small>今日</small> %03d <small>昨日</small> %03d <small>計</small> %04d",
	$todaycount, $yestcount, $totalcount);
print $txt;
exit;

# クッキーによる重複チェック処理
sub checkvisitbycookie
{
	local $visit;
	%cookie = plab::getcookie();
	if ($cookie{'VISIT'} == 1) { $visit = 1; }
	else                       { $visit = 0; }
	$cookie{'VISIT'} = 1;
	plab::setcookie(12, %cookie);	# 有効期限は12時間
	return $visit;
}

# 現在の日付を文字列で作る
sub gettoday
{
	local @t, $day;
	@t = localtime(time());
	$day = sprintf("%04d/%02d/%02d", $t[5]+1900, $t[4]+1, $t[3]);
	return $day;
}

# エラー
sub error
{
	print "?????";
	exit;
}

実行結果

カウンターです。昨日、今日、計のアクセス数を表示しています。

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

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

解説

プログラムの補足

前回のCGIプログラムから変更したところを説明します。

クッキーによる重複チェックを別関数にしました。これはなんとなくです。 プログラムがみにくかったので…

データファイルですが、以前は1行に1個のデータというようにデータを保存していましたが、 そうするとデータを読み込んだときに末尾に改行コードが残ってしまい、 文字列データを処理する場合にその改行コードが邪魔になるので、 そのやり方はやめました。 1行に <> で区切って保存するやり方に変更しています。 改行が邪魔にならないように、データファイルには改行は出力していません。

現在の日付を取得するには、localtime(time()) というものを使います。 これは、クッキーの有効期限のときにでてきた gmtime(time()) と同じデータを返します。 ただし、gmtime がGMT時間を返すのに対して、localtime はそのマシンのローカルな時間を返します。 つまり、世界中で一斉に gmtime を呼び出した場合はどのマシンでも同じものが返りますが、 localtime の場合はマシンの場所(設定)によって返される値が異なるっていうこと…だと思います。 で、この返された値を使って、gettoday 関数は 2004/12/31 という形式の文字列を作って返すようにしました。

日毎のアクセス数は、とにかく別ファイルに日付と一緒に保存しておくことにしました。 日毎アクセスを画面に表示するCGIプログラムは別に作ろうと思います。

日毎のアクセス数は、専用のファイルの末尾に毎日1行ずつ追加していきます。 ファイル末尾にデータを追加する方法は、 open FILE, ">> ファイル名"; です。

画面には、今日、昨日、計の3つのアクセス数を表示するようにしました。

動きました

なんだか賢いカウンターになってきました。 今日、昨日、計の3つのアクセス数を扱うアクセスカウンターって結構ありますよね。 それが自力で作れました。いやー1歩ずつ進んでおります (^^

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

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