稍微大一点的网站,通常都会有不只一个服务器,每个服务器运行着不同的功能模块或者不同的子系统,他们使用不同的二级域名,比如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" ; //主机的名称或是IP地址
|
02 |
$gb_DBname = "dbname" ; //数据库名称
|
03 |
$gb_DBuser = "username" ; //数据库用户名称
|
04 |
$gb_DBpass = "pwd" ; //数据库密码
|
05 |
$gb_COOKIE_DOMAIN = '.a.com' ;
|
07 |
$SESS_LIFE = get_cfg_var( "session.gc_maxlifetime" ); //得到session的最大有效期。
|
08 |
session_id(); //不使用 GET/POST 变量方式
|
09 |
ini_set ( 'session.use_trans_sid' , 0); //设置垃圾回收最大生存时间
|
10 |
ini_set ( 'session.gc_maxlifetime' , 13600); //使用 COOKIE 保存 SESSION ID 的方式
|
11 |
ini_set ( 'session.use_cookies' , 1);
|
12 |
ini_set ( 'session.cookie_path' , '/' ); //多主机共享保存 SESSION ID 的 COOKIE
|
13 |
ini_set ( "session.cookie_domain" , $gb_COOKIE_DOMAIN );
|
14 |
//将 session.save_handler 设置为 user,而不是默认的 files session_module_name('user'); |
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 ;
|
35 |
// var_dump($SESS_DBH); |
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" );
|