| 网站首页 | 文章中心 | 电子书下载 | 矢量图库 | 视频教程 | 素材下载 | 程序代码下载 | JS代码 | 论坛 | 
龙腾教程网  
常用软件类:
|杀毒安全 |联络聊天 |网络软件 |多媒体类 |系统工具 |图形图像 |系统工具 |应用软件 |行业软件
开发设计类:
|动画制作 |图像处理 |3D设计 |操作系统 |站长学院 |网络相关 |WEB设计 |数据库类 |程序开发
 
  您当前位置:您现在的位置: 龙腾软件教程网 >> 文章中心 >> WEB设计 >> PHP >> PHP技巧 >> 文章正文>>>>>> 
PHP实现多服务器session共享技巧



来源:http://imysql.cn,转载请注明作/译者和出处,并且不能用于商业用途,违者必究。 

mysql共享 

基于mysql的实现方式代码如下: 
getMessage()); 


if (!defined(’MySQLSession’)) 

    define(’MySQLSession’,    TRUE); 

class Usess 

    static  $mSessSavePath; 
    static  $mSessName; 
    static  $mSessMaxTime; 
    static  $mTblSess   = ’sessions’; 
    static  $mTblSessMap; 
    static  $mDb; 

    // {{{ 初始化构造函数 
    /** 
     * 构造函数 
     * 
     * @param string $login_user    登录用户 
     * @param int $login_type       用户类型 
     * @param string $login_sess    登录Session值 
     * @return Esession 
     */ 
    public function __construct() 
    { 
        self::$mSessMaxTime = SESS_LIFTTIME; 

        self::$mTblSessMap  = array( 
                ’sid’   => ’sid’, 
                ’data’  => ’session’, 
                ’last’  => ’flush_dt’, 
                ); 
    } 
    // }}} 

    /** {{{ sessOpen($pSavePath, $name) 
     * 
     * @param   String  $pSavePath 
     * @param   String  $pSessName 
     * 
     * @return  Bool    TRUE/FALSE 
     */ 
    public function sessOpen($pSavePath = ’’, $pSessName = ’’) 
    { 
        global $gDb; 

        self::$mDb  = $gDb; 
        self::$mSessSavePath    = $pSavePath; 
        self::$mSessName        = $pSessName; 

        self::sessGc(); 

        return TRUE; 
    } 
    // }}} 

    /** {{{ sessClose() 
     * 
     * @param   NULL 
     * 
     * @return  Bool    TRUE/FALSE 
     */ 
    public function sessClose() 
    { 
        return TRUE; 
    } 
    // }}} 

    /** {{{ sessRead($wSid) 
     * 
     * @param   String  $wSid 
     * 
     * @return  Bool    TRUE/FALSE 
     */ 
    public function sessRead($wSid = ’’) 
    { 
        global $db; 

        $wSql    = sprintf("SELECT * FROM `%s`.`%s` WHERE `%s` = ’%s’;", 
                        DB_NAME, 
                        self::$mTblSess, 
                        self::$mTblSessMap[’sid’], 
                        $wSid 
                ); 

        //这里一定要用 DB_FETCHMODE_ASSOC,否则取回的数组只能用数字做下标 
        if (!PEAR::isError($row = self::$mDb->getRow($wSql, null, DB_FETCHMODE_ASSOC))) 
        { 
            //session已经存在了 
            if (is_array($row) && 1 <= count($row)) 
            { 
                return $row[self::$mTblSessMap[’data’]]; 
            } 
            else 
            { 
                $wSql    = sprintf("INSERT INTO `%s`.`%s` VALUES (’%s’, ’’, UNIX_TIMESTAMP(NOW()));", 
                                DB_NAME, 
                                self::$mTblSess, 
                                $wSid 
                        ); 

                if (!PEAR::isError(self::$mDb->query($wSql))) 
                { 
                    return TRUE; 
                } 
            } 
        } 

        return FALSE; 
    } 
    // }}} 

    /** {{{ sessWrite($wSid, $wData) 
     * 
     * @param   String  $wSid 
     * @param   String  $wData 
     * 
     * @return  Bool    TRUE/FALSE 
     */ 
    public function sessWrite($wSid = ’’, $wData = ’’) 
    { 
        $wData  = mysql_escape_string($wData); 

        $wSql    = sprintf("UPDATE `%s`.`%s` SET `%s` = ’%s’, `%s` = UNIX_TIMESTAMP(NOW()) WHERE `%s` = ’%s’;", 
                        DB_NAME, 
                        self::$mTblSess, 
                        self::$mTblSessMap[’data’], 
                        $wData, 
                        self::$mTblSessMap[’last’], 
                        self::$mTblSessMap[’sid’], 
                        $wSid 
                ); 

        if (!PEAR::isError(self::$mDb->query($wSql))) 
        { 
            return TRUE; 
        } 

        return FALSE; 
    } 
    // }}} 

    /** {{{ sessDestroy($wSid) 
     * 
     * @param   String  $wSid 
     * 
     * @return  Bool    TRUE/FALSE 
     */ 
    public function sessDestroy($wSid = ’’) 
    { 
        $wSql    = sprintf("DELETE FROM `%s`.`%s` WHERE `%s` = ’%s’;", 
                        DB_NAME, 
                        self::$mTblSess, 
                        $wSid 
                ); 

        if (!PEAR::isError(self::$mDb->query($wSql))) 
        { 
            return TRUE; 
        } 

        return FALSE; 
    } 
    // }}} 

    /** {{{ sessGc() 
     * 
     * @param   NULL 
     * 
     * @return  Bool    TRUE/FALSE 
     */ 
    public function sessGc() 
    { 
        global $db; 

        //计算出过期时间 
        $last   = time() - self::$mSessMaxTime; 

        $wSql    = sprintf("DELETE FROM `%s`.`%s` WHERE `%s` < $last;", DB_NAME, self::$mTblSess, self::$mTblSessMap[’last’]); 

        if (!PEAR::isError(self::$mDb->query($wSql))) 
        { 
            return TRUE; 
        } 

        return FALSE; 
    } 
    // }}} 

    /** {{{ initSess() 
     * 
     * @param   NULL 
     * 
     * @return  Bool    TRUE/FALSE 
     */ 
    public function initSess() 
    { 
        $domain = ’’; 

        //不使用 GET/POST 变量方式 
        ini_set(’session.use_trans_sid’,    0); 

        //设置垃圾回收最大生存时间 
        ini_set(’session.gc_maxlifetime’,   SESS_LIFTTIME); 

        //使用 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(’Usess’, ’sessOpen’),   //对应于静态方法 My_Sess::open(),下同。 
                array(’Usess’, ’sessClose’), 
                array(’Usess’, ’sessRead’), 
                array(’Usess’, ’sessWrite’), 
                array(’Usess’, ’sessDestroy’), 
                array(’Usess’, ’sessGc’) 
                ); 
        session_start(); 

        return TRUE; 
    } 
    // }}} 

}//end class 

}//end define 

