PHP Conference Japan 2024

SessionHandlerInterface 类

(PHP 5 >= 5.4.0, PHP 7, PHP 8)

简介

SessionHandlerInterface 是一个接口,它定义了创建自定义会话处理程序的最小原型。为了使用其 OOP 调用将自定义会话处理程序传递给 session_set_save_handler(),该类可以实现此接口。

请注意,此类的回调方法旨在由 PHP 内部调用,并且不应从用户空间代码中调用。

接口概要

interface SessionHandlerInterface {
/* 方法 */
public close(): bool
public destroy(string $id): bool
public gc(int $max_lifetime): int|false
public open(string $path, string $name): bool
public read(string $id): string|false
public write(string $id, string $data): bool
}

示例

示例 #1 使用 SessionHandlerInterface 的示例

以下示例提供了基于文件的会话存储,类似于 PHP 会话默认的保存处理程序 files。此示例可以轻松扩展以使用您最喜欢的 PHP 支持的数据库引擎来涵盖数据库存储。

请注意,我们使用 session_set_save_handler() 的 OOP 原型并使用函数的参数标志注册关闭函数。在将对象注册为会话保存处理程序时,通常建议这样做。

警告

为了简洁起见,此示例省略了输入验证。但是,$id 参数实际上是用户提供的值,需要进行正确的验证/清理以避免漏洞,例如路径遍历问题。因此,请勿在生产环境中使用此未修改的示例。

<?php
class MySessionHandler implements SessionHandlerInterface
{
private
$savePath;

public function
open($savePath, $sessionName): bool
{
$this->savePath = $savePath;
if (!
is_dir($this->savePath)) {
mkdir($this->savePath, 0777);
}

return
true;
}

public function
close(): bool
{
return
true;
}

#[
\ReturnTypeWillChange]
public function
read($id)
{
return (string) @
file_get_contents("$this->savePath/sess_$id");
}

public function
write($id, $data): bool
{
return
file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
}

public function
destroy($id): bool
{
$file = "$this->savePath/sess_$id";
if (
file_exists($file)) {
unlink($file);
}

return
true;
}

#[
\ReturnTypeWillChange]
public function
gc($maxlifetime)
{
foreach (
glob("$this->savePath/sess_*") as $file) {
if (
filemtime($file) + $maxlifetime < time() && file_exists($file)) {
unlink($file);
}
}

return
true;
}
}

$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();

// 继续通过键从 $_SESSION 设置和检索值

目录

添加注释

用户贡献的注释 8 条注释

ohcc at 163 dot com
6年前
从 PHP 7.0 开始,您可以实现 SessionUpdateTimestampHandlerInterface 接口来
定义您自己的会话 ID 验证方法,例如 validate_sid,以及在 session_set_save_handler() 的非 OOP 原型中的时间戳更新方法,例如 update_timestamp。

SessionUpdateTimestampHandlerInterface 是 PHP 7.0 中引入的一个新接口,目前尚未记录在案。它有两个抽象方法:SessionUpdateTimestampHandlerInterface :: validateId($sessionId) 和 SessionUpdateTimestampHandlerInterface :: updateTimestamp($sessionId, $sessionData)。

