「Cookie の概要と使い方」で解説した通り、
Cookie の仕組みそのものはさほど難しいわけではありませんが、
Perl の Set-Cookie
ヘッダーの生成は意外に面倒です。
ほとんどのウェブシステムでは Cookie を扱うことになります。
しかし、毎度、同じような面倒なコードを書いていては時間の無駄であるだけでなく、
バグの原因にもなりかねません。
そこで、環境変数 $ENV{HTTP_COOKIE}
から Cookie 情報を抜き出したり、
Set-Cookie
ヘッダーを生成したりできる定番の
Perl モジュール「CGI::Cookie」
を紹介いたします。
CGI::Cookie は Perl で Cookie を扱うために使う Perl モジュールの一つです。 CGI を Perl で開発する上で定番の CGI.pm の関連モジュールです。 そのため、CGI.pm を一緒に使うことを想定されているものの、 CGI::Cookie 単独で利用することも可能です。
CGI::Cookie の主な機能は 2 つです。1 つは Set-Cookie
ヘッダーの生成、
もう一つは受信した Cookie のパースです。ここではそれぞれについて解説していきます。
CGI::Cookie を使って Set-Cookie
ヘッダーを生成するには、
次のようなコードを用意します。
use CGI::Cookie;
my $cookie = CGI::Cookie->new(
-name => "nickname",
-value => "Taro"
);
print $cookie; # nickname=Taro; path=/
上記コードは CGI::Cookie を使って Set-Cookie
ヘッダーを生成する必要最小限のコードです。
new()
の引数に Cookie の名前や値、そして、属性を定義します。
このコードから nickname=Taro; path=/
という文字列が得られます。
ここで注意してほしいのは、path 属性に /
が自動的にセットされる点です。
多くのシーンではこれで問題はありませんが、もし、パスを限定したいのであれば、
次のように path 属性を指定します。
my $cookie = CGI::Cookie->new(
-name => "nickname",
-value => "Taro",
-path => "/lecture/cookie"
);
これで nickname=Taro; path=/lecture/cookie
が得られます。
これを CGI の出力とする場合は、次のようなコードになります。
#!/usr/bin/perl
use strict;
use warnings;
use CGI::Cookie;
my $cookie = CGI::Cookie->new(
-name => "nickname",
-value => "Taro",
-path => "/lecture/cookie"
);
print "Set-Cookie: ${cookie}\n";
print "Content-Type: text/plain\n";
print "\n";
print $cookie;
「Cookie の概要と使い方」で解説した通り、Cookie 値で日本語を扱いたい場合は、 その値を URL エンコードする必要があります。 しかし、CGI::Cookie は、そのようなことを私たちが意識する必要がないいよう、必要に応じて、 自動的に URL エンコードを行ってくれます。
my $cookie = CGI::Cookie->new(
-name => "nickname",
-value => "太郎",
-path => "/lecture/cookie"
);
このコードで nickname=%E5%A4%AA%E9%83%8E; path=/lecture/cookie
が得られます。
CGI::Cookie は CGI 仕様で規定されているすべての属性を扱うことができます。 以下のコードは、CGI::Cookie ですべての属性を指定したサンプルです。
my $cookie = CGI::Cookie->new(
-name => "nickname",
-value => "Taro",
-path => "/lecture/cookie",
-expires => "+1d",
'-max-age' => "+1d",
-domain => ".futomi.com",
-secure => 1,
-httponly => 1,
-samesite => "Lax",
-priority => "High"
);
このコードによって、次のような値が得られます。
nickname=Taro; domain=.futomi.com; path=/lecture/cookie; expires=Tue, 07-Mar-2023 07:02:29 GMT; max-age=86400; secure; HttpOnly; SameSite=Lax; Priority=High
以下に、-name
, -value
, -path
を除いた各パラメータを解説します。
expires 属性を表し、Cookie の有効期限を指定します。
-expires
を指定しなければテンポラリ Cookie になります。
指定できる値は Tue, 07-Mar-2023 05:38:04 GMT
のように直接 Cookie 仕様に
基づいた日時形式を指定することもできますが、+1d
のように「1 日後」といった
現在からの相対時間の表現も受け付けます。指定できる値については後述します。
max-age 属性を表し、Cookie の有効期限を現在からの相対時間を指定します。
-expires
と同様に、+1d
のように「1 日後」といった
現在からの相対時間の表現も受け付けます。
Cookie 仕様では秒で指定することとなっていますが、CGI::Cookie では秒で指定する必要はありません。
指定できる値については後述します。
なお、Cookie の仕様では、expires と max-age の両方が指定された場合、max-age が優先されます。
domain 属性を表し、Cookie が有効となるドメインを指定します。
secure 属性を表し、このフラグをセットしたい場合は、-secure
に 1
をセットします。
HttpOnly 属性を表し、このフラグをセットしたい場合は、-httponly
に 1
をセットします。
SameSite 属性を表します。-samesite
には
Lax
, Strict
, None
のいずれかをセットします。
priority 属性を表します。-priority
には
Low
, Medium
, High
のいずれかをセットします。
なお、この属性は 2023 年 3 月現在、Chromium ベースの Chrome と Edge でのみ有効です。
※ -samesite
と -priority
は、
古いバージョンの CGI.pm がインストールされた環境ですと動作しない可能性があります。
-expires
と -max-age
には、+1d のような、
現在から見た相対時間を表す文字を指定することができます。
my $cookie = CGI::Cookie->new(
-name => "nickname",
-value => "Taro",
-expires => "+1d",
'-max-age' => "+1d"
);
実際に指定可能な値を例に挙げます。
表記例 | 説明 |
---|---|
+30s | 今から 30 秒 |
+10m | 今から 10 分 |
+1h | 今から 1 時間 |
-1d | 昨日 |
now | まさに今 |
+3M | 3 ヶ月後 |
+10y | 10 年後 |
上記の通り、先頭に +
を付けると未来を、-
を付けると過去を表します。
また、s
は秒、m
は分、h
は時間、d
は日、
M
は月、y
は年を表します。月だけ大文字ですので注意してください。
ブラウザーから送信された Cookie のデータは、環境変数 $ENV{HTTP_COOKIE}
から得られます。
Cookie データは、Cookie 名と Cookie 値のペアが複数存在していても、一つの文字列として得られます。
また、日本語などの値は URL エンコードされています。
そこで CGI::Cookie は環境変数 $ENV{HTTP_COOKIE}
の値を解析して、
Cookie 名を指定すれば URL デコード済みの Cookie 値を取り出す仕組みを提供してくれます。
次の CGI コードは、上記でセットした Cookie を読み取って画面に表示します。
use strict;
use warnings;
use CGI::Cookie;
print "Content-Type: text/plain; charset=utf-8\n";
print "\n";
my %cookies = CGI::Cookie->fetch;
print $cookies{screenname}->value;
上記コードを試す前に、まずは日本語の Cookie 値をブラウザーに仕込んでおきましょう。
これでブラウザーに Cookie 名 screenname
、Cookie 値 山田太郎
のペアがセットされます。
下のボタンを押して、Cookie を読み取ってみましょう。
ブラウザーには 山田太郎
と表示されたはずです。
この通り、URL エンコード済みの値もデコードしてくれます。
CGI::Cookie の基本的な使い方を解説しましたが、Cookie を簡単に扱えるようになることがお分かりいただけたのではないでしょうか。
CGI::Cookie は、このほか、CGI.pm を組み合わせて Set-Cookie
ヘッダーを短いコードで出力する機能なども提供しています。
もし興味があれば、英語となりますが
原文のドキュメントをご覧ください。