|
|
前のページ 1 2
|
|
実際の実装方法 |
本稿の実装例では、アクセスするWebサーバーを固定化するのではなく、セッション情報の保存先を固定化してHTTPセッションの永続性を確保することにします(リスト3)。
リスト3:PHPのPostgreSQL用セッションセーブハンドラの実装例
|
<?php
// pgsql-session.php
/*
セッションテーブル:各sessionデータベースにあらかじめ作成
CREATE TABLE php_session (
|
session_id | varchar(32) | NOT NULL,
|
i_created | integer | NOT NULL,
|
i_active | integer | NOT NULL,
|
t_remote_addr | varchar(20) | DEFAULT '',
|
t_session_data | text,
|
PRIMARY KEY (session_id)
|
);
*/
define('SESS_SV', 2); // セッションを保存するDBの数
// DB接続文字列。実際にDBホスト名はsession0, session1 ... session#の形式となる
define('SESS_DB','dbname=session user=yohgaki host=session');
define('SESS_TABLE','php_session'); // セッション情報テーブル
// セッションセーブハンドラを登録
session_set_save_handler (
'pg_session_open',
'pg_session_close',
'pg_session_read',
'pg_session_write',
'pg_session_destroy',
'pg_session_gc'
);
function pg_session_open ($save_path, $session_name) {
return true;
}
function pg_session_close() {
global $session_db;
pg_query($session_db,'COMMIT;');
return true;
}
function pg_session_read ($session_id) {
global $session_db;
if (strlen($session_id) != 32) {
return '';
}
// セッションID(MD5)の最初の5文字のアスキー値の足し算の結果を
// 利用するセッションDBのモジュロを算出し負荷を分散
$sum = 0;
for($i=0; $i<5; $i++) {
$sum += ord($session_id{$i});
}
$session_db = pg_pconnect(SESS_DB.$sum%SESS_SV);
$session_id = pg_escape_string($session_id);
$result = pg_query($session_db, 'BEGIN TRANSACTION; SELECT * FROM '. SESS_TABLE ." WHERE session_id = '$session_id' FOR UPDATE");
if (!pg_num_rows($result)) {
define('SESSION', false);
return '';
}
$sess = pg_fetch_assoc($result);
define('SESSION', true);
return $sess['t_session_data'];
}
function pg_session_write ($session_id, $session_data) {
global $session_db;
if (strlen($session_id) != 32) {
return false;
}
$session_id = pg_escape_string($session_id);
$session_data = pg_escape_string($session_data);
if (SESSION) {
$query = 'UPDATE '. SESS_TABLE ." SET i_active = ". time() .", t_session_data = '$session_data' WHERE session_id = '$session_id';";
} else {
$query = 'INSERT INTO '. SESS_TABLE ." (session_id, i_created, i_active, t_remote_addr, t_session_data) VALUES ('$session_id', ". time() .", ". time() .", '". $_SERVER['REMOTE_ADDR'] ."', '$session_data');";
}
pg_query($session_db,$query);
return true;
}
function pg_session_destroy ($session_id) {
global $session_db;
pg_query($session_db, 'DELETE FROM '. SESS_TABLE ." WHERE session_id = '". pg_escape_string($session_id). "'");
if (pg_errormessage($session_db)) {
return false;
}
return true;
}
function pg_session_gc ($maxlifetime = 4000) {
global $session_db;
pg_query($session_db, 'DELETE FROM '. SESS_TABLE ." WHERE i_active < ". (time() - $maxlifetime));
if (pg_errormessage($session_db)) {
return false;
}
return true;
}
?>
|
|
セッションセーブハンドラのコードは、通常のセッションセーブハンドラとほぼ同じです。違う部分は、負荷分散を行うために利用するセッションデータベースを、セッションIDを基に算出している部分(リスト3の白文字)のみです。リスト4にその部分を抜粋します。
リスト4:セッションデータベースの算出部分
|
// セッションID(MD5)の最初の5文字のアスキー値の足し算の結果を
// 利用するセッションDBのモジュロを算出し負荷を分散
$sum = 0;
for($i=0; $i<5; $i++) {
$sum += ord($session_id{$i});
}
$session_db = pg_pconnect(SESS_DB.$sum%SESS_SV);
|
Webサーバーを追加し、セッションデータベースのスケールアウトも必要となった場合にも、セッションデータを保存するデータベースは、必要に応じて追加可能です。
次回からはキャッシュについて解説していきます。
|
前のページ 1 2
|
|
|
|
著者プロフィール
大垣靖男(OHGAKI, Yasuo)
University of Denver卒。同校にてコンピュータサイエンスとビジネスを学ぶ。株式会社シーエーシーを経て、エレクトロニック・サービス・イニシアチブ有限会社を設立。Linuxはバージョン0.9xの黎明期から利用してるが、オープンソースシステム開発やコミュニティへの参加はエレクトロニック・サービス・イニシアチブ設立後から。PHPプロジェクトのPostgreSQLモジュールのメンテナ、日本PostgreSQLユーザ会の四国地域での活動等を担当している。
|
|
|
|
|
|
|