阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

PHP数据库保存session会话

167次阅读
没有评论

共计 4179 个字符,预计需要花费 11 分钟才能阅读完成。

前言:

在默认的情况下,PHP 会把全部的会话数据保存在服务器上的文本文件里面,这些文件通常都是保存在服务器上的临时目录里边。

那为什么我们要把 session 会话保存在数据库中呢?

  1. 主要原因: 提高系统的安全性。在共享服务器上,在没有进行特别的设置,所有的网站站点都会使用同一个临时目录,这意味着数十个程序都在同一个位置对文件进行读写操作。不仅速度下降了,而且别人也有可能窃取到我的站点的用户数据。
  2. 把会话数据保存到数据库还可以更方便的搜索 web 站点会话的更多信息,我们可以查询活动会话的数量(同时在线的用户量),还可以对会话数据进行备份。
  3. 假如我的站点同时运行于多个服务器,那么某个用户在一个会话过程中,可能会对不同的服务器发送多个请求,但是会话数据如果保存在某一个服务器上,那么其他服务器就不能使用到这些会话数据。假如我的某一台服务器仅仅是数据库的角色,那你把会话数据全保存在数据库中,不是很方便么?

1、创建会话表

由于 session 数据是保存在服务器上面的,而在客户端中保存的是一个索引(sessionID), 这个索引对应于服务器上的某一条 session 数据。因此该表必须包含的两个字段是 id、data,还有就是会话会有过期时间,所以在这里还有个字段就是 last_accessed,这里我把该表建在 test 数据库下:

CREATE TABLE sessions(id CHAR(32) NOT NULL,
    data TEXT,
    last_accessed TIMESTAMP NOT NULL,
    PRIMARY KEY(id)
);

PHP 数据库保存 session 会话

PS:如果程序需要在会话保存大量的数据,则 data 字段可能就需要定义为 MEDIUMTEXT 或 LONGTEXT 类型了。

2、定义会话函数:

这里我们主要有两个步骤:

  1. 定义与数据库交互的函数
  2. 使 PHP 能使用这些自定义函数

在第二步中,是通过调用函数 session_set_save_handler() 来完成的,调用它需要 6 个参数,分别是 open( 启动会话)、close(关闭会话)、read(读取会话)、write(写入会话)、destroy(销毁会话)、clean(垃圾回收)。

我们新建 php 文件 sessions.inc.php,代码如下:

<?php

$sdbc = null;  // 数据库连接句柄,在后面的函数里面让它成为全局变量 

// 启动会话 
function open_session()
{
    global $sdbc;      // 使用全局的 $sdbc
    $sdbc = mysqli_connect('localhost', 'root', 'lsgogroup', 'test');     // 数据库 test
    if (!$sdbc) {return false;
    }
    return true;
}

// 关闭会话 
function close_session()
{
    global $sdbc;
    return mysqli_close($sdbc);
}

// 读取会话数据 
function read_session($sid)
{
    global $sdbc;
    $sql = sprintf("SELECT data FROM sessions WHERE id='%s'", mysqli_real_escape_string($sdbc, $sid));
    $res = mysqli_query($sdbc, $sql);
    if (mysqli_num_rows($res) == 1) {list($data) = mysqli_fetch_array($res, MYSQLI_NUM);
        return $data;
    } else {return '';
    }
}

// 写入会话数据 
function write_session($sid, $data)
{
    global $sdbc;
    $sql = sprintf("INSERT INTO sessions(id,data,last_accessed) VALUES('%s','%s','%s')", mysqli_real_escape_string($sdbc, $sid), mysqli_real_escape_string($sdbc, $data), date("Y-m-d H:i:s", time()));
    $res = mysqli_query($sdbc, $sql);
    if (!$res) {return false;
    }
    return true;
}

// 销毁会话数据 
function destroy_session($sid)
{
    global $sdbc;
    $sql = sprintf("DELETE FROM sessions WHERE id='%s'", mysqli_real_escape_string($sdbc, $sid));
    $res = mysqli_query($sdbc, $sql);
    $_SESSION = array();
    if (!mysqli_affected_rows($sdbc) == 0) {return false;
    }
    return true;
}

