1. 問題の原因 7 O8 X8 R7 o& Z) Y# i3 O
やや大きな Web サイトでは通常、複数のサーバーがあり、各サーバーは異なる機能を持つモジュールを実行し、異なる第 2 レベルのドメイン名を使用します。総合的な Web サイトでは、ユーザー システム、つまりユーザー名のセットが統一されています。 Web サイト全体のすべてのモジュールにログインします。サーバー間でのユーザー データの共有は、バックエンドにデータベース サーバーを配置するだけで比較的簡単に実装でき、各サーバーは統一されたインターフェイスを通じてユーザー データにアクセスできます。しかし、まだ問題があります。つまり、ユーザーがこのサーバーにログインした後、別のサーバーの他のモジュールに入るときに、再度ログインする必要があります。これは 1 回限りのログインであり、一般的な問題はすべて にマッピングされています。実際には、さまざまなサーバー間で SESSION データを共有する方法です。 ! n) o+ ~2 R# T8 P$ @ R% PC
/ S" G* k: }5 j' R( {7 v5 {
2. PHP セッションの仕組み # Z3 ?;
.C) Z, n# ]9 ^- K9 B8 }- G
;
問題を解決する前に、まず PHP SESSION がどのように機能するかを理解しましょう。クライアント (ブラウザなど) が Web サイトにログインすると、訪問した PHP ページは session_start() を使用して SESSION を開くことができ、これによりクライアントの一意の識別 SESSION ID が生成されます (この ID は関数 session_id( ))。 SESSION ID は 2 つの方法でクライアントに保持できるため、PHP プログラムは別のページをリクエストするときにクライアントの SESSION ID を学習できます。1 つは、デフォルトで GET URL または POST フォームに SESSION ID を自動的に追加することです。最初の方法では、変数名は PHPSESSID ですが、もう 1 つの方法では、COOKIE を通じてセッション ID を保存します。デフォルトでは、この COOKIE の名前は PHPSESSID です。ここでは、広く使われている COOKIE メソッドを中心に説明します。
; [' U9 u2 t-d
SESSION の仕組みを理解すると、デフォルトで各サーバーが同じクライアントの SESSION ID を生成することがわかります。たとえば、同じユーザー ブラウザの場合、サーバー A によって生成される SESSION ID は 30de1e9de3192ba6ce2992d27a1b6a0a であり、サーバーによって生成される SESSION ID は B です。 c72665af28a8b14c0fe11afe3b59b51b。また、PHP の SESSION データは、このサーバーのファイル システムに別途保存されます。以下の図に示すように: 8 w) T" B/ f, J+ t$ }1 R: f; q
) O# ^1 |, C- u+ t# Z
;
問題を特定したら、解決を開始できます。 SESSION データを共有したい場合は、2 つの目標を達成する必要があります。1 つは、同じクライアントに対して各サーバーによって生成された SESSION ID が同じである必要があり、同じ COOKIE を介して渡せることです。つまり、各サーバーは次のことを行うことができなければなりません。もう 1 つは、SESSION データの保存方法と場所が各サーバーにアクセスできるようにする必要があることです。簡単に言えば、複数のサーバーはクライアントの SESSION ID を共有し、サーバーの SESSION データも共有する必要があります。
" X8 {7 ]% Q5 k# a1 L
最初の目標の実現は実際には非常に簡単です。デフォルトでは、COOKIE のドメインは現在のサーバーのドメイン名/IP アドレスになります。各サーバーのドメインは異なります。たとえば、www.aaa.com のサーバーは、www.bbb.com のサーバーが設定した COOKIE を読み書きすることはできません。
- g8 q8 |; U1 u8 `6 K* J
ここで説明している同じ Web サイトのサーバーにはそれぞれ独自の特徴があります。つまり、同じ第 1 レベルのドメインに属しています。たとえば、aaa.infor96.com と www.infor96.com は両方ともドメイン .infor96 に属しています。 .com の場合、COOKIE のドメインを .infor96.com に設定して、aaa.infor96.com、www.infor96.com などがこの COOKIE にアクセスできるようにします。 PHPコードでの設定方法は以下の通りです
ini_set('session.cookie_domain', '.infor96.com');
?>
コードをコピー
このようにして、各サーバーが同じクライアント SESSION ID を共有するという目的が達成されます。 ; l, @8 W1 ]& ~.S: y9 O;
解決策は以下のとおりです: o T/ N( c0 x P/ ^" U6 A& c
5 H+ K1 h, f; `2 o) U
4. コードの実装 ! m1 C8 / r1 v) O
0 V3 {( ^; |! o! $ C) u3 Y0 b
まずデータテーブルを作成します。My SQL の SQL ステートメントは次のとおりです。
テーブル `sess` を作成 (
`expiry` bigint(20) NOT NULL デフォルト '0'、
`data` ロングテキスト NOT NULL,
主キー (`sesskey`)、
KEY `有効期限` (`有効期限`)
) TYPE=MyISAMsesskey は SESSION ID、expiry は SESSION の有効期限、data は SESSION データの保存に使用されます。
コードをコピー
セッションモジュール名('ユーザー');
?>
コードをコピー
次に、session_set_save_handle() 関数に注目してみましょう。この関数には 6 つのパラメーターがあります。
Define('MY_SESS_TIME', 3600); //SESSION 生存時間
//クラス定義
クラスMy_Sess
{
関数 init()
{
$domain = '.infor96.com';
//GET/POST変数メソッドは使用しないでください
ini_set('session.use_trans_sid', 0);
// ガベージ コレクションの最大存続時間を設定します
ini_set('session.gc_maxlifetime', MY_SESS_TIME);
//COOKIEを使用してSESSION IDを保存する方法
ini_set('session.use_cookies', 1);
ini_set('session.cookie_path', '/');
//複数のホストがセッション ID を保存する COOKIE を共有します
ini_set('session.cookie_domain', $domain);
// session.save_handler をデフォルトのファイルではなくユーザーに設定します
セッションモジュール名('ユーザー');
//SESSION の各操作に対応するメソッド名を定義します:
session_set_save_handler(
array ('My_Sess', 'open'), // 静的メソッド My_Sess::open() に対応、以下同様。
array('My_Sess', 'close'),
array('My_Sess', 'read'),
array('My_Sess', 'write'),
array('My_Sess', 'destroy'),
array('My_Sess', 'gc')
);
//関数の終了
関数 open($save_path, $session_name) {
true を返します;
//関数の終了
関数 close() {
グローバル $MY_SESS_CONN;
if($ my_sess_conn){
$MY_SESS_CONN->Close();
}
true を返します;
//関数の終了
関数 read($sesskey) {
グローバル $MY_SESS_CONN;
$sql = 'SELECT data FROM sess WHERE sesskey=' . $MY_SESS_CONN->qstr($sesskey) ' および expiry>=' 。
$rs =& $MY_SESS_CONN->実行($sql);
if ($rs) {
If ($rs->EOF) {
戻ります '';
//セッションIDに対応するセッションデータを読む
$v = $rs->fields[0];
$rs->Close();
$v を返す;
//end if
//end if
戻ります '';
//関数を終了します
関数 write($sesskey, $data) {
グローバル $MY_SESS_CONN;
$qkey = $MY_SESS_CONN->qstr($sesskey);
$expiry = time() + My_SESS_TIME;
//セッションを書きます
$arr = array(
'sesskey' => $qkey,
'有効期限' => $有効期限,
に
$MY_SESS_CONN->Replace('sess', $arr, 'sesskey', $autoQuote = true);
true を返します;
//関数の終了
関数 destroy($sesskey) {
グローバル $MY_SESS_CONN;
$MY_SESS_CONN->qstr($sesskey);
$rs =& $MY_SESS_CONN->実行($sql);
true を返します;
//関数の終了
関数 gc($maxlifetime = null) {
グローバル $MY_SESS_CONN;
$sql = 'sess WHERE から削除< time();
'
$MY_SESS_CONN->Execute($sql);
// テーブル sess での削除操作が頻繁に行われるため、断片化が発生しやすくなります。
//したがって、テーブルはガベージ コレクション中に最適化されます。
$sql = 'テーブル最適化セッション';
$MY_SESS_CONN->Execute($sql);
true を返します;
//関数の終了
} } ///:~
//ADOdb をデータベース抽象化レイヤーとして使用します。
require_once('adodb/adodb.inc.php');
//データベース設定項目は設定ファイル (config.inc.php など) に配置できます。
$db_type = 'mysql';
$db_host = '192.168.212.1';
$db_user = 'sess_user';
$db_pass = 'sess_pass';
$db_name = 'sess_db';
//データベース接続を作成します。これはグローバル変数です。
$GLOBALS['MY_SESS_CONN'] =& ADONewConnection($db_type);
$GLOBALS['MY_SESS_CONN']->Connect( $db_host, $db_user, $db_pass, $db_name);
//SESSION 設定を初期化します。session_start() の前に実行する必要があります。 !
My_Sess::init(); www.2cto.com
?>
コードをコピー
5. 残りの問題 ' % p* 9 a5 N+ G+ v
アクセス数が多いWebサイトの場合、SESSIONによるデータベースへの読み書きが頻繁に行われるため、効率が大幅に低下します。通常、SESSION データはそれほど大きくないことを考慮して、C/Java でマルチスレッド プログラムを作成し、HASH テーブルを使用して SESSION データを保存し、ソケット通信を通じてデータの読み書きを試みることができます。メモリに保存され、読み書き速度が大幅に向上するはずです。さらに、負荷分散によりサーバーの負荷を分散できます。