Perl/CGI研究室 'PERL-LABO'

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

リファラーランキング

研究内容

訪問者様が一体どこからやってきてくださっているのか、気になりますね。 リファラーランキングの研究です。

詳細

リファラーランキングとは

リファラーっていうのは今までに何回か出てきた言葉です。 アクセス元URLのことですね。 CGIプログラムの中の環境変数 HTTP_REFERER でCGIプログラムにリンクしていた ページのURLが分かるんでした。 また、Javaスクリプトを使ってリファラーをCGIプログラムに渡すことで、 CGIプログラムを置いたページのその前に見ていたページのURLを調べることができるんでした。 今回は、Javaスクリプトを使ってリファラーをCGIプログラムに渡して、 リファラー毎にアクセスをカウントして、各リファラーのアクセス数ランキング、 略してリファラーランキングを作りましょう。

結果

仕様を考える

プログラムを作り始めるときは、どんな機能を付けるのか、どんなデータが必要か、 そのデータをどうやって保存するか、といった仕様を決めるんでした。 アクセスカウンターを作ったときは、この最初に決めた仕様があまくて、 後でちょっとした仕様変更が必要になったりして必要以上に苦労しました。 何事も最初が肝心?できるだけ、しっかりした仕様を最初に考えるようにした方がよさそうですね。

で、まずCGIプログラムの内容ですが、考えてみると

1.リファラーをカウントしてランキングにする。
2.ランキングは一定期間経ったらリセットするようにする。ログも残す。
3.ランキングページは ?v=graph を付けて呼び出すと表示されるようにする。
4.検索エンジンなどでは検索ワードによってURLが変わってしまうので、
URLの ? より後ろを削除してから処理する。
5.リファラーを解析するときは特になにも出力する必要がないので、
1x1 の透過gif画像を出力する。
6.自分のサイト内のURLはカウントしない。

