Web アプリケーションを作る上では欠かせないCookie。本コーナーでは Cookie の仕組みを詳しく説明し、Perl スクリプトでの実装方法を簡単に解説していきます。
Web アプリケーションを作る上では欠かせないCookie。本コーナーでは Cookie の仕組みを詳しく説明し、Perl スクリプトでの実装方法を簡単に解説していきます。
Cookie とは、サーバとの通信において、特定の情報をクライアント(ブラウザー)に保持させるものです。これにより、次回、同じサイトに訪れたとき、あなただけのカスタマイズされた画面を表示させたり、オンラインショッピングではショッピングカートとしても使われます。
Cookie を使うことによって、多彩な機能を実現することができますので、CGI を作成するにあたっては非常に便利な機能です。
Cookie の仕様は、Netscape Communications Corporation が、 http//home.netscape.com/newsref/std/cookie_spec.html で公開しております。futomi's CGI Cafeでは日本語訳を公開しておりますので、参考になれば幸いです。
さて、いろいろなサイトをブラウザーで見ていると、実は非常に多くの Cookie を仕込まれているものです。Microsoft Internet Explorer や Netscape Communicator のデフォルト設定では、Cookie を受け付けたり、サーバへ送信する際に警告を出さないようになっています。そのため、知らず知らずのうちに、あなたのブラウザーは Cookie をたくさん食べてしまっているのです。
では食べてしまった Cookie は何処にあるのでしょうか。Internet Explorer と Netscape Communicator それぞれについて消化してしまった Cookie までご案内いたしましょう。
| Internet Explorer |
\Documents and Settings\ログオン名\Local Settings\Temporary Internet Files\○○
\Documents and Settings\futomi\Cookies\○○.txt
\WINDOWS\Temporary Internet Files\○○
\WINDOWS\Cookies\○○.txt
| Netscape Communicator |
\Program Files\Netscape\Users\ユーザ名\cookies.txt
# 「ユーザ名」の部分は、プロファイルを使っていない場合「default」となります。
具体的に Cookie を受け付けるとはどういうことかを実験してみましょう。実験の前に、前述した Cookie の保存場所を開いておいてください。
Cookie の実験画面を開くと、クッキー名と値の表が表示されますが、まだ何も表示されていませんね。では Cookie を食べてみましょう。ここでは「クッキーをセットする」ボタンを押してみてください。具体的にどんなクッキーを受け入れたのかが表示されますね。
| Set-Cookie: CookieTest1=%83e%83X%83g%82P; expires=Wed, 03-Apr-2002 09:56:27 GMT; Set-Cookie: CookieTest2=%83e%83X%83g%82Q; expires=Wed, 03-Apr-2002 09:56:27 GMT; |
これはサーバ側からクライアント(ブラウザー)に対して Cookie をセットする際に送るリクエストヘッダーです。これを受けて、ブラウザーはクッキーをセットします。
では、セットされたクッキーを覗いてみましょう。ここではパソコンに保存されたクッキーを見るのではなく、サーバへ送られたクッキー情報を覗いてみます。「クッキーを見る」ボタンを押してみてください。
| クッキー名 | 値 |
|---|---|
| CookieTest1 | テスト1 |
| CookieTest2 | テスト2 |
ではパソコンに保存された Cookie を見てみましょう。先ほど開いておいた Cookie 保存場所を見てください。そのウィンドウをアクティブにした状態で「F5」を押して最新の情報にして下さい。
Internet Explorer の場合、新たにテキストファイルが出来上がりましたね。これが保存された Cookie です。Internet Explorer の場合は、サーバごとに別々のファイルが出来上がります。このファイルの中身はこのような感じになっているはずです。
| CookieTest1 %83e%83X%83g%82P www.futomi.com/cgi-bin/lecture/ 0 1881150208 29414327 1122876704 29414126 * CookieTest2 %83e%83X%83g%82Q www.futomi.com/cgi-bin/lecture/ 0 1881150208 29414327 1122876704 29414126 * |
Netscape Navigator の場合、「Cookie.txt」にすべての Cookie が保存されます。ファイルをダブルクリックして中身をのぞいてみると、
| www.futomi.com FALSE /cgi-bin/lecture FALSE 988884260 CookieTest1 %83e%83X%83g%82P www.futomi.com FALSE /cgi-bin/lecture FALSE 988884260 CookieTest2 %83e%83X%83g%82Q |
という行がありますね。これが先ほどセットされた Cookie 情報です。
いつも知らず知らずのうちに仕込まれてしまう Cookie ですが、Netscape の設定で都度確認画面を出すことができます。残念ながら Internet Explorer ではできません。
まず、Netscape Communicator の設定を変更しなければいけません。ツールバーから「編集(E)」→「設定(E)...」を選択してください。カテゴリ欄の「詳細」を選択すると、右側に詳細設定画面が表示されます。ここの「Cookie」の欄で「cookieを受け付ける前に警告する(W)」にチェックを入れてください。
これで、下図のとおり、Cookie を受け付ける都度、確認画面が出てくるようになります。(普段は非常にうっとうしいですがね…)