$sess   = new Usess; 
$sess->initSess(); 
?> 

以上代码在 php5.20 中测试通过。

NFS共享


前言,Nio大侠提出了session多服务器共享的问题,原文请见PHP 实现多服务器共享 SESSION 数据。其中,有一种方法就是利用NFS来共享session,如果session量比较大并且所有的session文件都在同一个子目录下的话,那么可能会由此带来很严重的负载问题,甚至导致网站无法使用。本文就是对这个方案做一下详细的解说。
首先,修改 php.ini的 session.save_path 选项,大致如下:
session.save_path = "2;/tmp/php_sess"
意为把session存放在 "/tmp/php_sess" 目录下,并且分成 2 级子目录,每级子目录又分别有 16 个子目录。
接下来,假设php的主目录为 /usr/local/server/php/,则新建一个文件 /usr/local/server/php/include/php/ext/session/mod_files.sh,其内容如下:
#! /bin/sh
# NAME
#      mod_files.sh  - Update of the php-source/ext/session/mod_files.sh
#
# SYNOPSIS
#      mod_files.sh basedir depth [numberofsubdirs]
#
# DESCRIPTION
#      this script creates the directories tree used by php to store the session files
#      (see php.ini - ’session.save_path’ option)
#
#      Example: if you want php to store the session files in a directory tree
#      of 3 levels of depth containing 32 directories in each directory,
#      first, put the setting bellow in the php.ini file:
#
#      session.save_path = "3;/tmp/session"
#
#      Now create the basedir directory: ’mkdir /tmp/session’
#
#      Then, call this scrip with the following arguments:
#
#      ./mod_files.sh ./mod_files.sh /tmp/session 3 32
if test "$2" = ""; then
       echo "usage: $0 basedir depth [numberofsubdirs]"
       echo "numberofsubdirs: if unset, defaults to 16. if 32, 32 subdirs, if 64, 64 subdirs."
       exit 1
