PHPのセッションが勝手に消えてしまう問題と解決法
PHPで開発をしていると、セッションを使用することがあると思います。
これはCookieと違い、ユーザーに書き換えることができないという利点がありますが、先日、このセッションデータが勝手に消えてしまう問題が発生しました。
今回はこの時のことを書いていこうと思います。
目次
環境について
今回、問題が発生した環境は下記のような感じでした。
- 新規案件としてお客様に指定された環境へ、PHPプロジェクトを構築した
- 他社が開発した既存のPHPシステムが複数存在していたことが問題発生後に調べて分かった
- PHPの設定は特に変な設定をしていない
- 既存のシステムではセッションも使用していたが、特に問題は発生していない
- 今回開発したプロジェクトで使用しているセッションデータが勝手に消えた
PHPの設定を見直す
まず調べたのはPHPの設定でした。
その結果、設定は下記のような感じになってました。
ブラウザにセッションIDのCookieを発行する際のCookieの有効期限。
これは0(=ブラウザを閉じるまで)が設定されたました。
session.gc_maxlifetime
サーバに保存されているセッションファイルを保護する有効期限。
デフォルトは1440秒ですが、それ以上に延ばされていました。
session.gc_divisor
session.gc_maxlifetimeを過ぎると必ずセッションファイルが削除されるわけではなく、PHPにリクエストがあったときに(session.gc_probability / session.gc_divisor)の確率でGCが起動して実際に削除されるそうです。
session.gc_probability は 1、session.gc_divisor は 1000 が設定されていましたので 1/1000 の確率で消えるということですね。
その他設定
session.save_path や session.save_handler、session.use_strict_mode なども見てみましたが、特に問題はありませんでした。
勝手に消える原因は?
ではここから、今回の環境で勝手にセッションが消える原因を解説していきます。
原因 その1
みなさんは今回の環境情報だけで、このセッションが消える原因がわかりましたか?
正解は PHPが設定に従ってセッションを消していた です。
どういうことか、図にして説明していきます。
この図を見ると分かると思いますが すべてのシステムが同じセッションパスを共有している というところに落とし穴があります。
この結果、何が起きるかというと すべてのアクセスにおいて全セッションファイルがガベージコレクション処理の対象になる ということです。
先ほど設定のところに記載してあった session.gc_divisor ですが、この環境では 1/1000 でした。
これは セッション有効期限が切れたとき、1/1000の確率でガベージコレクション処理が走る という意味です。
ではこの ガベージコレクション処理の対象となるもの はどこになるでしょうか?
それは アクセスしている当該システムが使用しているPHP設定の、セッションの保存先にある全セッションファイル です。
つまり、上記の図ではシステムA、システムB、システムC、そして今回導入したシステムのセッションファイルは いずれかのシステムでガベージコレクションが走るとすべて削除対象となる のです。
原因 その2
さらに、原因はもう一つあります。
説明のために図を書きました。
さて、この図から ガベージコレクションは最短どれくらいで発生する かわかりますか?
正解は システムAの1440秒(24分) です。
つまり、システムAを使用している人が24分の有効時間を過ぎた場合、ガベージコレクションが走ります。
そしてその削除対象は・・・もうお分かりですね?
システムAで設定されているセッション保存先にある全セッションファイル が対象となります。
その結果、他のシステムで session.gc_maxlifetime をいくら伸ばそうと、システムAを使用している人がいる限り、最短24分でセッションデータが消えることになります。
これが今回 「勝手にPHPのセッションが消えた原因」 のすべてです。
解決するには?
この問題を解決するには システムが使用しているセッション領域を変更する ことです。
つまり session.save_path をシステムごとに変更してあげれば解決します。
PHPの命令なら「session_save_path」、htaccessなら「php_value session.save_path」で変更ができます。
1 2 3 4 5 6 |
<?php // sessionの場所を変更 session_save_path('/foo/bar/session'); |
1 2 3 4 |
# sessionの場所を変更 php_value session.save_path "/foo/bar/session" |
CakePHP3の場合、下記のようにすることで自分のプロジェクトにセッションの保存先を変更できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php return [ 'Session' => [ // defaults を cake にすることで cake-project/tmp/session/ にセッションデータが格納されるようになる 'defaults' => 'cake', 'cookie' => 'session_name', 'timeout' => 60*24, 'ini' => [ 'session.cookie_secure' => false, 'session.cookie_path' => '/', 'session.gc_probability' => 1, 'session.gc_divisor' => 1000, ], ], ]; |
cake-project/tmp/ に session ディレクトリを作成しないと、エラーになってしまう事に注意してください。
さいごに
インターネットで検索すると、ほとんどが「設定の見直し」を書かれていると思いますが、システムが多数絡んだ時のことは見受けられませんでしたので、今回記載しようと思った次第です。
複雑に絡めば絡むほど原因の調査は難航しますので、何かの助けになればと思います。
- おすすめ記事
-
-
のえる2016.02.08
-
CakePHP3でPEARライブラリを使う方法
のえる2016.02.19
-
POPULAR
のえる
Full-stack Developer