PHPでセッションハンドラを自作
PHPは標準機能でセッション管理ができますが、何故かセッション管理のみが正しく動作しないサーバーがあったので、セッションハンドラで対応してみた。
PHPでは標準命令の session_set_save_handler()
を使用すれば、セッションを扱う際の挙動を自分で決めることができます。(セッションをMySQLで管理する仕組みを自作したり、など。)
以下はファイルでセッションを管理するサンプル。
<?php
define('SESSION_HANDLER_PATH', dirname(__FILE__) . '/sessions/');
define('SESSION_HANDLER_PREFIX', 'session_');
define('SESSION_HANDLER_EXTENSION', '.log');
if (SESSION_HANDLER_PATH != '') {
$session_handler_path = SESSION_HANDLER_PATH;
} else {
$session_handler_path = '';
}
function session_handler_open($save_path, $session_name) {
global $session_handler_path;
if ($session_handler_path == '') {
$session_handler_path = $save_path;
}
return true;
}
function session_handler_close() {
global $session_handler_path;
return true;
}
function session_handler_read($session_id) {
global $session_handler_path;
$file = $session_handler_path . SESSION_HANDLER_PREFIX . $session_id . SESSION_HANDLER_EXTENSION;
if (file_exists($file)) {
return file_get_contents($file);
} else {
return null;
}
}
function session_handler_write($session_id, $data) {
global $session_handler_path;
$file = $session_handler_path . SESSION_HANDLER_PREFIX . $session_id . SESSION_HANDLER_EXTENSION;
return file_put_contents($file, $data);
}
function session_handler_destroy($session_id) {
global $session_handler_path;
$file = $session_handler_path . SESSION_HANDLER_PREFIX . $session_id . SESSION_HANDLER_EXTENSION;
unlink($file);
return true;
}
function session_handler_gc($lifetime) {
global $session_handler_path;
if ($dir = scandir($session_handler_path)) {
foreach ($dir as $entry) {
if (is_file($session_handler_path . $entry) and preg_match('/^' . preg_quote(SESSION_HANDLER_PREFIX, '/') . '\w+' . preg_quote(SESSION_HANDLER_EXTENSION, '/') . '$/i', $entry) and time() - filemtime($session_handler_path . $entry) > $lifetime) {
unlink($session_handler_path . $entry);
}
}
}
return true;
}
session_set_save_handler(
'session_handler_open',
'session_handler_close',
'session_handler_read',
'session_handler_write',
'session_handler_destroy',
'session_handler_gc'
);
?>
上のコードを一例ですが session_handler.php
という名前で保存し、同じディレクトリ内に sessions
というディレクトリを作成します。この中にセッションの情報が保存されます。
session_set_save_handler()
関数によって、「セッションを開始した時は session_handler_open()
が呼ばれる」「セッションを保存する時は session_handler_write()
が呼ばれる」のような設定を行っています。
以降は、以下のコードで自作のセッション管理を利用できます。
<?php
include_once('session_handler.php');
session_start();
if (isset($_SESSION['count'])) {
$_SESSION['count']++;
} else {
$_SESSION['count'] = 1;
}
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>サンプル</title>
</head>
<body>
<?php
echo $_SESSION['count'] . '回目のアクセスです。';
?>
</body>
</html>
include_once('session_handler.php');
でファイルを読み込む以外は、ごく普通のセッション利用サンプルです。
急きょ書いたコードなので変な箇所があるかもしれません。また、名前の重複を避けるためにもクラス化した方が良かったかも。と思っていたら、公式サイトにクラスのサンプルがあった…。またそのうち調べる予定。