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分)以上経過したセッションファイルを自動削除してくれる。