PHP session_set_save_handler():将Session存储到数据库

通过前面的学习我们知道,Session 是存储在服务器的临时目录中的,当站点的登陆人数较多时,也就意味着服务器中会存储大量的 Session 文件,很占服务器资源。而服务器想要在这众多的 Session 中查找指定的 Session_id 也并不是什么轻松的事情。出现这种情况时该怎么办呢?这时我们可以选择将 Session 存储到数据库中,以减轻服务器的压力。

PHP 中的 session_set_save_handler() 函数可以设置自定义的会话存储函数,通过这些自定义函数来操作 Session,从而将 Session 信息存储到数据库中。session_set_save_handler() 函数有两种形式,其语法格式如下:

session_set_save_handler(
    callable $open,
    callable $close,
    callable $read,
    callable $write,
    callable $destroy,
    callable $gc
    [, callable $create_sid
    [, callable $validate_sid
    [, callable $update_timestamp]]]
)

参数说明如下:

  • $open(string $savePath, string $sessionName):$open 回调函数类似于类的构造函数,在会话打开的时候会被自动调用。这是自动开始会话或者通过调用 session_start() 手动开始会话之后第一个被调用的回调函数。此回调函数操作成功会返回 TRUE,反之返回 FALSE;
  • $close():$close 回调函数类似于类的析构函数。 在 $write 回调函数调用之后调用。当调用 session_write_close() 函数之后,也会调用 $close 回调函数。此回调函数操作成功返回 TRUE,反之返回 FALSE;
  • $read(string $sessionId):如果会话中有数据的话,$read 回调函数会返回 $sessionId 所对应的 Session 数据;如果会话中没有数据,那么 $read 回调函数会返回空字符串。在会话自动开始或者通过调用 session_start() 函数手动开始会话之后,PHP 会在内部调用 $read 回调函数来获取会话数据。在调用 $read 之前,PHP 会调用 $open 回调函数;
  • $write(string $sessionId, string $data):在创建或修改 Session 信息时会调用 $write 回调函数。此回调函数接收当前会话的 ID 以及 $_SESSION 中数据序列化之后的字符串作为参数。序列化会话数据是由 PHP 根据 session.serialize_handler 设定值来自动完成;
  • $destroy($sessionId):当调用 session_destroy() 函数或者调用 session_regenerate_id() 函数并且设置 $destroy 参数为 TRUE 时,会调用此回调函数。此回调函数操作成功返回 TRUE,反之返回 FALSE;
  • $gc($lifetime):为了清理会话中的旧数据,PHP 会不时的调用垃圾收集回调函数。调用周期由 session.gc_probability 和 session.gc_divisor 参数控制。传入到此回调函数的 $lifetime 参数由 session.gc_maxlifetime 设置。此回调函数操作成功返回 TRUE,反之返回 FALSE;
  • $create_sid():可选参数,当需要新的会话 ID 时被调用的回调函数。回调函数被调用时不用传入参数,其返回值应该是一个字符串格式的、有效的会话 ID;
  • $validate_sid():可选参数,用来验证会话 ID;
  • $update_timestamp():可选参数,用来修改时间戳。

除了上面这种形式,session_set_save_handler() 函数还有另外一种形式(自 PHP5.4 及以上版本可用),如下所示:

session_set_save_handler(object $sessionhandler [, bool $register_shutdown = TRUE])

参数说明如下:

  • $sessionhandler:实现了 SessionHandlerInterface、SessionIdInterface 或 SessionUpdateTimestampHandlerInterface 接口的对象,例如 SessionHandler;
  • $register_shutdown:可选参数,将函数 session_write_close() 注册为 register_shutdown_function() 函数。

一般函数的参数都是直接使用变量,但是 session_set_save_handler() 函数中却是以多个函数的名称作为参数。下面将通过示例的形式对这几个参数(函数)分别进行讲解。

1) 封装 sess_open() 函数,用来连接数据库,示例代码如下:

