14 June 2008

PHPのセッション管理

PHPのセッション管理はプログラムをする上で必須機能だが、あまり細かく考えたことが無かった。

まず、セッションの引継ぎ方法は、ユーザのブラウザでCookieが使えると仮定すれば、サーバ側で何も考えなくても引継ぎが行えている。 しかし、セキュリティ上の理由でCookieが保存されないように設定されている端末では、プログラムが利用できない不具合が出る。

セッションの引き渡し方をメモしてみると

Cookieが使える時 : ボタンコントロールのPOSTでページ遷移
<html> <body> <?php session_start(); print "session_id = " . session_id() . "<br>"; print "session_name = " . session_name() . "<br>"; print "session_save_path = " . session_save_path() . "<br>"; $_SESSION['ticket'] = md5(uniqid().mt_rand()); // 引き渡したい情報 print('ticket = ' . $_SESSION['ticket'] . '<br>'); ?> <form action="test1_receive.php" method="post"> <input type="hidden" name="ticket" value="<?= htmlspecialchars($_SESSION['ticket'], ENT_QUOTES); ?>"> <input type="submit" name="submit_button" value="次のページへ移動"> </form> </body> </html>
Cookieが使えない時 : ボタンコントロールのPOSTでページ遷移
<html> <body> <?php session_start(); print "session_id = " . session_id() . "<br>"; print "session_name = " . session_name() . "<br>"; print "session_save_path = " . session_save_path() . "<br>"; $_SESSION['ticket'] = md5(uniqid().mt_rand()); // 引き渡したい情報 print('ticket = ' . $_SESSION['ticket'] . '<br>'); ?> <form action="test1_receive.php" method="post"> <input type="hidden" name="ticket" value="<?= htmlspecialchars($_SESSION['ticket'], ENT_QUOTES); ?>"> <input type="hidden" name="<?=session_name()?>" value="<?=session_id()?>"> <input type="submit" name="submit_button" value="次のページへ移動"> </form> </body> </html>
Cookieが使えない時 : リンク a href= でページ遷移
<html> <body> <?php session_start(); print "session_id = " . session_id() . "<br>"; print "session_name = " . session_name() . "<br>"; print "session_save_path = " . session_save_path() . "<br>"; $_SESSION['ticket'] = md5(uniqid().mt_rand()); // 引き渡したい情報 print('ticket = ' . $_SESSION['ticket'] . '<br>'); ?> <a href="test1_receive.php?<?=SID?>">次のページへ移動</a> </body> </html>

なお、Cookieが使えるかどうかは、サーバ側でCookieにセッション情報を格納するオプションがONになっていない限り、ブラウザで幾らがんばっても使えない。

/etc/php.ini
; Whether to use cookies. session.use_cookies = 1


情報を受け取る側のプログラムはこんな感じになる。 プログラムでは特別なコーディング無しに、セッション情報が引き継がれてくる。

情報を受け取る側のプログラム (test1_receive.php)
<html> <body> <?php session_start(); print "session_id = " . session_id() . "<br>"; print "session_name = " . session_name() . "<br>"; print "session_save_path = " . session_save_path() . "<br>"; print('ticket = ' . $_SESSION['ticket'] . '<br>'); $_SESSION = array(); // セッション変数を全てクリア session_destroy(); // セッションファイルを削除 ?> </body> </html>

セッション情報を利用し終われば、サーバ側で利用しているセッション情報ファイルは消去すべきである。そのためのコマンドが、session_destroy(); だが、ユーザがページ途中で閲覧を放棄してしまった場合、セッションファイルが削除されずに残ることになる。

サーバにひたすら溜まり続けていくのかと思っていたが、ガベージコレクションでちゃんと消去してくれているようである。

CentOS 5 で、PHPのセッション一時ファイルの保管場所は、/var/lib/php/session なので、ネット上の一般的な情報の /tmp で無いからcronのスケジューラの自動削除対象にはあたっていないのだが、次の設定で自動消去されている。

/etc/php.ini
; Define the probability that the 'garbage collection' process is started ; on every session initialization. ; The probability is calculated by using gc_probability/gc_divisor, ; e.g. 1/100 means there is a 1% chance that the GC process starts ; on each request. session.gc_probability = 1 session.gc_divisor = 1000 ; After this number of seconds, stored data will be seen as 'garbage' and ; cleaned up by the garbage collection process. session.gc_maxlifetime = 1440

1000回アクセスがあるごとに、ガベージコレクションが1440秒(24分)以上経過したセッションファイルを自動削除してくれる。