fi
if test "$2" = "0"; then
       exit 0
fi
hash_chars="0 1 2 3 4 5 6 7 8 9 a b c d e f"
if [ ! -z $3 ] ; then
if test "$3" -a "$3" -eq "32"; then
  hash_chars="$hash_chars g h i j k l m n o p q r s t u v"
  if test "$3" -eq "64"; then
   hash_chars="$hash_chars w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z - ,"
  fi
fi
fi
for i in $hash_chars; do
       newpath="$1/$i"
       mkdir $newpath || exit 1
       sh $0 $newpath `expr $2 - 1` $3
done
设置为可执行之后,运行以下命令来创建哈希目录:
shell>#cd /usr/local/server/php/include/php/ext/session/
shell>#./mod_files.sh /tmp/php_sess 2 16
现在,就开始设置 NFS 共享了。假定有3台主机,ip分别为192.168.0.1(主机名svr1)、192.168.0.2(主机名svr2)、192.168.0.3(主机名svr3),现在让192.168.0.1来提供NFS共享服务,配置 /etc/exports,加入如下内容:
/tmp/php_sess/ svr*(rw,no_root_squash)
然后重启 nfs 服务,即可对另外两台主机提供NFS共享了。
在 svr2、svr3 上执行以下命令来挂在NFS:
shell>#mkdir /tmp/php_sess
shell>#mount svr1:/tmp/php_sess /tmp/php_sess
用NFS来存储session的缺点是,session过期后不能自动清除,必须自己设定回收机制,我们可以利用crontab来定期回收,用用以下shell命令即可:
find /tmp/php_sess -mmin +30 | xargs rm -fr
意思是,删除30分钟以前的session文件,具体的时间请大家自己重新设置吧。
最后,在这两个主机上对 php.ini 增加/修改上面提到的内容,然后重启apache即可。

 
memcache共享

  本文是 PHP实现多服务器session共享之NFS共享的延续,不过这次,我采用memcache来存储session了,memcache的安装请看这里: 搭建高效、可靠、稳定的WEB服务器 -- 二、) 安装MySQL、memcache。
