セッションの有効期間(2/2)

CakePHPのセッション有効期間

今度はCakePHPのお話。CakePHPでは

  • Session.timeout
  • Security.level

が関係します。

(以下はSession.save=PHPとしている場合の話です)

timeoutで秒数を指定して、levelにより決まった係数をその秒数に掛け算したものが有効期間となります。わかりにくいのでサンプルを・・

timeout = 10、level = high(係数10)

=> 10 * 10 = 100秒

timeout = 10、level = medium(係数100)

=> 10 * 100 = 1,000秒

timeout = 10、level = low(係数300)

=> 10 * 300 = 3,000秒

となります。

ちなみにこの有効期間はPHPgc_maxlifetime とは何の関係もありません。CakePHPが独自に管理しています。独自とは言っても、セッション変数にtimeパラメータを持たせてるだけです。興味があればsession.phpを読めばすぐわかります。

ちなみに、明示的なパラメータは無いのですが、CakePHPはブラウザのクッキー期限も設定します。これはまんまcookie_lifetimeを設定しています。これもSecurity.levelによって設定する値が異なります。

  • high: cookie_lifetime = 0(ブラウザを終了するまで)
  • medium: cookie_lifetime = 7 * 86400(7日)
  • low: cookie_lifetime = 788940000(25年ぐらい)

しかもこれは、アクセスする度にSet-Cookieするので、mediumだったら最終アクセスから7日経過すればブラウザはセッションIDを送ってこなくなります。PHP単体におまかせするとセッション開始時だけしかSet-Cookieを送ってこないので・・。

そしたら、Session.timeout を1000にすれば、level=highでも10,000秒セッションは有効になるの?

それがそうとも限らないのです。前回の説明でPHPのセッション管理を説明しましたが、セッションデータファイルはPHPが管理しているので、CakePHPが知らない間にセッションデータファイルが消される可能性があります。具体的にはこんな場合です。

  • PHPの設定
    • gc_maxlifetime = 1800 (30分)
    • gc_divisor = 1
    • gc_probability = 1(GCが絶対に走るように)
  • CakePHPの設定
    • Session.timeout = 720
    • Security.level = high ( => 7,200秒 = 2時間)

で、ブラウザを2つ用意します。FireFox(FF)とInternetExplorer(IE)を用意したとしましょうか。次にCakePHPにセッション動作確認用のページを用意します。こんなページでOKです。

$p = $this->Session->read("hoge");
var_dump($p);
$this->Session->write("hoge", 1);
exit;

セッションデータが有効ならint(1)、無効ならNULLが出力されるようになってます。

  1. まずFFでCakePHPのページにアクセスします。最初は当然NULLですね。
  2. 再読み込みします。int(1)になりましたね。セッションが有効になりました。
  3. 次にシステムの時計を1時間早めます。FFは放置です。終了させてはいけません。
  4. 今度はIEでアクセスします。IEでもNULL->int(1)となってセッションが有効になったことを確認できます。
  5. ではFFで再読み込みします。CakePHPの設定では2時間有効なハズなのでint(1)になるハズですが、結果はどうですか?NULLになりましたね。

つまり、IEでアクセスした時に、FFのセッションデータファイルが削除されてしまったということです。この問題を回避する方法はまぁ色々ありますが、素直にgc_maxlifetime=7200とするのがわかりやすいでしょうか。

ま、PHPCakePHPでセッションの有効期間を厳密に定義すること自体そうそう無いことなのですが、内部的にはこういうカラクリになっていることを知っておいても損はないでしょう。