稍微大一點的網站,通常都會有不只一個伺服器,每個伺服器執行著不同的功能模組或者不同的子系統,他們使用不同的二級域名,比如www.a.com、i.a.com、bbs.a.com。而一個整體性強的網站,使用者系統是統一的,即一套使用者名稱、密碼在整個網站的各個子系統中都是可以登入使用的。各個伺服器共享使用者資料是比較容易實現的,只需要在後端放個資料庫伺服器,各個伺服器通過統一介面對使用者資料進行訪問即可。但還存在一個問題,就是使用者在i.a.com登入之後,進入www.a.com時,仍然需要重新登入,基本的通行證的問題,對映到技術上,其實就是各個伺服器之間如何實現共享
SESSION 資料的問題。
為了解決這個問題,我們採用將 SESSION 的資料儲存資料庫的方式。關於PHP SESSION的掃盲這裡就不在累贅。在預設情況下,各個伺服器會各自分別對同一個客戶端產生 SESSION ID,如對於同一個使用者瀏覽器,www.a.com系統產生的 SESSION ID 是a0211e9de3192ba6c22992d27a1b6a0a,而i.a.com生成的則是277003f262f0c366946a86a28ba431d8。另外,PHP 的 SESSION 資料都是分別儲存在本伺服器的檔案系統中。
想要共享 SESSION 資料,那就必須實現兩個目標:www.a.com和i.a.com所產生的SESSION ID相同,並且可通過同一個 COOKIE 進行傳遞,也就是說各個伺服器必須可以讀取同一個名為 PHPSESSID 的 COOKIE;另一個是 SESSION 資料必須存放在一個各個系統都能訪問到的地方。簡單地說就是多伺服器共享客戶端的 SESSION ID,同時還必須共享伺服器端的 SESSION
資料。
第一個目標的實現其實很簡單,只需要對 COOKIE 的域(domain)進行特殊地設定即可,預設情況下,COOKIE 的域是當前伺服器的域名/IP 地址,而域不同的話,各個伺服器所設定的 COOKIE 是不能相互訪問的,如 www.a.com 的伺服器是不能讀寫 www.b.com 伺服器設定的 COOKIE 的。這裡我們所說的同一網站的伺服器有其特殊性,那就是他們同屬於同一個一級域,如:www.a.com 和 i.a.com 都屬於域 .a.com,那麼我們就可以設定 COOKIE 的域為 .a.com,這樣
www.a.com、i.aaa.com 等等都可以訪問此 COOKIE。PHP 程式碼中的設定方法如下:
1 |
ini_set ( 'session.cookie_domain' , '.a.com' ); |
這樣各個系統共享同一客戶端 SESSION ID 的目的就達到了,下面就是共享SESSION資料,我們就將SESSION資料放在資料庫中,首先建立資料庫表:
1 |
CREATE TABLE sessions
( |
2 |
session_id varchar (32) NOT NULL , |
3 |
session_last_access int (10)
unsigned, |
5 |
PRIMARY KEY (session_id) |
session_id為主鍵,儲存SESSION ID ,session_last_access是SESSION最後更新時間,session_data是SESSION資料。
PHP 提供了session_set_save_handle() 函式,可以用此函式自定義 SESSION 的處理過程,當然首先要先將 session.save_handler 改成 user,可在 PHP 中進行設定:
接下來著重講一下 session_set_save_handle() 函式,此函式有六個引數:
session_set_save_handler ( string open, string close, string read, string write, string destroy, string gc )
各個引數為各項操作的函式名,這些操作依次是:開啟、關閉、讀取、寫入、銷燬、垃圾回收。PHP 手冊中有詳細的例子,詳細程式碼如下:
01 |
$gb_DBHOSTname = "127.0.0.1" ; |
02 |
$gb_DBname = "dbname" ; |
03 |
$gb_DBuser = "username" ; |
05 |
$gb_COOKIE_DOMAIN = '.a.com' ; |
07 |
$SESS_LIFE =
get_cfg_var( "session.gc_maxlifetime" ); |
09 |
ini_set ( 'session.use_trans_sid' ,
0); |
10 |
ini_set ( 'session.gc_maxlifetime' ,
13600); |
11 |
ini_set ( 'session.use_cookies' ,
1); |
12 |
ini_set ( 'session.cookie_path' , '/' ); |
13 |
ini_set ( "session.cookie_domain" , $gb_COOKIE_DOMAIN ); |
15 |
function sess_open( $save_path , $session_name )
{ |
16 |
global $gb_DBHOSTname , $gb_DBname , $gb_DBuser , $gb_DBpass , $SESS_DBH ; |
17 |
if (! $SESS_DBH =
mysql_pconnect( $gb_DBHOSTname , $gb_DBuser , $gb_DBpass ))
{ |
20 |
mysql_query( "SET
character_set_connection=utf8, character_set_results=utf8, character_set_client=binary" , $SESS_DBH ); |
21 |
if (!mysql_select_db( $gb_DBname , $SESS_DBH ))
{ |
27 |
function sess_close()
{ |
33 |
function sess_read( $key )
{ |
34 |
global $SESS_DBH , $SESS_LIFE ; |
36 |
$qry = "select
session_data from sessions where session_id = '$key' " ; |
37 |
$qid =
mysql_query( $qry , $SESS_DBH ); |
39 |
if (list
( $value )
= mysql_fetch_row( $qid ))
{ |
45 |
function sess_write( $key , $val )
{ |
46 |
global $SESS_DBH , $SESS_LIFE ; |
47 |
$session_last_access =
time(); |
49 |
$qry = "insert
into sessions values('$key',$session_last_access,'$value')" ; |
50 |
$qid =
mysql_query( $qry , $SESS_DBH ); |
52 |
$qry = "update
sessions set session_last_access=$session_last_access, session_data='$value' where session_id='$key' " ; |
53 |
$qid =
mysql_query( $qry , $SESS_DBH ); |
58 |
function sess_destroy( $key )
{ |
60 |
$qry = "delete
from sessions where session_id = '$key'" ; |
61 |
$qid =
mysql_query( $qry , $SESS_DBH ); |
65 |
function sess_gc( $maxlifetime )
{ |
67 |
$old =
time() - $maxlifetime ; |
68 |
$old =
mysql_real_escape_string( $old ); |
69 |
$qry = "delete
from sessions where session_last_access < " . $old ; |
70 |
$qid =
mysql_query( $qry , $SESS_DBH ); |
71 |
return mysql_affected_rows( $SESS_DBH ); |
73 |
session_module_name(); |
74 |
session_set_save_handler( "sess_open" , "sess_close" , "sess_read" , "sess_write" , "sess_destroy" , "sess_gc" ); |