接下来,再自定义一套session处理机制,关于session的实现方法我就不再多讲,直接贴程序了。
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
//===========================================
// 程序:   Memcache-Based Session Class
// 功能:   基于Memcache存储的 Session 功能类
// 作者:    yejr
// 网站:    http://imysql.cn
// 时间:    2007-01-05
//===========================================
/**
 * 文件:    MemcacheSession.inc.php
 * 类名:    MemcacheSession Class
 * 功能:    自主实现基于Memcache存储的 Session 功能
 * 描述:    这个类就是实现Session的功能,基本上是通过
 *          设置客户端的Cookie来保存SessionID,
 *          然后把用户的数据保存在服务器端,最后通过
 *          Cookie中的Session Id来确定一个数据是否是用户的,
 *          然后进行相应的数据操作
 *
 *          本方式适合Memcache内存方式存储Session数据的方式,
 *          同时如果构建分布式的Memcache服务器,
 *          能够保存相当多缓存数据,并且适合用户量比较多并发比较大的情况
 *
 * 注意: 本类必须要求PHP安装了Memcache扩展或者必须有Memcache的PHP API
 *       获取Memcache扩展请访问: http://pecl.php.net
 */
//设定 SESSION 有效时间,单位是 秒
define(’SESS_LIFTTIME’, 3600);
//定义memcache配置信息
define(’MEMCACHE_HOST’, ’localhost’);
define(’MEMCACHE_PORT’, ’10000’);
if (!defined(’MemcacheSession’))
{
    define(’MemcacheSession’,    TRUE);
class MemacheSession
{
    // {{{ 类成员属性定义
    static  $mSessSavePath;
    static  $mSessName;
    static  $mMemcacheObj;
    // }}}
    // {{{ 初始化构造函数
    /**
     * 构造函数
     *
     * @param string $login_user    登录用户
     * @param int $login_type       用户类型
     * @param string $login_sess    登录Session值
     * @return Esession
     */
    public function __construct()
    {
        //我的memcache是以php模块的方式编译进去的,可以直接调用
        //如果没有,就请自己包含 Memcache-client.php 文件
        if (!class_exists(’Memcache’) || !function_exists(’memcache_connect’))
        {
            die(’Fatal Error:Can not load Memcache extension!’);
        }
        if (!empty(self::$mMemcacheObj) && is_object(self::$mMemcacheObj))
        {
            return false;
        }
        self::$mMemcacheObj = new Memcache;
        if (!self::$mMemcacheObj->connect(MEMCACHE_HOST , MEMCACHE_PORT))
        {
            die(’Fatal Error: Can not connect to memcache host ’. MEMCACHE_HOST .’:’. MEMCACHE_PORT);
        }
        return TRUE;
    }
    // }}}
    /** {{{ sessOpen($pSavePath, $name)
     *
     * @param   String  $pSavePath
     * @param   String  $pSessName
     *
     * @return  Bool    TRUE/FALSE
     */
    public function sessOpen($pSavePath = ’’, $pSessName = ’’)
    {
        self::$mSessSavePath    = $pSavePath;
        self::$mSessName        = $pSessName;
        return TRUE;
    }
    // }}}
    /** {{{ sessClose()
     *
     * @param   NULL
     *
     * @return  Bool    TRUE/FALSE
     */
    public function sessClose()
    {
        return TRUE;
    }
    // }}}
    /** {{{ sessRead($wSessId)
     *
     * @param   String  $wSessId
     *
     * @return  Bool    TRUE/FALSE
     */
    public function sessRead($wSessId = ’’)
    {
        $wData = self::$mMemcacheObj->get($wSessId);
        //先读数据,如果没有,就初始化一个
        if (!empty($wData))
        {
            return $wData;
        }
        else
        {
            //初始化一条空记录
            $ret = self::$mMemcacheObj->set($wSessId, ’’, 0, SESS_LIFTTIME);
            if (TRUE != $ret)
            {
                die("Fatal Error: Session ID $wSessId init failed!");
                return FALSE;
            }
            return TRUE;
        }
    }
    // }}}
    /** {{{ sessWrite($wSessId, $wData)
     *
     * @param   String  $wSessId
     * @param   String  $wData
     *
     * @return  Bool    TRUE/FALSE
     */
    public function sessWrite($wSessId = ’’, $wData = ’’)
    {
        $ret = self::$mMemcacheObj->replace($wSessId, $wData, 0, SESS_LIFTTIME);
        if (TRUE != $ret)
        {
            die("Fatal Error: SessionID $wSessId Save data failed!");
            return FALSE;
        }
        return TRUE;
    }
    // }}}
    /** {{{ sessDestroy($wSessId)
     *
     * @param   String  $wSessId
     *
     * @return  Bool    TRUE/FALSE
     */
    public function sessDestroy($wSessId = ’’)
    {
        self::sessWrite($wSessId);
        return FALSE;
    }
    // }}}
    /** {{{ sessGc()
     *
     * @param   NULL
     *
     * @return  Bool    TRUE/FALSE
     */
    public function sessGc()
    {
        //无需额外回收,memcache有自己的过期回收机制
        return TRUE;
    }
    // }}}
    /** {{{ initSess()
     *
     * @param   NULL
     *
     * @return  Bool    TRUE/FALSE
     */
    public function initSess()
    {
        $domain = ’.imysql.cn’;
        //不使用 GET/POST 变量方式
        ini_set(’session.use_trans_sid’,    0);
        //设置垃圾回收最大生存时间
        ini_set(’session.gc_maxlifetime’,   SESS_LIFTTIME);
        //使用 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(’MemacheSession’, ’sessOpen’),   //对应于静态方法 My_Sess::open(),下同。
                array(’MemacheSession’, ’sessClose’),
                array(’MemacheSession’, ’sessRead’),
                array(’MemacheSession’, ’sessWrite’),
                array(’MemacheSession’, ’sessDestroy’),
                array(’MemacheSession’, ’sessGc’)
                );
        session_start();
        return TRUE;
    }
    // }}}
}//end class
}//end define
$memSess    = new MemacheSession;
$memSess->initSess();
?>
  然后,在项目程序的头文件中直接包含 MemacheSession.inc.php 即可,并且以前的程序不用做任何改动。
  特别感谢:黑夜路人 的 实现基于Memcache存储的Session类。
