PHPでのクッキーの削除

HTTP cookieについて整理したので,実際にPHPでクッキーを使ったセッション情報の管理処理を勉強していた。

ネット上のサンプルでのPHPでのクッキーの削除時のExpires属性に,意味不明な数字が指定されていて気持ち悪かったので調べた。

結論としては,クッキーの削除時にはExpires属性に1を指定するのがいいだろうと判断した。

setcookie(session_name(), '', 1, '/');

導入

PHPでのクッキーの削除コードに以下のようなコードが,本 (例: 「改訂版 今すぐ導入!PHP×PostgreSQLで作る最強Webシステム (Gihyo Expert Books)」p. 76) やネット上のサンプルなどでよく見かける。

setcookie(session_name(), '', time() - 42000, '/');
setcookie(session_name(), '', time() - 3600, '/');

setcookieの引数は,順番に,クッキー名,クッキー値,Expires属性,Domain属性となる。

クッキーを削除するので,現在のセッション名をsession_name()で指定し,削除するので値は空 (''),削除対象ドメインを指定 ('/') というように,第1, 2, 4引数の意味はわかる。

問題なのは,第3引数のExpires属性の指定だ。time() - 42000time() - 3600と指定されている。time()により現在時刻をUNIXタイムスタンプで取得し,そこから42000秒 (700分,11.666666667時間) または3600秒 (60分, 1時間) を引いた過去の日時を指定している。

クッキーを削除するには,Set-CookieヘッダーのExpires属性に過去の日時を指定するしかない。現在日時を指定した場合,一瞬だけブラウザーにクッキーが保存されてしまい,余計な処理が増えてしまう。

従って,time() - 何らかの数字として,過去の日時を指定するのは問題ない。ただし,過去であれば1でも100でも何でもいいのにも関わらず,42000や3600のように意味ありげな数字が指定されているのが気持ち悪い。

原因

原因を調べたところ,どうやらこれらの数字は,PHPの公式マニュアルのsetcookie関数session_destroy関数で,サンプルとして掲載されている数字だった。おそらく,公式マニュアルに書かれている内容をそのまま流用しており,コピーペーストで広まったのだろう。

そもそもtime関数を使った現在日時からの差分での表現に問題がある。なぜならば,OSの時刻操作などで,現在時刻を過去の日時にしてしまった場合,time() - 3600などの差分の結果が0になる可能性がある。

PHPのsetcookie関数のExpires属性に相当する引数に0を指定した場合,以下に記載がある通り,指定を省いたのと同じで,有効期限がブラウザ終了時と解釈される。

expires

The time the cookie expires. This is a Unix timestamp so is in number of
seconds since the epoch. In other words, you’ll most likely set this
with the time() function plus the number of seconds before you want it
to expire. Or you might use mktime(). time()+60*60*24*30 will set the
cookie to expire in 30 days. If set to 0, or omitted, the cookie will expire at the end of the session (when the browser closes).

PHP: setcookie – Manual

つまり,クッキーを削除するどころか値を設定してしまうことになり,意味が全く変わってしまう。

また,差分で値を表現する場合,time関数が万が一下限値を返却した場合に,オーバーフローする可能性がある。

time関数の返却値の型はintである。int型の値がオーバーフローした場合,自動的にfloat型に変換される。ただし,float型からint型に変換する場合,floatが整数の範囲を超過する場合,結果が未定義となる。

From floating point numbers

When converting from float to integer, the number will be rounded towards zero.

If the float is beyond the boundaries of integer (usually +/- 2.15e+9 =
2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms
other than Windows), the result is undefined, since the float doesn’t
have enough precision to give an exact integer result. No warning, not
even a notice will be issued when this happens!

PHP: Integers – Manual

そのため,time関数が万が一,int型の最小値 (PHP_INT_MIN) を返却する場合,setcookieの第3引数のExpires属性はint型なので,未定義の値となりえる。

さらに,現在日時が万が一int型の最小値 (PHP_INT_MIN) の場合,それより過去の日時を指定不可能だ。HTTP cookieの仕様としても,Expires属性の値が限界値を超過した場合,限界値とみなされるため,過去の日時の指定が不可能となる。

もっとも,現実問題としてOSの日時が変更されてこのような限界値に達することがあるのかという議論はもちろんある。ただし,それをいってしまえば,OSの日時が過去に達することを考慮すること自体が無駄だろう。

どちらにしても,過去の日時を差分で表現する場合,値が0になることとオーバーフローの問題を回避できない

したがって,OSの日時が過去になることを考慮しても問題を解決できず,意味がないので,固定値の決め打ちでExpires属性を指定して問題ないように思う。具体的には,以下のようにExpires属性に1を指定する。

setcookie(session_name(), '', 1, '/');

0は未指定を意味するため,0以外の最小値・最短値として1を選定した。

結論

PHPでのsetcookie関数によるクッキーの削除方法を検討した。

細かいことではあるが,クッキーの削除は基本事項であり,ネット上の情報に揺らぎがあり,気になってしまった。

自分なりにどうすればいいか結論を出せたので,今後はこの方針に従う。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です