// 执行垃圾回收(删除旧的会话数据)
function clean_session($expire)
{
    global $sdbc;
    $sql = sprintf("DELETE FROM sessions WHERE DATE_ADD(last_accessed,INTERVAL %d SECOND)<NOW()", (int)$expire);
    $res = mysqli_query($sdbc, $sql);
    if (!$res) {return false;
    }
    return true;
}

// 告诉 PHP 使用会话处理函数 
session_set_save_handler('open_session', 'close_session', 'read_session', 'write_session', 'destroy_session', 'clean_session');

// 启动会话,该函数必须在 session_set_save_handler() 函数后调用,不然我们所定义的函数就没法起作用了。
session_start();

// 由于该文件被包含在需要使用会话的 php 文件里面,因此不会为其添加 PHP 结束标签 

PS:

  1. 处理“读取”函数外,其他函数必须返回一个布尔值,“读取”函数必须返回一个字符串。

  2. . 每次会话启动时,“打开”和“读取”函数将会立即被调用。当“读取”函数被调用的时候,可能会发生垃圾回收过程。

  3. 当脚本结束时,“写入”函数就会被调用,然后就是“关闭”函数,除非会话被销毁了,而这种情况下,“写入”函数不会被调用。但是,在“关闭”函数之后,“销毁”函数将会被调用。

  4. .session_set_save_handler() 函数参数顺序不能更改,因为它们一一对应 open、close、read、、、、

  5. 会话数据最后将会以数据序列化的方式保存在数据库中。

3、使用新会话处理程序

使用新会话处理程序只是调用 session_set_save_handler() 函数,使我们的自定义函数能够被自动调用而已。其他关于会话的操作都没有发生变化(以前怎么用现在怎么用,我们的函数会在后台自动被调用),包括在会话中存储数据,访问保存的会话数据以及销毁数据。

在这里,我们新建 sessions.php 文件,该脚本将在没有会话信息时���建一些会话数据,并显示所有的会话数据,在用户点击‘log out’(注销)时销毁会话数据。

代码:

<?php

// 引入 sessions.inc.php 文件,即上面的代码 
require('sessions.inc.php');

?>
<!doctype html>
<html lang='en'>
<head>
    <meta charset="utf-8">
    <title>DB session test</title>
</head>
<body>
<?php

// 创建会话数据 
if(empty($_SESSION)){$_SESSION['blah'] = "umlaut";
    $_SESSION['this'] = 12345;
    $_SESSION['that'] = 'blue';
    echo "<p>Session data stored</p>";
}else{echo "<p>Session data exists:<pre>".print_r($_SESSION,1)."</pre></p>";
}

if(isset($_GET['logout'])){// 销毁会话数据 
    session_destroy();
    echo "<p>session destroyed</p>";
}else{echo "<a href='https://www.linuxidc.com/Linux/2017-05/sessions.php?logout=true'>log out</a>";
}


echo "<p>session data :<pre>".print_r($_SESSION,1)."</pre></p>";

echo '</body></html>';

session_write_close();  // 下面重点解析 
?>

</body>

解析 session_write_close():

顾名思义,该函数就是先写入会话数据,然后关闭 session 会话,按道理这两步在脚本执行完后会自动执行,为什么我们还要显式调用它呢?因为这里涉及到了数据库的连接!

由于我们知道,PHP 会在脚本执行完后自动关闭数据库的所有连接,而同时会话函数会尝试向数据库写入数据并关闭连接。这样一来就会导致会话数据没法写入数据库,并且出现一大堆错误,例如 write_session()、close_session() 函数中都有用到数据库的连接。

为了避免以上说的问题,我们在脚本执行完之前调用 session_write_close() 函数,他就会调用“写入”函数和“关闭”函数,而此时数据库连接还是存在的!

PS:在使用 header() 函数重定向浏览器之前也应该调用 session_write_close() 函数,假如有数据库的操作时!

4、测试使用

在浏览器中打开 sessions.php,刷新页面,然后再看看数据库有没有添加数据。在另一个浏览器打开 sessions.php,看看数据库中有没有添加另一条数据。

本文永久更新链接地址 :http://www.linuxidc.com/Linux/2017-05/143595.htm

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计4179字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中