掲示板にアクセスする際に、前回入力した自分のログイン名が自動的に入力されている、そんなことを実現するのが クッキー(Cookie)です。ページを表示する際にサーバーからこっそり Cookie 情報と呼ばれるデータが送信されてクライアント側のディスクに保存され、次回そのページを表示する際に、ブラウザが Cookie 情報を送り返します。
Cookie データはサーバーからクライアントに返される HTTP レスポンスのヘッダに含まれます。形式は以下の通りです。
Set-Cookie: LOGIN=tanaka; expires=Thu, 1-Jan-2030 00:00:00 GMT;
LOGIN=tanaka の部分は AGE=26 でも PASSWORD=hi.mi.tu でも、好きな変数名と値を指定することができます。expires にはブラウザが Cookie情報を覚えておく期限を指定します。タイムゾーンは必ず GMT(世界標準時)で指定してください。expires を省略すると、ブラウザが終了するまで覚えておきます。
ブラウザは、サーバーから受け取った Cookie 情報をメモリやディスクに保存しておきます。Windows XP + Internet Explorer の場合は、下記のフォルダに保存されるようです。expires 指定が無い場合は、メモリにだけ保存します。
C:\Document and Setting\ログイン名\Cookies
ブラウザは、次回、同じページ、あるいは、同じフォルダにある別ページにアクセスする際に、覚えておいた Cookie 情報を HTTP リクエストのヘッダに含めて送信します。
Cookie: LOGIN=tanaka
これをサーバーが受け取ることにより、その日初めてアクセスしたページであっても、前回のログイン名を表示することができるようになります。
クライアント側に Cookie 情報を送り込むには、下記のような CGI を作成します。記号や日本語などのデータは URLエンコード形式 などにエンコードしておきます。$setcookie は、HTTP のヘッダ部(Content-type: の前後、最初の空行よりも前)に記述してください。
#!/usr/local/bin/perl # Cookie 情報書き込み用のヘッダを生成する $setcookie = SetCookie("LOGIN", "tanaka", "p"); # Cookie情報書き込み用ヘッダを作成する # SetCookie(名前, 値, モード) # モード:p=パーマネント=永続的設定 # t=テンポラリ=ブラウザを終了するまで有効 sub SetCookie { local($name, $value, $mode) = @_; local($tmp); $value =~ s/(\W)/sprintf("%%%02X", unpack("C", $1))/eg; $tmp = "Set-Cookie: $name=$value;"; if ($mode eq "p") { return "$tmp; expires=Thu, 1-Jan-2030 00:00:00 GMT;"; } else { return "$tmp"; } } # ページを書き出す print <<END_OF_DATA; Content-type: text/html $setcookie <html> <head><title>Cookie情報の設定</title></head> <body> <div>Cookie情報を設定しました。</div> <div>setcookie = [ $setcookie ]</div> </body> </html> END_OF_DATA
クライアント側に書き込んだ Cookie 情報を読み込むには、CGI に次のような機能を埋め込みます。
#!/usr/local/bin/perl # Cookie情報を読み出す GetCookie(*COOKIE); # Cookieデータを解釈する sub GetCookie { local(*COOKIE) = @_; local($name, $value); foreach (split(/; */, $ENV{'HTTP_COOKIE'})) { ($name, $value) = split(/=/); $value =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("C", hex($1))/eg; $COOKIE{$name} = $value; } } # ページを書き出す print <<END_OF_DATA; Content-type: text/html <html> <head> <meta http-equiv="Content-type" content="text/html; charset=Shift_JIS"> <title>Cookie情報の読み出し</title> </head> <body> <hr> <div>Cookie情報を読み出しました。</div> <div>LOGIN = [ $COOKIE{'LOGIN'} ]</div> <hr> </body> </html> END_OF_DATA
読み込んだ Cookie 情報は $COOKIE{変数名} という連想配列に格納されます。
クライアント側に書き込んだ Cookie 情報を削除するには、expires に過去の時刻を指定した Set-Cookie ヘッダを送ります。
#!/usr/local/bin/perl # Cookie情報を削除するヘッダ $delcookie = DelCookie("LOGIN"); # Cookieデータを削除する sub DelCookie { local($name) = @_; return "Set-Cookie: $name=; expires=Thu, 1-Jan-1970 00:00:00 GMT;"; } # ページを書き出す print <<END_OF_DATA; Content-type: text/html $delcookie <html> <head> <title>Cookie情報の削除</title> </head> <body> <hr> <div>Cookie情報を削除しました。</div> <hr> </body> </html> END_OF_DATA
一度に複数の Cookie 情報を書き込むには、下記のように複数の Cookie ヘッダを設定してください。
$setcookie1 = SetCookie("LOGIN", "tanaka"); $setcookie2 = SetCookie("AGE", "26"); print <<END_OF_DATA; Content-type: text/html $setcookie1 $setcookie2 <html> :
読み込み側はこれらの値を $COOKIE{'LOGIN'} と $COOKIE{'AGE'} で参照することができます。
1週間だけ有効な Cookie 情報を設定するには、Set-Cookie ヘッダの expires に 1週間後の日時を指定します。"Thu, 1-Jan-2030 00:00:00 GMT" の代わりに、以下のサブルーチンで得られる日時を指定してください。
$expires = getExpiresTime(7); sub getExpiresTime { local($days) = @_; local(@mon) = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ); local(@wday) = ( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ); local($time, $sec, $min, $hour, $mday, $mon, $year, $wday); $time = time() + ($days * 24 * 60 * 60); ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($time); return sprintf("%s, %d-%s-%d %02d:%02d:%02d GMT", $wday[$wday], $mday, $mon[$mon], $year + 1900, $hour, $min, $sec); }