14.2 Session详解
负载均衡中使用Redis实现共享Session
https://segmentfault.com/a/1190000011558000
PHP session有效期session.gc_maxlifetime的设置方法
https://www.cnblogs.com/luowei/p/5294835.html
14.2.1 Session的基本概念和设置
Session存储在服务端,本质上和Cookie没有区别,都是针对HTTP协议的局限性而提出的一种保持客户端和服务端间会话状态的机制。Session经常用来网站的上下文间实现页面变量的传递、用户身份认证、程序状态记录等,常见的有配合Cookie使用、实现保存用户的登录状态或者记录用户的购物下单信息等。
在使用Session之前必须先开启Session,可使用session_start()开启Session,同Cookie一样,在开始之前不能有任何输出内容.
也可以修改php.ini中的session.auto_start = 0为session.auto_start = 1,设置自动开启Session支持,这样就不必每次在使用Session的时候都加上session_start()了。
码中设置了Session时,在HTTP请求的消息头中会携带一个名为PHPSESSID的Cookie,其值是一个32位十六进制的字符串。每个客户端向服务器请求时都会产生一个不同的值,如果清除浏览器的Cookie,再次刷新页面时将会重新设置一个PHPSESSID的值。服务端接收到这个Cookie,根据其值在服务器中找到对应的Session文件,从而实现保持与客户端链接状态的信息,其中Session中存储着序列化的Session键值等信息。设置了Session的HTTP请求消息头如下:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cache-Control: max-age=0
Connection: keep-alive
Cookie: PHPSESSID=oigi9s1fi2vn9up2a3pviboec6
Host: php.jingpan.io
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75
14.2.2 Session的工作原理和存储机制
前文讲到,Session是通过一个名为PHPSESSID的Cookie来和服务器取得联系的,Session通过sessionID(PHPSESSID的值)来找到对应服务器中Session的文件名。sessionID是在客户端和服务端通过HTTP Requset和HTTP Response传来传去的。sessionID按照一定的算法生成,保证其值的唯一性和随机性。Cookie里存储着Session的sessionID和Session的生存期,如果没有设置Session的生存期,则sessionID存储在内存中,关闭浏览器时Session失效,重新请求页面时会重新注册一个sessionID。
默认情况下,Session是存储在服务器硬盘上的,在php.ini中可通过session.save_path设置Session文件的存储路径,默认为服务器上的/tmp目录。此配置指令还有一个可选的N参数来决定会话文件分布的目录深度。例如,设定为’5; /tmp’将使创建的会话文件和路径类似于/tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If。要使用N参数,必须在使用前先创建好这些目录。在ext/session目录下有个小的shell脚本,即mod_files.sh。Windows版本下的mod_files.bat可以用来做这件事。此外,如果使用了N参数并且大于0,那么将不会执行自动垃圾回收。文件储存模块默认使用mode 600创建文件。通过修改可选参数MODE来改变这种默认行为:N;MODE; /path。其中,MODE是mode的八进制表示。使用以上描述的可选目录层级参数N时请注意,对于绝大多数站点,大于1或者2的值会不太合适——因为这需要创建大量的目录。例如,值设置为3需要在文件系统上创建64^3个目录,将浪费很多空间和inode。仅仅在绝对肯定站点足够大时才可以设置N大于2。一个Session文件的内容如下:
namehaha|s:10:"lixiaolong";namehah|s:10:"lixiaolong";namehaa|s:10:"lixiaolong";namhaha|a:5:{s:1:"a";i:1;i:0;i:2;i:1;i:3;i:2;i:4;i:3;i:4;}
内容的格式为:session名|值类型:长度:值;。
14.2.3 使用Redis存储Session
PHP设置Redis储存Session
https://cloud.tencent.com/developer/article/1556413
mySessionHandler.php
<?php
class mySessionHandler implements \SessionHandlerInterface
{
private $redis;
private $expTime = 1440; // 默认超时时间 根据业务场景设置
private $prefix = 'PHPREDIS_SESSION_';
function __construct(){
// 连接redis
$this->redis = new Redis();
$this->redis->connect('127.0.0.1',6379);
// 设置session处理回调 并且将session_write_close注册为register_shutdown_function函数
session_set_save_handler($this, true);
// 开启
session_start();
}
function open($path, $name)
{
return true;
}
function close(){
return true;
}
function read($session_id)
{
//$value = $this->redis->get("siam_".$session_id);
$value = $this->redis->get($this->prefix.$session_id);
if ($value){
return $value;
}
return '';
}
function write($session_id, $data)
{
if( $this->redis->set($this->prefix.$session_id, $data) ){
$this->redis->expire($this->prefix.$session_id, $this->expTime);
return true;
}
return false;
}
function destroy($session_id)
{
if ( $this->redis->delete($this->prefix.$session_id) )
{
return true;
}
return false;
}
function gc($maxlifetime)
{
return true; // 因为redis设置了过期时间,不需要再gc回收
}
function __destruct()
{
session_write_close();
}
}
set.php
<?php
require_once "mySessionHandler.php";
new mySessionHandler();
$_SESSION['name'] = "siam123";
echo $_SESSION['name'];
浏览器访问显示结果
siam123
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION_65sskh7jn2v3qo0p77bcgq3q55"
127.0.0.1:6379> get
(error) ERR wrong number of arguments for 'get' command
127.0.0.1:6379> get PHPREDIS_SESSION_65sskh7jn2v3qo0p77bcgq3q55
"name|s:7:\"siam123\";"
127.0.0.1:6379> ttl PHPREDIS_SESSION_65sskh7jn2v3qo0p77bcgq3q55
(integer) 1420
127.0.0.1:6379>