CGIとはCommon Gateway Interfaceの略で、ブラウザから要求を受けたWebサーバ側で、色々な情報を受け取ったり、送り返したりする仕組みである。
アクセスカウンタ、掲示板、アクセスログ集計などが代表的なCGIと言える。
このページでは
access.cgiで使用されているCGIについてを解説する。
このCGIは、アクセスした時の時間やIPアドレスなどを表示し、その情報をlog.cgiというファイルに保存するものである。
これをうまく使えば、自分のHPにどのような人がどんな時にどのページを見たかなどがわかり、また自分のサイトにとって好ましくない訪問者(いたずら、誹謗・中傷、荒らしなど)を特定することもできる。
なお、ここで紹介するCGIサンプルはPerlという言語を用いて作成されている。
CGIは様々な言語で作成できるが、その中でも一般的でわかりやすい言語がPerlである。
#!c:/perl/bin/perl
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)
= localtime();
最初の一行はPerlでCGIを記述するときに必ず記述するものである。
サーバー側でCGIを実行するとき、サーバーのどこにPerlがあるかを指示するものであるが、プロバイダによって記述が変わることもあるため、
この記述がわからないときはプロバイダに問い合わせる必要がある。次の行ではPerlで日時を取得する関数「localtime()」を用いて、左から順に
秒、分、時、日、月、年、曜日、経過日数、夏時間調整をそれぞれの変数に格納している。
ここで述べた変数とは、スカラー変数という数値、文字列など単純な変数をいい、これは名前の前に$をつけることで利用できる。
また、普通変数を扱うときは、それぞれの変数に一個ずつ値を格納していくが、
上のように「localtime()」関数で取得した値を一括してそれぞれの変数に格納するにはこのような書式(リスト書式という)を用いる。
なお、ここで取得した値について解説すると、秒は(0〜59)の数字、分も(0〜59)の数字、時は(0〜23)の数字、
日は(1〜31)の数字、月は(0〜11)の数字、年は西暦1900年が基準として、そこから何年たったかを数字で取得し、曜日は(0〜6)の数字で日が0を表し、
経過日数はその年の1月1日からの経過数(1月1日が0)を表し、夏時間調整は(0〜1)でサマータイムの時に1を表す。
$format = "%04d/%02d/%02d %02d:%02d:%02d";
$days =
sprintf($format,$year+1900,$mon+1,$mday,$hour,$min,$sec);
上の行の[%04d]は値を4桁に整形する書式で、[%02d]は値を2桁に整形する書式である。
[%02d]の場合、月が1桁なら0を補間して2桁にすることができる。
これを次の行の「sprintf()」関数で使うことで、上で指定した書式にしたがって文字整形を行うことができる。
「sprintf()」関数は、左端に書式を指定し、その後書式にしたがって必要な数だけ変数をカンマで区切り順に記述していくことで使うことができ、
これにより、年は4桁で、月は2桁、といったように整形して表示することができる。
$hpadrs = $ENV{'REQUEST_URI'};
$refer = $ENV{'HTTP_REFERER'};
$agent = $ENV{'HTTP_USER_AGENT'};
$hostnm = $ENV{'REMOTE_HOST'};
$ipadrs = $ENV{'REMOTE_ADDR'};
この5行でアクセスした時の情報を取得している。これらは全てPerlが持つ環境変数で簡単に取得することができる。
最初の一行目は現在表示しているページを、
2行目ではその人がどのサイトから訪問してきたか、3行目ではアクセスをしたときのOS、ブラウザなどの情報、
4行目ではホスト名、5行目でIPアドレスを取得し、それぞれの変数に格納している。
print << "END_DOC";
Content-type:text/html\n\n
<?xml version="1.0" encoding="shift_jis"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>アクセスログの表\示と保存</title>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis" />
<meta http-equiv="Content-Style-Type" content="text/css" />
</head>
<body>
END_DOC
print << "END_OF_DOC"; という記述は、「この命令の次の行から END_OF_DOC までを print せよ」という意味である。
これはヒアドキュメントといい、表示したい文章をCGIの中に埋め込み、それをそのまま表示することができる。
"END_OF_DOC"という部分の""の中身は自分で文字列を指定でき、その文字列に到達するまで文字列を出力することができる。
次の行で、これから書かれる文章はHTML形式だということをブラウザに解釈させている。これによりブラウザは文章の形式を知ることができる。
これ以降の行は単なるhtmlの文章である。なお、このHPではXHTML準拠を目指しているため、
ここで使用しているhtmlもXHTML準拠を目指して書いている。
print "現在の日時:";
print "$days<br />";
print "表\示ページ:$hpadrs<br />";
print "リンク元:$refer<br />";
print "エージェント:$agent<br />";
print "ホスト名:$hostnm<br />";
print "IPアドレス:$ipadrs";
print << "END_DOC";
</body>
</html>
END_DOC
ここで<body>タグの中身を記述している。2行目ではdaysという変数に格納されている情報を、
3行目ではhpadrsという変数に格納されている情報をそれぞれ表示し、同様にして全ての情報を表示している。
このように記述することで変数に格納されている情報を参照し表示することができる。
最後にヒアドキュメントを用いて<body>と<html>タグを閉じている。
$fname = "log.cgi";
open(FP,">>$fname");
print FP "$days,$hpadrs,$refer,$agent,$hostnm,$ipadrs,\n";
close(FP);
これがプログラムの最後であり、ここで最初に取得した情報をファイルに保存している。
最初の行では、情報を保存するファイル名をfnameという変数に保存している。
次の行以降で、そのファイルを開き変数をカンマ区切りで羅列して、ファイルに追加方式で情報を記録している。文字列中の最後の「\n」は改行を表す。
なお、ファイル名はどんな名前でもいいが、セキュリティの関係で拡張子は「.cgi」にしている。
こうしておくと訪問者がこのファイルを覗こうとした時に自動的にCGIとして実行しようとするが、中身がCGIではないためエラーが発生する。
よって覗こうとしてもエラーが発生して覗けなくなるためファイルを覗かれる心配がなくなる。