Cookie をセットするには、Java スクリプトでも可能ですが、ここでは Perl で作る CGI でどうすればいいかを解説します。先ほどのレスポンスヘッダーをもう一度ご覧下さい。実際には、以下の文字列をレスポンスヘッダーとしてブラウザーに返します。
| Set-Cookie: CookieTest=%83e%83X%83g; expires=Tue, 01-May-2001 11:32:58 GMT; Content-Type: text/html 以下、HTMLが続く |
Perl スクリプトで出力する際には、
| print 'Set-Cookie: CookieTest=%83e%83X%83g; expires=Tue, 01-May-2001 11:32:58 GMT;'; print 'Content-Type: text/html',"\n"; print "\n"; print "以下、HTMLが続く\n"; |
のようになります。
これはあくまでも例ですが、基本的に次に示すような文法で、サーバからクライアントへレスポンスヘッダーに加えます。
| Set-Cookie: クッキー名=クッキー値; expires=有効期限; domain=ドメイン名(サーバ名); path=パス; secure |
それぞれの意味は以下のとおりです。
| クッキー名=クッキー値 | ブラウザーに保存したい変数名とその値をセットします。スペース、カンマ、セミコロンは含まれてはいけません。そのため URL エンコードをする必要があります。(後述) Cookie をセットする際には、この項目のみが必須です。 |
| expires | クッキーの有効期限をセットします。有効期限は GMT で指定します。フォーマットは以下のとおりです。
Wdy, DD-Mon-YYYY HH:MM:SS GMT 有効期限が省略されると、テンポラリークッキーとして扱われます。つまり、ブラウザーを閉じた時点で、そのクッキーは無効となります。(後述) |
| domain | セットしたクッキーが送信されるドメインを指定します。サーバ名で指定すれば、指定サーバへのアクセスの時だけセットしたクッキーを送信します。ドメインが省略されると、そのときアクセスしたサーバ名がセットされます。
先ほどの実験でアクセスした URL は、 |
| path | セットしたクッキーが送信されるパスを指定します。パスが省略されると、アクセスしたリソース(HTML、CGI)のパスがセットされます。
先ほどの実験でアクセスしたURLは、 |
| secure | この項目が指定されていると、アクセス先が SSL などのような安全なサイトの場合のみにクッキーを送信するようになります。ドメイン、パスが一致したとしても、アクセス先が安全とみなされないと、クッキーを送信しません。 |
【domain, path の補足】
ブラウザーに保存された Cookie は、サーバ側の要求あるなしにかかわらずサーバへ送信されます。しかし、domain と path に一致した場合にのみ Cookie をサーバへ送信します。domain, path を省略すると、その Cookie をブラウザーにセットした CGI の domain と path が設定されますので、同じサーバでかつ、同じパス配下にアクセスしたときだけその Cookie をサーバへ送信します。
しかし、Cookie をセットした CGI 以外のリソースにアクセスしたときも、その Cookie 情報を得たい場合があります。そのときは、どうすればいいのでしょう。具体的に、今回の実験で説明します。
Cookie をセットした CGI のURLは、「http://www.futomi.com/cgi-bin/lecture/cookietest.cgi」です。今回の実験では、その Cookie を取得する CGI も同じですので、問題はなかったのです。しかし、「http://www.futomi.com/cgi-bin/test/cookieget.cgi」にアクセスしたときに、その Cookie を取得するにはどうすればいいのでしょうか。この場合、パスが /cgi-bin/test/ であるのに対し、Cookie をセットしたパスが /cgi-bin/lecture/ ですので、その Cookie 情報をサーバへ送信しません。これを /cgi-bin/test/ にアクセスしたときにも送信するような path で明示的に Cookie をセットしなければいけません。この場合には、 path=/cgi-bin/ とすればいいのです。こうすれば、/cgi-bin/ 配下のすべてのリソースにアクセスしたときに、Cookie 情報をサーバへ送信することになるのです。極端なことをいうと、path=/ としてしまうと、www.futomi.com すべてのリソースにアクセスしたときすべてにCookie 情報を送信することになるのです。
Cookie は、場合によっては、プライバシーにかかわる情報をセットする場合があります。やはり、無駄に Cookie 情報をサーバに送りつけるのは、セキュリティーの観点からも危険です。前述の例のように path=/ とした場合、もしサーバがプロバイダーが提供する共用のサーバだった場合には、同じサーバを利用している他のユーザのホームページへアクセスした場合にも Cookie を送信してしまうのでう。もし、明示的に domain, path を指定する場合には、できる限り、domain, path を厳密に指定したほうがいいのです。
クッキー名とクッキー値には、スペース、カンマ、セミコロンを含めてはいけません。そのような文字が出現しないようにエンコードする必要があります。今までの例でもお気づきのとおり、URLエンコードをしてからセットしなければいけません。本来「テスト」の部分が、URLエンコードをして「%83e%83X%83g」をとなっていますね。Perlスクリプトで URL エンコードするには以下のコードで実現できます。
| $CookieValue = 'テスト'; $CookieValue =~ s/([^\w\=\& ])/'%' . unpack("H2", $1)/eg; $CookieValue =~ tr/ /+/; |
URL エンコードは、RFC2396 で定義されています。
ブラウザーから送信された Cookie を CGI で受け取るには、環境変数 $ENV{'HTTP_COOKIE'} を使います。ブラウザーから送信された Cookie 情報はすべて $ENV{'HTTP_COOKIE'} に格納されますので、この値を見れば Perl スクリプト内で、その値を使うことができるのです。
先ほどの実験でも、$ENV{'HTTP_COOKIE'} の値がそのまま表示されますので、ご確認ください。以下のような値が表示されているはずです。
| 環境変数 HTTP_COOKIE |
| CookieTest1=%83e%83X%83g%82P; CookieTest2=%83e%83X%83g%82Q |
実験では2つのクッキーをセットしました。「クッキー名=クッキー値」のペアーが、セミコロンで区切られていますね。さらにセミコロンの後ろに半角スペースが入ります。もし3つ以上あっても同様に、セミコロンと半角スペースで区切られます。逆に1つだけの場合には、最後にセミコロンと半角スペースはつきません。
今回の実験では、クッキー値が URL エンコードしてありますので、これをデコードしないと意味がわかりません。次に URL エンコードされたクッキー値を、デコードする方法をご案内します。
URL デコードは、以下のコードで実現できます。
| $CookieValue =~ s/\+/ /g; $CookieValue =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C",hex($1))/eg; |
CGI を使って、クライアント(ブラウザー)にセットされた Cookie を無効にするにはどうすればいいのでしょうか。これは、その Cookie をセットしたときと同じ Cookie ヘッダーをクライアントへ送信すればいいのですが、有効期限を過去の時間にすればいいのです。そうすることで、ブラウザーは Cookie 情報をサーバへ送信することをしなくなります。過去の時間であればいつでも問題ありません。
サブルーチンコーナーにも、Cookieをクリア(無効に)するサブルーチンを公開しておりますが、
| expires=Thu, 01-Jan-1970 00:00:00 GMT |
としております。
Cookie ヘッダに expires を省略することで、テンポラリー Cookie をセットすることができます。テンポラリー Cookie とは、ブラウザーを閉じた時点で、無効になってしまいます。パスワードを入力させて、そのブラウザーを開いているときだけ CGI への要求を受け付けるようなアプリケーションに有効です。
では実験してみましょう。
先ほどの実験とまったく同じ画面ですので、Cookie をセットしたあと、Cookie を見てみてください。再度、今開いているブラウザーを閉じ、再度起動してから、実験ページを見てみてください。すると、Cookie がサーバへ送信されていないのがわかりますね。
このテンポラリー Cookieは、ファイルに保存されません。