Perl で、JavaScript と連動してサーバにアクセスログを残す方法

ウェブページへのアクセスログを記録する方法は、いろいろな方法があると思う。もっとも簡単なのは Apache などのウェブサーバが自動的に記録するログをチェックすることで、これには何の手間もいらない。しかし、レンタルサーバなどでログが自由に扱えない場合はどうしたらいいのだろう?

そのひとつが、画像としてリンクされている Perl などの CGI を呼び出す方法だ。利用者に知られずこっそりとアクセスログを取るには 1x1 ピクセルの画像をそのウェブページの背景と共に表示してしまえば、そのウェブページのソースをチェックされない限り、ほとんどの場合は気づかれずにすむだろう。

そんなわけで、以下のように JavaScript と対応する Perl スクリプトで、アクセスログを記録する仕組みを作ってみた。ログの形式は Apache に準拠する(たぶん)。

サーバ側 CGI Perl 設定ファイル (xlog.conf)

# xlog.conf our $LOG_PATH = '/path_to_log_file/temp'; # Specify the path to the location of the log our $FILE_EXT = 'log'; # Specify the file extension # このほかに、/path_to_log_file/lock を mkdir して、 chmod 777 しておく。 use strict; use GD; use CGI; use URI; use POSIX;

サーバ側 CGI Perl ファイル (xlog.cgi)

#!/usr/bin/perl # xlog.cgi # # Access log system # E-mail: support@twinkle.cc # (c) Copyright 2005, 2006, twinkle.cc, All Rights Reserverd. require 'xlog.conf'; my $cgi = new CGI; ##### Initialize # my $r = $cgi->param('r') ? $cgi->param('r') : 0; # my $g = $cgi->param('g') ? $cgi->param('g') : 0; # my $b = $cgi->param('b') ? $cgi->param('b') : 0; my $r = 0; my $g = 0; my $b = 0; $ENV{REMOTE_ADDR} = $ENV{REMOTE_ADDR} ? $ENV{REMOTE_ADDR} : '-'; $ENV{REMOTE_IDENT} = $ENV{REMOTE_IDNET} ? $ENV{REMOTE_IDENT} : '-'; $ENV{REMOTE_USER} = $ENV{REMOTE_USER} ? $ENV{REMOTE_USER} : '-'; my $ref = $cgi->param('ref') ? $cgi->param('ref') : '-'; my $uri = $cgi->param('uri') ? new URI($cgi->param('uri'))->path : '-'; my $host = $cgi->param('uri') ? new URI($cgi->param('uri'))->host : 'unknown'; my $id = $cgi->param('id') ? $cgi->param('id') : 'unknown'; my $date = strftime("%d/%b/%Y:%H:%M:%S %z", localtime(time)); ##### Write a record for a log file_lock; open(LOG, ">>$LOG_PATH/$host.$FILE_EXT") || die; # ex: /path_to_the_file/yourserver.com.log print LOG qq|$ENV{REMOTE_ADDR} $ENV{REMOTE_IDENT} $ENV{REMOTE_USER} [$date] "$ENV{REQUEST_METHOD} $uri $ENV{SERVER_PROTOCOL}" 200 - "$ref" "$ENV{HTTP_USER_AGENT}"\n|; close(LOG); file_unlock; ##### Show an image my $image = new GD::Image(1,1); # Create a new image my $background = $image->colorAllocate($r ,$g, $b); $image->transparent($background); # Transparent the background color # $image->interlaced('true'); # Interlaced binmode STDOUT; # Make sure to write to binary stream print "Content-type: image/png\n\n";# Print Content Header print $image->png; # Output STDOUT by converting the image to PNG ##### Libs sub file_lock { my $wait = 5; while (!symlink(".","$LOG_PATH/lock/.$LOG_EXT")) {
if (--$wait <= 0) {
# &error( '現在他の方が使用中です。', # 'しばらくしてから再度ご利用ください。');
}
sleep (1);
} } sub file_unlock { unlink ("$LOG_PATH/lock/.$LOG_EXT"); } 1;

サーバ側に置く JavaScript (xlog.js)

function tracker() { document.write(''); }

アクセスログを残したい(トラッキングしたい)ウェブページ(の最後)に書く JavaScript
(</body> タグの直前あたりに書くのがいいだろう。)

<SCRIPT Language="JavaScript"> "); // --> </SCRIPT>