TOP書籍連動> 実際の実装方法
まるごと PostgreSQL!
商用データベースに匹敵するWebシステム構築手法

第5回:HTTPセッションの永続性確保

著者:大垣靖男(OHGAKI, Yasuo)   2005/5/2
前のページ  1  2
実際の実装方法

   本稿の実装例では、アクセスするWebサーバーを固定化するのではなく、セッション情報の保存先を固定化してHTTPセッションの永続性を確保することにします(リスト3)。
リスト3:PHPのPostgreSQL用セッションセーブハンドラの実装例
<?php
// pgsql-session.php

/*
セッションテーブル:各sessionデータベースにあらかじめ作成
CREATE TABLE php_session (
session_idvarchar(32)NOT NULL,
i_createdintegerNOT NULL,
i_activeintegerNOT NULL,
t_remote_addrvarchar(20)DEFAULT '',
t_session_datatext,
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ユーザ会の四国地域での活動等を担当している。


INDEX
第5回:HTTPセッションの永続性確保
  レイヤー7スイッチ機能の実装
実際の実装方法