phalcon自定义session_id

phalcon基于di容器管理所有服务,session也做为服务被引入。正常情况下要实现自定义session_id只要在session_start前使用session_id函数设置即可。但是,一般逻辑是先检查session是否存在用户信息,如果存在表示登陆,不存在表示游客。要获取session信息必须先session_start,因此想要真正自定义session_id,要在返回cookie头前对session_id进行修改。 php提供了一个函数session_regenerate_id(),允许使用新生成的会话 ID 更新现有会话 ID,并且不会修改用户信息。基于这个思路,注入di容器的session服务如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
$di->setShared('session', function () {
$session = new class() extends SessionManager{
};

$factory = new SerializerFactory();
$adapterFactory = new AdapterFactory($factory);

$redis = new class($adapterFactory, array_merge([
"lifetime" => 86400,
"prefix" => 'sess-ph-',
], $this->getConfig()->redis->toArray()[0])) extends SessionRedis {

private $userSid = "";

/**
* @return string
*/
public function getUserSid(): string
{
return $this->userSid;
}

/**
* @param string $userSid
*/
public function setUserSid(string $userSid)
{
$this->userSid = $userSid;
}

/**
* 这个函数有用,不要删除
* phalcon在session start时调用session_set_save_handler函数设置当前类作为session
* 适配器,create_sid对SessionHandler::create_sid方法进行重写,在调用本类regenerateId时会调用php的session_regenerate_id函数。
* session_regenerate_id函数内部调用适配器的create_sid方法生成sid,也就是这个方法,当前匿名类对外暴露sid的getter和setter方法实现
* 自定义sid,方便控制sid生成和获取任意用户的session信息
* @return string
*/
public function create_sid() :string
{

if (empty($this->getUserSid())){
// 固定给一个无效的sessid, 这个无法解密,也就是说解密失败的sessid,可以认为就是游客
return "guest_" . md5("pref_" . di()->get("request")->getClientAddress(true));
}

return $this->getUserSid();
}
};


$session->setAdapter($redis);

$session->start();

return $session;
});

redis存储session,提高效率,session服务对外开放setUserSid方法,用户登陆时重新生成session_id即可。可以在生成用户sid过程中对用户之前的sid进行清理,更新sid的同时,避免sid堆满内存。游客用户可以使用ip作为唯一sid,如果没有特殊需求,固定一个sid更好一点

1
2
3
$this->session->getAdapter()->setUserSid($this->generateUserSessId(1));
$this->session->regenerateId();
$this->session->set("user_info", $userInfo);