…こんな感じかなぁ。あんまり思いつかないですね。 例によって、作っていくと、いろいろ足したいものが出てくるのかも (^^;

さて、これらの機能ですが、メインとなるのは、 上の番号で言うと 1. 2. のカウント処理、それに、 ランキングを表示する 3. の処理です。 他の、4. 5. 6. は、プログラムでいうとたぶん数行程度の処理で、たいしたことはありません。 そして、メインとなる 1. 2. 3. の機能ですが、これは実は、既にページビューカウンターで作った ライブラリがそのまま使えます。 特定の文字列に対してカウントを行う、 一定期間経ったら過去ログに保存して現在のカウントをリセットする、 トータルのカウントも記録する、 グラフを表示する、 といった機能を持つライブラリを作っちゃってあるんです! データの保存とか、その辺の処理は全部このライブラリの中で勝手にやってくれます。 ですから、今回作ろうとしているプログラムは、実際はほとんどやることがありません。 これが、ライブラリの威力です。 他のところでも使えそうなものは、ライブラリにしておく。 これがいかに大事か、よく分かりますよね。 皆さんも、プログラムを作る時には、便利な関数をライブラリにしておきましょう。 お勧めしますよ!

最初から配布を考えて作ります

アクセスカウンター、ページビューカウンターのときは、 手探りでCGIプログラムを作っていきましたので寄り道もしましたが、 今回はその経験を生かして、最初から配布できるレベルのものを作りたいと思います。 具体的には、設定を別ファイルにするとか、 CGIプログラム本体もライブラリ内の1つの関数にしちゃうとか、 そんなことです。

経験というのは大事ですね。 寄り道せずに一直線に完成に向かうことが出来ればプログラムを作るのにかかる時間も ずっと少なくて済みます。今回はそのうえ、大部分は既に作ったライブラリの関数で まかなえるので、比較的簡単にプログラムを作ることができました。 うーん、ゼロから始めたPerl/CGIプログラミングですが、上達してきました!

作成したCGIプログラム

refcounter.cgi
#!/usr/bin/perl

# Plab Ref Counter v1.10

# (c) PERL-LABO
# http://www.perl-labo.org/

require 'setting.cgi';
require 'refcounter.pl';
require 'stdplab.pl';

if (plab::exec_refcounter() == 0) {
	plab::toumeigif();
}

refcounter.pl
$::refcounter_version = "Plab Ref Counter v1.10";

# (c) PERL-LABO
# http://www.perl-labo.org/

require 'getformdata.pl';
require 'counters.pl';
require 'html.pl';
require 'stdplab.pl';

package plab;

# リファラーカウントを行います
# 戻値 1:画面出力を行った 0:出力を行っていない
sub exec_refcounter
{
	%form = plab::getformdata();

	if (exists $form{'ref'})
	{
		# ref= が指定されていたらそれはリファラー。カウントを実行
		$ref = $form{'ref'};

		if ($::rc_myurl eq "") {
			$::rc_myurl = $ENV{'SERVER_NAME'};
		}

		if ($ref eq "") {
			# ブックマーク、URL直接入力など
			# 空だと連想配列上よく無いので名前を変える
			$ref = "NULL";
		}
		elsif ($ref =~ /$::rc_myurl/) {
			# 自サイト内の移動なのでなにもしない
			return 0;
		}
		elsif ($ref =~ /\?/) {
			# ? を含んだURLなので ? 以降を削除する
			$i = index($ref, '?');
			$ref = substr($ref, 0, $i);
		}

		plab::incl_counters($::rc_fname, $ref, $::rc_ipcheck, $::rc_nlog, $::rc_logspan);
		return 0;
	}
	elsif ($form{'v'} eq "graph")
	{
		# グラフ表示
		print "Content-type: text/html\n\n";

		if ($::rc_pswd ne "" && $::rc_pswd ne $form{'pswd'}) { return 1; }

		plab::printhtmlheader($::rc_title);
		print "<table width=100%><tr><td>";
		print "$::rc_title \n";
		if ($::homeurl) { print "<small>[<a href=$::homeurl>トップページ</a>]</small> \n"; }
		print "</td><td align=right>";
		plab::printcopyright($::refcounter_version);
		print "</td></tr></table><br>";

		$logno = $form{'log'};	# 表示するログ番号
		if ($::rc_pswd eq "") { $link = 1; }
		else                  { $link = 0; }
		$mincount = 0; if ($logno eq "t") { $mincount = $::rc_mincount; }
		plab::view_counters($::rc_fname, $::rc_nlog, $logno, $link, $mincount);

		plab::printhtmlfooter();
		return 1;
	}

	return 0;
}

1;

実行結果

当サイトのリファラーランキングになります。次のリンクをクリックしてみてください。 (…お見せするのは非常に恥ずかしいですが他にサンプルがありませんので…。 是非当サイトにリンクを…お願いします…)

PERL-LABO リファラーランキング (2004/12/24〜2006/11/02のデータになります。)

解説

プログラムの解説

このCGIプログラムを呼び出すときは、リファラーを情報として渡してあげないといけません。 それには、Javaスクリプトを使います。 具体的には、次のようなJavaスクリプトをサイト内の各ページに書いておきます。

<script type="text/javascript">
	document.write(
		"<img src=http://www.perl-labo.org/cgi/ref/refcounter.cgi?ref=" + 
		document.referrer + " width=1 height=1>"
	);
</script>

このCGIプログラムには ref=(リファラー) という形でデータを渡すのですが、 リファラーはJavaスクリプトの document.referrer で取得できますので、このようになっています。 このCGIプログラムは常に1x1の透過gifを返しますので、 IMGタグを使っています。

CGIプログラムの中では、 まず、リファラーが自分のサイトのものか、そうでないかを判定する必要があります。 自分のサイト内を移動した場合、リファラーが自分のサイト内のURLになりますが、 それはカウントしても仕方ありませんから。 で、そのやり方ですが、自分のサイト内であることを判定する文字列、 正確には正規表現なのですが、それを設定ファイルで $rc_fname に書いておきます。 ただし、空欄になっている場合は、 自動的に $::rc_myurl = $ENV{'SERVER_NAME'}; を行って、 CGIプログラムのURLのホスト名部分が入ります。 $ENV{'SERVER_NAME'} にはホスト名が入っているんで、それを利用したわけです。 大抵は、これでOKなんじゃないかな? $::変数名 としているのは、 これがパッケージの外の変数だからでしたね。 で、これを使って、文字列マッチ /$::rc_myurl/ によってURLが自サイト内かどうかを判定しています。

あと注意しないといけないのは、リファラーが空の場合があるっていうことです。 リファラーが空になるのは、ブックマークから訪問した場合や、 ブラウザのアドレス欄に直接URLを入力した場合、それから、メールに書かれたURLをクリックしたとき、 あとは、なにかソフトウェアでリファラーが出力されないような設定にしている場合などがあります。 この場合、空の文字列に対してカウントを行うことになりますが、 空だとなにかと都合が悪そうなので、NULL っていう文字列に変えています。 ですから、ランキング表示画面で NULL っていうのがあったら、それはリファラが空だったっていう意味です。

他には、HTMLの出力部分と、既存のライブラリ関数の呼び出しです。 これだけでできちゃいました (^^ ライブラリの作者(=自分)に感謝 (^^;

分かったこと

  1. $ENV{'SERVER_NAME'} にCGIプログラムのURLのホスト名部分が入っています。
Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

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