説明
ホームページのアクセス履歴を取る「アクセスログ」の説明をします。SSI を利用した方法、JavaScript を利用した方法、また <img> タグを使った方法がありますが、ここでは、JavaScript を使った方法を取り上げます。
CGI には、Perlスクリプトを使います。スクリプトでは、訪問者のプラウザの環境変数を取得しますが、それだけでは十分な情報を取得することができません。例えば、使用しているモニターの解像度などはWebページを作成する場合、知りたい情報です。作成するページの幅を決定する場合に、参考とします。
ここで扱うアクセスログでは、多くの環境変数を取得することにしますが、本当に必要な情報は限られていると思います。人によって必要な情報は違うかもしれませんが、私が必要とするのは、「訪問年月日時間」、「リンク元」、「訪問ページ」、「モニター解像度」くらいです。
ページトップへ
JavaScript
まず最初の方で、ブラウザの環境変数からは取得できないものを JavaScript で取得します。
訪問者の、モニターの解像度、表示色数、表示ウィンドウの高さと幅などです。
次に、使用している OS の種類です。これは、CGI の方でも判別できるのですが、ここでやっています。
次に、リンク元を取得します。これは、CGI の方で取得してしまうと、CGIを呼び出した元、即ちこの JavaScript を記述しているページの URL になってしまい知りたいリンク元にはならないので、ここで取得しておきます。
最後の部分で、アクセスログの CGI を呼び出していますが、この JavaScript で取得した情報も引き継ぐようにしています。
var w = screen.width;
var h = screen.height;
var c = screen.colorDepth;
var doc_width = document.body.clientWidth;
var doc_height = document.body.clientHeight;
var os, ua = navigator.userAgent;
if (ua.match(/Win(dows )?NT 6\.1/)) {
os = "Windows 7"; // Windows 7 の処理
}
else if (ua.match(/Win(dows )?NT 6\.0/)) {
os = "Windows Vista"; // Windows Vista の処理
}
else if (ua.match(/Win(dows )?NT 5\.2/)) {
os = "Windows Server 2003"; // Windows Server 2003 の処理
}
else if (ua.match(/Win(dows )?(NT 5\.1|XP)/)) {
os = "Windows XP"; // Windows XP の処理
}
else if (ua.match(/Win(dows)? (9x 4\.90|ME)/)) {
os = "Windows ME"; // Windows ME の処理
}
else if (ua.match(/Win(dows )?(NT 5\.0|2000)/)) {
os = "Windows 2000"; // Windows 2000 の処理
}
else if (ua.match(/Win(dows )?98/)) {
os = "Windows 98"; // Windows 98 の処理
}
else if (ua.match(/Win(dows )?NT( 4\.0)?/)) {
os = "Windows NT"; // Windows NT の処理
}
else if (ua.match(/Win(dows )?95/)) {
os = "Windows 95"; // Windows 95 の処理
}
else if (ua.match(/Mac|PPC/)) {
os = "Mac OS"; // Macintosh の処理
}
else if (ua.match(/Linux/)) {
os = "Linux"; // Linux の処理
}
else if (ua.match(/(Free|Net|Open)BSD/)) {
os = RegExp.$1 + "BSD"; // BSD 系の処理
}
else if (ua.match(/SunOS/)) {
os = "Solaris"; // Solaris の処理
}
else {
os = "N/A"; // 上記以外 OS の処理
}
// Referrer リンク元
tmpref = escape(document.referrer);
ref = "";
for(i = 0; i < tmpref.length; i++) {
ch = tmpref.charAt(i);
if(ch == "*") {tmp = "%2A"; }
else if(ch == "_") { tmp = "%5F"; }
else if(ch == "+") { tmp = "%2B"; }
else if(ch == "-") { tmp = "%2D"; }
else if(ch == ".") { tmp = "%2E"; }
else if(ch == "/") { tmp = "%2F"; }
else if(ch == " ") { tmp = "%20"; }
else { tmp = ch; }
ref += tmp;
}
document.write("<IMG SRC=\"/cgi-bin/log.cgi?ref=" + document.referrer
+ "&os=" + os + "&width=" + w + "&height=" + h
+ "&wwidth=" + doc_width + "&wheight=" + doc_height
+"&color=" + c + "\" align=\"right\">");
ページトップへ
Perlスクリプト
最初の方では、引数として JavaScript で取得した情報を変数に格納しています。その次は、JavaScript で、このCGI をイメージファイルとして呼び出しているので、そのための画像ファイルのファイル名「dummy.gif」を変数として初期値設定しています。
次は、年・月・日や時・分・秒など、システム時間を取得し、更に、数値が一桁のものは、前に「0」を追加して、文字として、全てを2桁表示できるように加工しています。そして、曜日の設定も行います。
そして、いよいよブラウザから環境変数を取得します。まず、IPアドレスを取得します。リモートホストですが、サーバーによっては負荷軽減のために、リモートホスト情報を取得できないように設定している場合があります。そのため、この CGI では、その部分はコメント・アウトしており、IPアドレスをそのまま設定するようにしています。
次の一群は、あえて説明を省略します。そう難しいものではありませんので、各々必要に応じて調べてみてください。そして、その次ですが、必要な情報をログに書きだすために、一つにまとめていますが、データの一つ一つをカンマで区切るようにしています。必要であれば、これをタブなどに変えても良いでしょう。カンマ区切りとして、テキストに書き出すことの利点として、それをダウンロードすれば Excel で読み込み都合の良いように加工することが挙げられます。CGI で色んな抽出方法で表示するようにもできますが、こちらの方が自由度が高いと思われます。
そして、ログファイルは、月毎のものとしているので、ログを書き出すファイル名をシステム時間の年と月より編集しています。
アクセスログを書き出すために、ログファイルをオープンしますが、ここで同時に他の訪問者があれば、競合してしまうため、ロックを掛けてオープンします。そして、ログを書き出します。
最後に、イメージファイルを書き出していますが、これは JavaScript で、この CGI をイメージファイルとして呼び出しているためです。ここで、書き出すイメージファイルですが、訪問者からは見えないようにするために、縦横が1ピクセルの GIF画像を使っています。見えても構わない場合は、普通のサイズの画像でも構わないでしょう。
#!/usr/local/bin/perl
use CGI;
$cgi = CGI::new();
$ref = $cgi->param('ref');
$os = $cgi->param('os');
$w = $cgi->param('width');
$h = $cgi->param('height');
$ww = $cgi->param('wwidth');
$wh = $cgi->param('wheight');
$cl = $cgi->param('color');
$IMGFILE = "dummy.gif";
$LOGPATH = './alog/';
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
gmtime(time +9*60*60);
$month = ($mon + 1);
if ($month < 10) { $month = "0$month"; }
if ($mday < 10) { $mday = "0$mday"; }
if ($sec < 10) { $sec = "0$sec"; }
if ($min < 10) { $min = "0$min"; }
if ($hour < 10) { $hour = "0$hour"; }
$year = ($year + 1900);
$y0="日"; $y1="月"; $y2="火"; $y3="水"; $y4="木"; $y5="金"; $y6="土";
$youbi = ($y0,$y1,$y2,$y3,$y4,$y5,$y6) [$wday];
$num = "$year$month$mday$hour$min$sec";
$date_now = "$year\/$month\/$mday($youbi) $hour\:$min'$sec";
$addr = $ENV{'REMOTE_ADDR'};
# リモートホスト
# $host = $ENV{'REMOTE_HOST'};
$host = gethostbyaddr(pack("C4",split(/\./,$addr)),2) || $addr;
# if ($host eq "") { $host = $ENV{'REMOTE_ADDR'}; }
$nref = $ENV{'HTTP_REFERER'};
$via = $ENV{'HTTP_VIA'};
$xfor = $ENV{'HTTP_X_FORWARDED_FOR'};
$for = $ENV{'HTTP_FORWARDED'};
$agent = $ENV{'HTTP_USER_AGENT'};
$svnm = $ENV{'SERVER_NANE'};
$svsf = $ENV{'SERVER_SOFTWARE'};
if ($xfor ne "") { $xfor_name = gethostbyaddr(pack('C4',split(/\./,$xfor)),2)
|| $xfor; }
$log_value = "$year年,$month月,$mday($youbi),$hour時,$min分,$sec秒,$addr,
$host,$agent,$ref,$nref,$via,$for,$xfor,$xfor_name,$os,$w,
$h,$ww,$wh,$cl,$svnm,$svsf\n";
$logfile = sprintf("./alog%04d%02d.txt", $year, $month);
open(LOG, ">>$logfile")
or die("エラー!ログファイルが開けません");
eval{ flock(LOG, 2) };
seek(LOG, 0, 2);
print LOG $log_value;
close(LOG);
print "Content-type: image/gif\n\n";
open (IMG, "<<$IMGFILE")
or die("エラー!画像ファイルが開けません");
binmode(IMG);
binmode(STDOUT);
print <IMG>
close(IMG);
exit(0);
ページトップへ
ログ
実際のアクセスログを、Excel で表示したものです。IPアドレスとリモートホストは、見えないように加工しています。
下の画像をクリックすると、原寸大の画像が表示されます。
ページトップへ