てきとうなさいと べぇたばん

【PHP】 session.save_pathについて

session

この話の前提として、session.save_handlerはデフォルトのfilesである。

あれ、すぐにセッション切れる

セッションが切れるとは、例えばログインしている状態からいきなりログアウトになってしまうとか。別の要因もある可能性はあるけど。

セッションの設定

session.gc_maxlifetimeで設定した時間に到達したセッションは、gc_probability/gc_divisorの確率で破棄される。デフォルトでは24分(1440秒)過ぎたら、1/100の確率で破棄。

セッションの破棄の条件

session.gc_maxlifetimeで設定した時間に到達したセッションとは、いったい何のことを意味しているのだろう?

ソースコードを調べてみた。php-5.3.18のソースである。

ext/session/mod_files.cに、ps_files_cleanup_dirという関数を見つけた。そこで、session.save_pathで設定したディレクトリを開き、そこにあるセッションファイルを判定して条件に合致すれば削除というものだった。

     while (php_readdir_r(dir, (struct dirent *) dentry, &entry) == 0 && entry) {
         /* does the file start with our prefix? */
         if (!strncmp(entry->d_name, FILE_PREFIX, sizeof(FILE_PREFIX) - 1)) {
             size_t entry_len = strlen(entry->d_name);

             /* does it fit into our buffer? */
             if (entry_len + dirname_len + 2 < MAXPATHLEN) {
                 /* create the full path.. */
                 memcpy(buf + dirname_len + 1, entry->d_name, entry_len);

                 /* NUL terminate it and */
                 buf[dirname_len + entry_len + 1] = '\\0';

                 /* check whether its last access was more than maxlifet ago */
                 if (VCWD_STAT(buf, &sbuf) == 0 &&
                         (now - sbuf.st_mtime) > maxlifetime) {
                     VCWD_UNLINK(buf);
                     nrdels++;
                 }
             }
         }
     }

その条件として使われているsbuf.st_mtimeというものがsession.gc_maxlifetimeで設定されている値との比較に使われている。ちょっとソースの上に遡ると、こんな初期化がされている。

     struct stat sbuf;

statとはファイルの状態を取得する構造体である。man statを参照すると、st_mtimeとは最終修正時刻とある。ファイルが修正された場合に変更される値なのだ。

つまり、session.gc_maxlifetimeの値との比較対象は、最後にセッションが変更された時間ということになる。

session.save_pathの罠

セッションが削除される条件は、最後にセッションが変更された時間が、session.save_pathで設定したディレクトリから、session.gc_probability/session.gc_divisorの確率で、session.gc_maxlifetimeの値と比較して上回っていれば削除というもの。

これは、ひとつのサーバーで複数のWebアプリケーションを利用しているとトラブルのもとになりやすい。たとえば、以下のような設定になっている3つくらいのWebアプリケーションがあったとする。

Webアプリケーションのsession.gc_maxlifetimeの設定
名前 session.gc_maxlifetime session.save_path
Webアプリケーション A 1440 /tmp
Webアプリケーション B 14400 /tmp
Webアプリケーション C 86400 /tmp

Webアプリケーション A、B、Cのセッションは一体いつまで持つでしょう?

答えはA、B、Cとも1440秒に到達したら、session.gc_probability/session.gc_divisorの確率で削除。

なぜなら、WebアプリケーションAで上記の条件に当てはまった時点で/tmpのファイルは削除の対象になってしまうため。削除するセッションがどのWebアプリケーションで使用されているか、という判断は出来ないのである。

session.save_pathは別々に設定しましょう!

なので、Webアプリケーションごとにsession.save_pathは別々に設定しましょう!CakePHPとかのフレームワークつかえば、ココらへんは意識しなくても大丈夫ですけどね。

session.gc_maxlifetimeの項目にも書いてあるので、一読しとくといいとおもいます。

異なる値を session.gc_maxlifetime に指定している 別々のスクリプトがセッションデータの保存場所を共有している場合、 一番小さい設定値に達した時点でデータが消去されます。このような場合には、 お互いに session.save_path を使用します。