在Mysql数据库中存储Session

Posted by 撒得一地 on 2015年12月13日 in PHP笔记

描述

你可能会知道,Sessions是动态网站和网络应用程序中重要的组成部分。当我们创建这样类型的网站时,我们一定会被要求在某些时候增加Sessions处理机制。

我们经常将session参数保存在服务端特殊的文件中,在一个指定的位置,比如:session.save_path。你可以调用phpinfo()函数来找到这个文件的位置。不幸的是,如果你的网站放置在一个共享的服务器上,你不能排除其他用户(也连接在你的服务器)偷偷查看这些文件的可能性。

所以,在接下来我们重点关注PHP Sessions:为什么你需要它们,它们应该如何被存储,还有我们会给你一个完整的PHP类来处理数据库内的Sessions。

什么是Sessions和它们如何工作

在我们实现数据库存储之前,重要的是要先了解什么是Sessions和它们如何工作。

默认情况下,在互联网上的每一个请求,都是“匿名”的,这意味着它和之前的请求是没有任何联系的。所以,当你登录到你的网站时,脚本文件必须“记住”你已经登录(你当前的“状态”)了,以便在后续的请求应该将你的账户信息联系起来。为了维持这种状态,我们需要使用Sessions机制。

用简单的话来说,Session是一个独一的标识符,记录在服务器或你的浏览器中。使用此记录信息,服务器在你访问了多个页面后还能够维持登陆状态。Sessinos通过分配给每个访问者一个唯一标识符来进行工作。当你把数据保存在Session(例如,当你执行登录时),Session会将此信息存储在服务器上某个文件中。那唯一标识符也被作为一个coockie存储在你的电脑中。

所以,当你访问一个新页面时,会从cookie中找到session id,并进一步从存储文件中找到对应的session数据。如果数据被找到,那么它就会加载这些Session变量,在你所访问的应用程序中就可以使用它。

Sessions(会话)安全吗?

在一定程度上,Sessions像许多其它涉及到互联网相关事情一样,是安全的。但一个问题你可能遇到的是,当你使用共享的服务端托管计划时,如果你服务器没有正确配置,那么其它人可能会访问到你的Sessions文件。

有许多方法可以阻止这类问题发生,其中最流行的方法之一就是把Sessions存储在数据库中,而不是文件中。令人欣喜的是,将Sessions存储在数据库中是十分简单的,而且对你的用户不会有任何负面的影响,他们甚至不知道你是如何存储Sessions的。

将Sessions存储在数据库中对你来说也是十分有益的,如果你需要扩大你的应用到多台服务器中。

如何在数据库中设置Sessions(会话)?

在你将Sessions存储在数据库中时,首先你要先建立一张表。下面的例子展示了这张表的字段及参数(你可以根据你不同的查询操作进行修改)。
例子1 创建Sessions表:

CREATE TABLE `sessions` (
  `session_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL,

  `expires_at` int(11) NOT NULL,

  `session_data` text COLLATE utf8_unicode_ci NOT NULL,

  UNIQUE KEY `session_id` (`session_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

现在,你有一张表可以用来存储Sessions,接下来你应该学习如何使用它。好消息是,PHP提供了一个函数,通过指定指定这个函数名,并重写默认的session引擎,可以实现所需的任务。

这个函数被称为session_set_save_handler(),它需要六个参数,其中每个参数又是一个相应函数。这些函数负责以下任务:

Opening the session data store 打开session数据存储

Closing the session data store 关闭session数据存储

Reading session data 读session数据

Writing session data 写session数据

Destroying all session data 销毁全部session数据

Cleaning out old session data 清空旧session数据

让我们假设这个函数这样被调用(后面我们会根据需要去定制它):
例子2 调用session_set_save_handler()函数

session_set_save_handler(
    "openSession",
    "closeSession",
    "readSession",
    "writeSession",
    "destroySession",
    "gcSession"
); 

创建Session类

现在我们将创建一个类来处理我们的Sessions。这意味着我们可以简单地实例化一个类的新对象在我们的代码中的任何地方。它也有助于保持我们的所有Session方法在同一个地方。

为了将session数据存储在数据库中,我们需要有一个与数据库进行交互的方式。可以说你有一些数据库类,如扩展PDO一样。你还可以使用自己的数据库抽象层,这应该很容易地切换到它。

所以…我们需要做的第一件事是创建一个类,该类具有数据库对象的属性。

实例3:创建Session类

/**
 * Session provides session-level data management
 * by using database as session data storage
 */
class Session {
    /** @var Database */
    private $_db;
}

类的构造函数(Constructor)

现在我们要实例化Session类,我们需要设置一些事情来让它工作。在实例化类该类时,构造函数的方法是自动运行,你应该明白这是一个定义对象初始化属性的好地方。

首先我们必须实例化一个数据库副本类并将其赋值给_db属性。然后我们需要重写Session处理程序-这样我们告诉PHP我们想用自己的方法处理Session,最后我们需要启动Session。

实例4:

/**
 * Class default constructor
 */
function __construct()
{
    // instance of new Database object
    $this->_db = CDatabase::init();
    
    // set handler to overide SESSION
    @session_set_save_handler(
        array($this, "openSession"),
        array($this, "closeSession"),
        array($this, "readSession"),
        array($this, "writeSession"),
        array($this, "destroySession"),
        array($this, "gcSession")
    );   

    // start the session
    session_start();
}

打开Session方法

现在我们需要创建一个简单的检查,看看是否有一个可供使用的数据库连接。
例子5:Method "openSession".

/**
 * Session open handler
 * @return boolean
 */
public function openSession(
    // if database connection exists
    if($this->_db){
        return true;
    }
    return false;
}

关闭Session方法

这种方法类似于openSession方法,它只是检查是否连接已经关闭。
实例6. Method "closeSession".

/**
 * Session close handler
 * Do not call this method directly
 * @return boolean
 */
public function closeSession()
{
    // if database connection is closed
    if($this->_db->close()){
        @session_write_close();
        return true;
    }
    return false;    
}

读Session方法

这需要会话(Session)标识和数据库查询。此方法是我们如何将数据绑定到查询的示例。通过绑定id到类中的ID占位符,而不是使用变量,我们使用PDO的方法防止SQL注入。
实例7. Method "writeSession".

/**
 * Session read handler
 * Do not call this method directly
 * @param string $id
 * @return string
 */
public function readSession($id)
{
    $result = $this->_db->select(
        "SELECT session_data FROM sessions WHERE session_id = :session_id",
        array(":session_id"=>$id)
    );
    return isset($result[0]) ? $result[0] : "";
}

写Session方法

要更新会话(Session),它需要写方法。然后写方法需要会话(Session)标识和会话(Session)数据。
访问令牌是当前时间戳,所以你可以插入或更新你的会话(Session)数据。如果查询被正确执行,我们返回真,否则返回假。
例子8. Method "writeSession".

/**
 * Session write handler
 * Do not call this method directly
 * @param string $id
 * @param string $data
 * @return boolean
 */
public function writeSession($id, $data)
{        
    $result = $this->_db->select(
        "SELECT session_data FROM sessions WHERE session_id = :session_id",
        array(":session_id"=>$id)
    );
    if(isset($result[0])){
        $result = $this->_db->update(
            "sessions",
            array(
                "expires_at"=>time()+$this->getTimeout(),
                "session_data"=>$data
            ),
            "session_id = :session_id",
            array(":session_id"=>$id)
        );
    }else{
        $result = $this->_db->insert(
            "sessions",
            array(
                "session_id"=>$id,
                "expires_at"=>time()+$this->getTimeout(),
                "session_data"=>$data
            )
        );
    }  
    return true;
}

销毁Session方法

destroy方法是基于它的id,来删除Session数据。这个方法将被调用,当你使用Session销毁全局函数时,如:session_destroy();
实例 9. Method "destroySession".

/**
* Session destroy handler
* Do not call this method directly
* @param string $id
* @return boolean
*/
public function destroySession($id)
{
    return $this->_db->delete(
        "sessions", "session_id = :session_id", array(":session_id"=>$id)
    );        
}

gcSession方法-垃圾回收

gcSession函数将由服务器运行,来清理数据库中过期的会话(Session)。这个函数是根据几个设置运行在服务器上。该方法传入一个$ maxLifetime变量。该变量设定了一个最大的秒数,来使PHP识别到一个会话(Session)是否已经过期。要记住,这是一个设置在服务器上可以进行编辑的变量。它可能在php.ini文件中找到。
实例10. Method "gcSession".

/**
 * Session garbage collection handler
 * Do not call this method directl
 * @param int $maxLifetime
 * @return boolean
 */
public function gcSession($maxLifetime)
{
    return $this->_db->delete(
        "sessions", "expires_at < :expires_at", array(":expires_at"=>time())
    );
}

总结
在本文中,我们已经讨论了一个比较好并且简单的方法来启动和运行存储在数据库中的PHP会话(Session)。在PHP的MVC框架,我们已经使用此代码在CDbHttpSession.php。希望本文很好的介绍了相应的概念,你可以下载下面的类的代码完整示例:

http://pan.baidu.com/s/1beuCma

英文原文地址:

http://www.codeproject.com/Articles/798978/Session-Storage-in-a-MySQL-Database

译文地址:http://coderschool.cn/1282.html

转载请注明译文和英文原文地址

标签:

上一篇:

下一篇:

相关推荐

网站地图|XML地图

Copyright © 2015-2024 技术拉近你我! All rights reserved.
闽ICP备15015576号-1 版权所有©psz.