<?php
    // 连接数据库
    function sess_open($savePath, $sessionName){
        global $link;
        $link = mysqli_connect('localhost', 'root', 'root') or die('数据库连接失败!');
        mysqli_select_db($link, 'testdb') or die('未找到该数据库!');
        return true;
    }
?>

函数中并没有用到 $save_path 和 $session_name 这两个参数,可以将它们去掉,但是建议读者保留这两个参数,因为一般使用时都是存在这两个变量的,应该养成一个好的习惯。

2) 封装 sess_close() 函数,用来关闭数据库连接,示例代码如下:

<?php
    // 关闭数据库连接
    function sess_close(){
        global $link;
        mysqli_close($link);
        return true;
    }
?>

在这个函数中不需要任何参数,所以不论是将 Session 存储到数据库还是文件中,都只需返回 true 即可。但是这里是将 Session 存储到数据库中,所以最好还是在这里将数据库关闭,以避免出现其它问题。

3) 封装 sess_read() 函数,根据参数 $sessionId 来获取 Session 的信息,示例代码如下:

<?php
    // 读取 Session 内容
    function sess_read($sessionId){
        global $link;
        $time = time();
        $sql = "SELECT data FROM session WHERE id = '$sessionId' AND lapse_time > '$time'";
        $result = mysqli_query($link, $sql);
        $row = mysqli_fetch_array($result, MYSQLI_ASSOC);
        if($row){
            return $row['data'];
        }else{
            return false;
        }
    }
?>

4) 封装 sess_write() 函数,用来将 Session 内容写入数据库,示例代码如下:

<?php
    // 写入 Session
    function sess_write($sessionId, $data){
        global $link;
        $lapse_time = time()+(60*60);
        $sql = "SELECT data FROM session WHERE id = '$sessionId'";
        $result = mysqli_query($link, $sql);
        if(mysqli_num_rows($result) == 0){
            $ins_sql = "INSERT INTO session VALUES('$sessionId', '$data', '$lapse_time')";
            $res = mysqli_query($link, $ins_sql);
        }else{
            $up_sql = "UPDATE session SET data = '$data', lapse_time = '$lapse_time' WHERE id = '$sessionId'";
            $res = mysqli_query($link, $up_sql);
        }
        return $res;
    }
?>

5) 封装 sess_destroy() 函数,用来删除指定的 Session 数据,示例代码如下:

<?php
    // 删除 Session
    function sess_destroy($sessionId){
        global $link;
        $sql = "DELETE FROM session WHERE id = '$sessionId'";
        return mysqli_query($link, $sql);
    }
?>

6) 封装 sess_gc() 函数,用来清理失效的 Session,示例代码如下:

<?php
    // 清理失效的 Session
    function sess_gc(){
        global $link;
        $time = time();
        $sql = "DELETE FROM session WHERE lapse_time < '$time'";
        $res = mysqli_query($link, $sql);
        return $res;
    }
?>

以上定义的 6 个函数便是 session_set_save_handler() 函数 6 个必选参数,调用 session_set_save_handler() 函数即可实现将 Session 存储到数据库中,示例代码如下:

<?php
    ini_set("session.save_handler", "user");
    session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');
    session_start();
    $_SESSION['user'] = 'admin';
?>

运行上面的代码即可将 user = 'admin' 的 Session 信息写入到数据库,如下所示:

mysql> SELECT * FROM session;
+——————————–+——————-+————–+
| id                                             | data                     | lapse_time    |
+——————————–+——————-+————–+
| c91mct86sfs3gs9lpke225b8ir | user|s:5:"admin";  | 1595587392 |
+——————————–+——————-+————–+
1 row in set (0.00 sec)

上面代码中 ini_set("session.save_handler", "user"); 用来临时修改 PHP 的配置信息,与直接将 php.ini 配置文件中 session.save_handler 的值改为 user 效果相同。另外需要注意的是,以上代码仅在 PHP7.0 版本中成功运行,其它版本暂未测试通过。

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/23998.html

(0)
上一篇 2021年7月20日
下一篇 2021年7月20日

相关推荐

发表回复

登录后才能评论