备注:memcache PECL 未来版本中,可以直接设置 php.ini 来这定自己的 session.save_handler,大致如下:
session.save_handler = memcache
session.save_path = "tcp://host:port?persistent=1&weight=2&timeout=2&retry_interval=15,tcp://host2:port2"


上一篇:
  • 上一篇文章:
  • 下一篇
  • 下一篇文章: 没有了
  • 收藏此文到百度搜藏 百度搜藏| 新浪VIvi| 365key| Younote| 博采中心| 你好BLOG| 亿友网摘| 和讯网摘|
    相关文章    
    php 制作无限级分类方法
    php生成WML页面方法详解
    php.ini register_globals配置详解
    PHP5基础教程-类与对象之抽象类(Class Abst
    PHP5基础教程-类与对象之对象接口(Object I
    PHP5基础教程-类与对象之对象克隆(Object c
    PHP5基础教程-类与对象之类常量(Class Cons
    PHP5基础教程-类与对象之模式(Patterns)
    PHP5基础教程-类与对象之重载(Overloading)
    PHP生成HTML静态页面实现方法详解
     
     
     
    最新文章
    普通文章 PHP实现多服务器session共享技巧最新文章
    普通文章 黑客如何利用文件漏洞进行网站入最新文章
    普通文章 江民KV2008 强大安全防御能力最新文章
    普通文章 十招确保迅雷安全高速下载最新文章
    普通文章 win Vista浏览网站该页无法显示解最新文章
    普通文章 Photoshop绘制齐白石大师虾图最新文章
    普通文章 无线网络攻击工具进攻及防范技巧最新文章
    普通文章 Win Vista的防火墙使用注意事项最新文章
    普通文章 撤消Windows XP自带的无用功能最新文章
    普通文章 Windows Vista系统22类问题解决方最新文章
     
    热门文章
    推荐文章 Photoshop绘制逼真绚丽的金鱼
     
     
    设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 

    版权所有2006-2008 龙腾教程网