<?php
/*
@author 吴贤成
仅适用于 PHP 7.0+ 的代码结构,因为 SessionUpdateTimestampHandlerInterface 是在 PHP 7.0 中引入的
使用此类,您可以验证 php 会话 ID 并使用 PHP 7.0+ 中 session_set_save_handler() 的 OOP 原型更新 php 会话数据的时间戳
*/
class PHPSessionXHandler implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {
public function
close(){
// 返回值应为成功则为 true,失败则为 false
// ...
}
public function
destroy($sessionId){
// 返回值应为成功则为 true,失败则为 false
// ...
}
public function
gc($maximumLifetime){
// 返回值应为成功则为 true,失败则为 false
// ...
}
public function
open($sessionSavePath, $sessionName){
// 返回值应为成功则为 true,失败则为 false
// ...
}
public function
read($sessionId){
// 返回值应为会话数据或空字符串
// ...
}
public function
write($sessionId, $sessionData){
// 返回值应为成功则为 true,失败则为 false
// ...
}
public function
create_sid(){
// 从 PHP 5.5.1 开始可用
// 在需要新的会话 ID 时在内部调用
// 不需要参数,返回值应为创建的新会话 ID
// ...
}
public function
validateId($sessionId){
// 实现 SessionUpdateTimestampHandlerInterface::validateId()
// 从 PHP 7.0 开始可用
// 返回值应为会话 ID 有效则为 true,否则为 false
// 如果返回 false,则 php 会在内部生成一个新的会话 ID
// ...
}
public function
updateTimestamp($sessionId, $sessionData){
// 实现 SessionUpdateTimestampHandlerInterface::validateId()
// 从 PHP 7.0 开始可用
// 返回值应为成功则为 true,失败则为 false
// ...
}
}
?>
ohcc at 163 dot com
6年前
session_set_save_handler() 的非 OOP 原型从 PHP 7.0 开始支持 validate_sid 和 update_timestamp,而 OOP 原型即使在 PHP 7.2 中也不支持。但是 OOP 原型从 PHP 5.5.1 开始支持 create_sid。

validate_sid($sessionId)
此回调用于验证 $sessionId。其返回值应为会话 ID $sessionId 有效则为 true,无效则为 false。如果返回 false,则生成一个新的会话 ID 来替换无效的会话 ID $sessionId。

update_timestamp($sessionId)
此回调用于更新时间戳,其返回值应为成功则为 true,失败则为 false。
ohcc at 163 dot com
7年前
从 PHP 5.5.1 开始,支持另一种方法 create_sid()。当调用 session_regenerate_id() 时,将调用它。

SessionHandlerInterface {
/* 方法 */
抽象公共布尔关闭(无效)
抽象公共布尔 create_sid(无效)
抽象公共布尔销毁(字符串 $session_id)
抽象公共布尔 gc(整数 $maxlifetime)
抽象公共布尔打开(字符串 $save_path,字符串 $session_name)
抽象公共字符串读取(字符串 $session_id)
抽象公共布尔写入(字符串 $session_id,字符串 $session_data)
}
avenidagez at foro5 dot com
9年前
请注意,session_start() 会先调用 open 然后调用 read,并且类会为 open 返回 true,并为 read 返回会话值或空值。
好吧,然后没有捕获错误,也就是说,session_start() 必须在失败时返回 false,但这在类方法 open 的实现中并非如此,无论您从 open 返回 true、false 还是其他任何值,session_start() 函数都会忽略它,并继续执行 read 方法
一个 bug?如果 open 返回 false,session_start() 应该停止下一步(读取)并将其自身返回 false

如果(session_start())...代码
否则退出();

因此,忘记 session_start() 的返回值,您需要实现一个错误捕获例程,并在 open 方法失败时退出()
warxcell at gmail dot com
12年前
您应该在类名前添加<b>\</b>,以告诉 php 它来自根命名空间。
tony at marston-home dot demon dot co dot uk
6年前
您的自定义会话处理程序不应包含对任何会话函数的调用,例如 session_name() 或 session_id(),因为相关值作为参数传递给各种处理程序方法。尝试从其他来源获取值可能无法按预期工作。
ohcc at 163 dot com
4年前
如果您想在自己的会话处理类中使用类型声明,请不要“实现”SessionHandlerInterface、SessionIdInterface 或 SessinUpdateTimestampInterface,否则您将收到一个致命错误,提示类方法的声明必须与接口方法兼容。

一个不好的例子
<?php
class SessionWuXianchengHandler implements SessionHandlerInterface {
public function
open(string $sessionPath, string $sessionName) : bool {
}
......
}
?>

一个好的例子
<?php
class SessionWuXianchengHandler {
public function
open(string $sessionPath, string $sessionName) : bool {
}
......
}
?>
StanE
9年前
我认为 MySessionHandler 类中 gc() 方法的示例中有一个小“错误”。它使用了 filemtime() 函数,该函数的返回值会被 PHP 缓存。在 gc() 方法的 foreach 块内添加以下行

clearstatcache(true, $file);
To Top