LoginSignup
4
5

More than 5 years have passed since last update.

PHPでクッキーの寿命をPHP_INT_MAXにしようとすると64bitでハマる

Last updated at Posted at 2013-11-11
<?php
setcookie("TestCookie", $value, PHP_INT_MAX);

などと書くと、64bit環境で

PHP Warning:  Expiry date cannot have a year greater than 9999 in hoge.php

などというエラーが出る。32bit環境だとPHP_INT_MAXは西暦2038年だが、64bit環境だと西暦3000億年だからだろう。PHPにはありがちなことだが、そのような機能制限についてドキュメントは存在しない。
http://php.net/manual/ja/function.setcookie.php
(もっとも、PHPがこれを通したとしても、ブラウザ側が適切に扱えないという事はありそうなので、PHPだけを責めるわけにもいかないが)

2038年問題を避けようとした結果がごらんの有様だよ!
具体的にどういう動作になるのかとか、正確にはいくつまでOKなのかは調べていない。エラーメッセージを素直に信じるなら、西暦9999年12月31日23時59分59秒が上限だろう。
果てしなくどうでもいい問題だが、踏んだので記念パピコ。

追記:
setcookieの実装はここ(エラーメッセージの定義もここ)
https://github.com/php/php-src/blob/94e15ff3877f842e5eb5c89e3aeab214fb4a3a33/ext/standard/head.c#L76
日付のフォーマット関数が呼ばれて
https://github.com/php/php-src/blob/19e8052be31d8361477906932f4c6dc9cd738de2/ext/date/php_date.c#L1219
フォーマット関数で
https://github.com/php/php-src/blob/94e15ff3877f842e5eb5c89e3aeab214fb4a3a33/ext/date/lib/unixtime2tm.c#L40

while (tmp_days >= DAYS_PER_LYEAR) {
    cur_year++;
    if (timelib_is_leap(cur_year)) {
        tmp_days -= DAYS_PER_LYEAR;
    } else {
        tmp_days -= DAYS_PER_YEAR;
    }
}

となるので、ここで3000億年分ループを回して関数が呼ばれるため、たいていの環境で処理がタイムアウトする。また、9999を超えるとエラー扱いになるため(最初のコード)、クッキーは吐かれない。
(タイムスタンプをいじりながら確認すると、処理時間が線形で伸びていくのがわかる)

なお、9999年までは正常に吐けることを確認(PHP 5.3.9 64bit)。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5