michihide's blog

技術メモおよび雑感

phpでセッションの情報が消える

【概要】

  • 現象
    • PHPで書いた申請フォームで、ユーザIDによる認証を行っているが、時々申請者のメールアドレスが""@example.comとなることがある。
  • 原因
    • 入力に時間がかかりすぎたためにセッションがタイムアウトし、セッション情報(ここではユーザID)が削除されてしまっていた。
  • 対策
    • セッションの有効期限を長くする。

【セッションの有効期限とガーベッジ・コレクション

  • セッションの有効期限は、session.gc_maxlifetime パラメータで制御されている。デフォルトは24分。
    • - GCはGarbage Collection(ごみ掃除)の略。
    • - GC とは、不要になったメモリ領域やファイルを削除すること。
    • - ほとんどのプログラム言語の実行部分において、自動的に行われることが多い。
    • - C 言語など一部の GC 機構のない言語では、プログラマが自分で領域の確保/解放を行わなければならない。
  • このパラメータは、セッション情報をサーバ上で残すべき時間を指定する
  • これを超えると、消される「可能性」が生じる(必ず消えるとは限らない)
  • セッション情報は、デフォルト(session.save_handler=files)ではファイルに格納されている

【セッションが消される契機(トリガー)】

  • 同じAache+PHPのバイナリを共有する、いずれかのページ/アプリケーションに誰かがアクセスした時
    • 問題が起きたのと同じアプリケーションとは限らない
  • アクセスごとに毎回 GC をやらせるとシステムに負荷がかかるため、毎回 GC を行うかどうかの判定(確率計算)が行われる
    • - session.gc_probability ÷ session.gc_divisor の値が 1 になったら削除
    • - デフォルトでは 1 ÷ 1000 =1000分の1の確率で、期限切れのセッションファイルが削除される

【問題点】

  • 現象
    • Apache の VirtualHost の設定で session.gc_maxlifetime を延ばしても効かないことがある
  • 原因
    • 同じホスト(かつ、同じセッション保持用ディレクトリ)を共有するすべての VirtualHost のうち一つでもこの設定がなされていないと、その設定していない VirtualHost にアクセスがあった場合、php.ini のデフォルト 値が有効となってしまうため。

【対策(1)】

  • 対策
    • /etc/php.ini を修正し、session.gc_maxlifetime を延ばす
  • 利点
    • 簡単
  • 欠点
    1. 1.影響が全 VirtualHost に及ぶ
    2. 2.yum updateによりphpのバージョンが上がると、php.iniが上書きされてしまう可能性あり

【対策(2) - 公式マニュアルではこちらを推奨】

  • 対策
    • セッションの格納位置(session.save_path)の設定を、各 VirtualHost ごとに別々にする
  • 利点
    • VirtualHost間の相互影響範囲を限定できる
  • 欠点
    • あらかじめそれぞれのディレクトリを用意する必要がある

【備考】

  • 多くのセッション情報(セッションファイル)の中でどのセッション情報を使うかは、クライアントが送りつけてくるクッキー(Set-cookie:ヘッダ)で決まる。
  • たとえセッション情報の有効期限が session.gc_maxlifetime に達していなくても、クライアントがクッキーを送ってこない(もしくは別のクッキーを送って来た)場合、別セッション扱いとなり、セッション情報は引き継がれない。
  • クライアントが(ブラウザで保持している)クッキーを送るかどうかは、以下のパラメータで決まる。
    • session.cookie_lifetime : クッキーの有効期限(単位:秒、デフォルト180)

【参考資料】
以下のサイトを参考にさせていただきました:
セッションの有効期間とか設定とか挙動とかを調べました