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('<img src=https://yourserver.com/path_to_the_xlog.cgi/xlog.cgi?uri=' + document.URL + '&id=' + xlog_id + '&ref=' + document.referrer + ' width=1 height=1>');
}
アクセスログを残したい(トラッキングしたい)ウェブページ(の最後)に書く JavaScript(</body> タグの直前あたりに書くのがいいだろう。)
<SCRIPT Language="JavaScript">
<!--
document.write("<img src=\"https://yourserver.com/path_to/xlog.cgi?uri=");
document.write(document.URL);
document.write('&r=255');    // 背景が白 (R=255、G=255、B=255 の場合
document.write('&g=255');
document.write('&b=255');
document.write('&ref=');
document.write(document.referrer);
document.write("\" width=1 height=1>");

// -->
</SCRIPT>
トラックバック URL: https://perltips.twinkle.cc/trackback/130
from PERL2javascript on 2007/12/20(木) 16:54
ワンピクセルの画像にアンカータグを付け、そこから環境変数の情報を取得するという方法らしい。 シリコンバレー在住のPerl Tipsさんのページより引用。 使用モジュールはSTRICT,CGIのほ...