PHP实现多服务器共享SESSION数据

来源:互联网  作者:肖理达
摘要:PHP 实现多服务器共享 SESSION 数据一、问题起源稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网站,用户系统是统一的,即一套用户名、密码在整个网站的各个模块中都是可以登……

四、代码实现

首先创建数据表,MySQL 的 SQL 语句如下:

CREATE TABLE `sess` (
   `sesskey` varchar(32) NOT NULL default '',
    `expiry` bigint(20) NOT NULL default '0',
    `data` longtext NOT NULL,
    PRIMARY KEY  (`sesskey`),
    KEY `expiry` (`expiry`)
  ) TYPE=MyISAM
sesskey 为 SESSION ID,expiry 为 SESSION 过期时间,data 用于保存 SESSION 数据。

默认情况下 SESSION 数据是以文件方式保存,想要使用数据库方式保存,就必须重新定义 SESSION 各个操作的处理函数。PHP 提供了session_set_save_handle() 函数,可以用此函数自定义 SESSION 的处理过程,当然首先要先将 session.save_handler 改成 user,可在 PHP 中进行设置:

<?php
session_module_name('user');
?>

接下来着重讲一下 session_set_save_handle() 函数,此函数有六个参数:
session_set_save_handler ( string open, string close, string read, string write, string destroy, string gc )
各个参数为各项操作的函数名,这些操作依次是:打开、关闭、读取、写入、销毁、垃圾回收。PHP 手册中有详细的例子,在这里我们使用 OO 的方式来实现这些操作,详细代码如下:

<?php
define('MY_SESS_TIME', 3600);   //SESSION 生存时长
//类定义
class My_Sess
{
  function 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',    '/');
      //多主机共享保存 SESSION ID 的 COOKIE
      ini_set('session.cookie_domain',  $domain);

//将 session.save_handler 设置为 user,而不是默认的 files
      session_module_name('user');
      //定义 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')
      );
  }   //end function

function open($save_path, $session_name) {
      return true;
  }   //end function

function close() {
      global $MY_SESS_CONN;

if ($MY_SESS_CONN) {  //关闭数据库连接
          $MY_SESS_CONN->Close();
      }
      return true;
  }   //end function

function read($sesskey) {
      global $MY_SESS_CONN;

$sql = 'SELECT data FROM sess WHERE sesskey=' . $MY_SESS_CONN->qstr($sesskey) . ' AND expiry>=' . time();
      $rs =& $MY_SESS_CONN->Execute($sql);
      if ($rs) {
          if ($rs->EOF) {
              return '';
          } else {  //读取到对应于 SESSION ID 的 SESSION 数据
              $v = $rs->fields[0];
              $rs->Close();
              return $v;
          }   //end if
      }   //end if
      return '';
  }   //end function

function write($sesskey, $data) {
      global $MY_SESS_CONN;
      
      $qkey = $MY_SESS_CONN->qstr($sesskey);
      $expiry = time() + My_SESS_TIME;  //设置过期时间
      
      //写入 SESSION
      $arr = array(
          'sesskey' => $qkey,
          'expiry'  => $expiry,
          'data'  => $data);
      $MY_SESS_CONN->Replace('sess', $arr, 'sesskey', $autoQuote = true);
      return true;
  }   //end function

function destroy($sesskey) {
      global $MY_SESS_CONN;

$sql = 'DELETE FROM sess WHERE sesskey=' . $MY_SESS_CONN->qstr($sesskey);
      $rs =& $MY_SESS_CONN->Execute($sql);
      return true;
  }   //end function

function gc($maxlifetime = null) {
      global $MY_SESS_CONN;

$sql = 'DELETE FROM sess WHERE expiry<' . time();
      $MY_SESS_CONN->Execute($sql);
      //由于经常性的对表 sess 做删除操作,容易产生碎片,
      //所以在垃圾回收中对该表进行优化操作。
      $sql = 'OPTIMIZE TABLE sess';
      $MY_SESS_CONN->Execute($sql);
      return true;
  }   //end function
}   ///:~

//使用 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();
?>

五、遗留问题

如果网站的访问量很大的话,SESSION 的读写会频繁地对数据库进行操作,这样效率就会明显降低。考虑到 SESSION 数据一般不会很大,可以尝试用 C/Java 写个多线程的程序,用 HASH 表保存 SESSION 数据,并通过 socket 通信进行数据读写,这样 SESSION 就保存在内存中,读写速度应该会快很多。另外还可以通过负载均衡来分担服务器负载。不过这些都只是我自己的一些想法和假设,并没有实践过

【相关文章】好搜一下
SQLite in PHP

SQLite in PHP

(1)SQLite介绍SQLite第一个Alpha版本诞生于2000年5月. 至…