Perl/CGI研究室 'PERL-LABO'

Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

クッキーに有効期限を

研究内容

クッキーに有効期限を設定する研究です。

詳細

有効期限を設定しなかった場合

有効期限を設定しない場合、有効期限はブラウザを閉じるまでです。 これでは不便ですね。有効期限を設定して、ブラウザを閉じても クッキーが消えないようにする必要があります。

有効期限の設定方法

クッキーの有効期限を設定するには、HTTPヘッダの Set-cookie で次のようにします。

Set-Cookie: (保存するクッキーデータ); expires=(有効期限);

クッキーの後ろに、; で区切って有効期限を指定すればいいようです。 有効期限は、日付と時刻で指定します。 ここで指定した日付、時刻を越えると自動的にクッキーが削除されます。

有効期限の書式

この有効期限、 どのような書式で設定するのかというと、 例えば次のようにして指定します。

Set-Cookie: (保存するクッキーデータ); expires=Tue, 02-Dec-2003 09:00:00 GMT;

うーんこれは見慣れない形式ですね。少なくとも日本では。 曜日, 日-月-年 時:分:秒 GMT となっています。曜日と月は英語の略されているやつですね。 …これはちょっと困りました。

例えば、有効期限を、今から1週間、というようにしたい場合はどうしたらいいのでしょうか。 そう、1週間後の、上の形式での日付時刻表示を求めなければいけません。 そういう機能がPerlにあるのかな?と思ったら、残念ながらないみたいです。 ですので、日付時刻作成を自分でしないといけません。

結果

有効期限の日付時刻指定文字列の作成

有効期限は、今から〜日後 という形で指定したいですね。 そこで、有効期限を日数で指定すると、 Set-cookie 用の有効期限を指定する文字列を作成してくれる関数を作りましょう。

その関数はこうです。

sub makeexpiresdate
{
	local $delta;
	local ($gmt, @t, @m, @w);

	$delta = $_[0];

	@t = gmtime(time() + $delta*60*60*24);
	@m = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
	@w = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');

	$gmt = sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT",
			$w[$t[6]], $t[3], $m[$t[4]], $t[5]+1900, $t[2], $t[1], $t[0]);

	return $gmt;
}

引数にはクッキーを保存する日数を与えることにしました。

まず、現在の日付、時刻が無ければ、〜日後がいつなのかは分かりませんよね。 現在の日付と時刻は time 関数で取得します。 この time 関数、取得できるのは 1970年1月1日 00:00:00 からの秒数なんだそうです。 なので、コレに引数で渡されている日数を秒数に直したもの(*60*60*24)を加えて、 有効期限時刻にしています。

そしてそれを gmtime という関数に渡します。 time 関数は秒数を返しますが、これを gmtime 関数は 年月日時分秒 に変えてくれます。 gmtime の結果を配列に代入すると、次の順番でデータが格納されます。

[0] 秒
[1] 分
[2] 時
[3] 日
[4] 月(1を引いたもの)
[5] 年(1900を引いたもの)
[6] 曜日(0〜6、日曜日が0)
[7] 1月1日からの経過日数
[8] 1または0(サマータイムかどうか)

ただし、注意。gmtime はグリニッジ標準時の日付と時刻を返します。 グリニッジ標準時というのは日本と9時間ずれてます。 地元の日付と時刻を得るには localtime という関数が利用できるみたいです。

さて、だいぶ近づいてきましたが、でもこれでは、欲しい形式にはなっていないですね。 というのは、曜日と月を英語の3文字のやつに変えないといけません。 これはPerlにはそういう機能が無いので、自前でやるしか無いようです。 あらかじめ3文字のをずらっと用意しておいて、それを使って3文字のやつにすることにします。 それが配列 @m と @w です。

これで必要な情報は揃いました。これを、sprintf 関数を使って文字列にします。 sprintf 関数は、文字列や数値をある決まった書式の1つの文字列にするのに便利な関数です。 sprintf(書式文字列, データ, データ, ...) というようにして使います。 書式文字列の中に %(書式) という形で書式を指定しておくと、 その部分を指定した書式でデータに置き換えてくれます。 データは引数の左側から順に使われていきます。 %s は文字列をそのまま。%02d は整数を2桁で(2桁未満のときは頭に 0 をつけます)、 %04d は整数4桁で(4桁未満のときはやっぱり頭に 0 )という意味です。 書式を指定する方法は他にもたくさんあります。

これを使えば、有効期限設定も簡単ですね。

作成したCGIプログラム

cookietest.cgi
#!/usr/bin/perl

$now_cookie = $ENV{"HTTP_COOKIE"};
$new_cookie = $now_cookie + 1;

$expires = makeexpiresdate(1);

print "Content-type: text/html\n";
print "Set-Cookie: $new_cookie; expires=$expires;\n";
print "\n";
print "$new_cookie<br>\n";
print "(リロードしてください)<br>\n";
print "($expires まで有効です)<br>\n";


sub makeexpiresdate
{
	local $delta;
	local ($gmt, @t, @m, @w);

	$delta = $_[0];

	@t = gmtime(time() + $delta*60*60*24);
	@m = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
	@w = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');

	$gmt = sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT",
			$w[$t[6]], $t[3], $m[$t[4]], $t[5]+1900, $t[2], $t[1], $t[0]);

	return $gmt;
}

実行結果

下のリンクをクリックしてみてください。 クッキーカウンタです。リロードすると数字が増えていきます。 有効期限を1日に設定していますので、 ブラウザを閉じても1日以内に戻ってくればクッキーが削除されず続きになります。

有効期限1日のクッキーカウンターです。(別窓で開きます)

考察

動きました。これでクッキーが消えずに済みますね。 ここでは有効期限を1日にしましたが、通常はもっと長く、1ヶ月とか1年とかにするようです。 その場合でも、makeexpiresdate 関数の引数を 30 とか 365 とかにすればいいので、 簡単ですね。

分かったこと

  1. Cookieの有効期限はSet-Cookieで expires=有効期限を表す文字列; とします。
  2. 現在の時刻を知るにはまず time 関数で 1970年1月1日 00:00:00 からの秒数を得ます。
  3. time 関数で得た値を gmtime 関数や localtime 関数で年月日時分秒に変えられます。
  4. 決まった書式の文字列を作成するには sprintf 関数を使います。
  5. 環境変数HTTP_COOKIEの中にはexpiresは含まれないようです。
    現在のクッキーの有効期限を知ることは出来ないということですね。
Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

Copyright (c) 'PERL-LABO' All Rights Reserved.  リンクフリーです。