SESSION基础
session 即会话,它与cookie类似,是记录用户行为状态的机制,只不过cookie将用户状态信息放在客户端(浏览器),session是把信息以一定的数据结构(通常由sessionID和内容组成)放在服务端,存储容器可以是文件(最常用)、RDB(mysql,postgresql,sqlLite等)、NoSql(redis,memcache)等,它的正常工作依赖于http协议助其完成客户端与服务端的交流,最常见的是借用http header头的cookie,PHP默认就是用cookie,还可以借用url参数,html的隐藏表单域等,但后两者不够方便,并且实践证明用户很少会禁用cookie。其实单台服务器用文件存储seesion内容就可以了,多台的话一定要用数据库的,防止找不到相应的seesion。
工作原理如下图:
PHP中一般借用session扩展(php内置)进行session的管理:
session_id($sessionID);//设置或获取sessionID,放在session_start()之前
session_start();//开启session扩展
$_SESSION['token'] = 'shjsals1212klasssu80';//利用超全局变量$_SESSION设置session内容
echo $_SESSION['token'];//获取当前sessionID下的某一个session值
SESSION(运行时)配置
session运行时配置即在php.ini文件中进行session的配置。常用的如下:
- session.save_handler :string
session.save_handler 确定了存储session用的处理器的名字,默认files,如果想改成memcache,可以这样写:
session.save_handler = memcache,session.save_path = “tcp://127.0.0.1:8888”
- session.save_path :string
session.save_path确认了传递给存储处理器的参数。如果选择了默认的 files 文件处理器,则此值是创建文件的路径。默认为 /tmp,此指令还有一个可选的 N 参数来决定会话文件分布的目录深度,如session.save_path=‘2;/tmp’。N不宜太大,不然I/O太多,很影响性能。
- session.name :string
session.name定义了sessionID名以用做 cookie 的名字。只能由字母数字组成,默认为 PHPSESSID。
- session.auto_start :bool
session.auto_start 定义了session扩展是否自动开启,默认0,所以我们在使用session时要session_start()。
- session.use_cookies : bool
定义session是否指定客户端用cookie存储PHPSESSID
- session.use_only_cookies : bool
定义session是否指定客户端只能用cookie存储PHPSESSID
- session.use_trans_sid : bool
定义session是否启用透明 SID 支持,这样可以将PHPSESSID作为URl的参数来管理,默认为 0(禁用)
- session.gc_probability : int
session.gc_probability 与 session.gc_divisor 合起来用来管理 gc(garbage collection 垃圾回收)进程启动的概率。默认为 1。
- session.gc_divisor :int
session.gc_divisor 与 session.gc_probability 合起来定义了在每个会话初始化时启动 gc(garbage collection 垃圾回收)进程的概率。此概率用 gc_probability/gc_divisor 计算得来。例如 1/100 意味着在每个请求中有 1% 的概率启动 gc 进程。session.gc_divisor 默认为 100。
- session.gc_maxlifetime :int
session.gc_maxlifetime 指定过了多少秒之后数据就会被视为“垃圾”并被清除。你可以将gc_divisor设为1,gc_maxlifetime设为10,来看gc回收的现象,如果save_handler值为files,就是将过期的session文件删除。
这些是常用的,详情见官网session运行中配置
SESSION函数
函数也列出一些常用的,详情见官网session函数。
- session_id($sessionID);//设置或获取sessionID,放在session_start()之前
- session_start();//开启session扩展
- $_SESSION[‘token’] = ‘shjsals1212klasssu80’;//利用超全局变量$_SESSION设置
- $_SESSION[‘token’];//获取当前sessionID下的某一个session值
- unset($_SESSION[‘token’]);//释放指定的session变量,注意请不要使用unset($_SESSION)来释放整个$_SESSION, 因为它将会禁用通过全局$_SESSION去注册会话变量
- session_unset();//释放所有的session变量,等价于$_SESSION=[];
- session_destroy//销毁当前sessionID对应的数据(如果save_hander=files,则删除相应的文件), 但是不会重置当前会话所关联的全局变量, 就是不改变内存中$_SESSION值。 如果需要再次使用会话变量, 必须重新调用 session_start() 函数。可以通过isset($_SESSION[‘token’])来认识其差别
SESSION类和接口
php为用户提供了一个接口,SessionHandlerInterface,用户可以自定义seesion管理。
官方提示:SessionHandlerInterface是一个接口,它定义了用于创建自定义会话处理程序的原型。自定义seesion处理类必须实现此接口,若需要调用自定义类,必须将该类的实例传递给session_set_save_handler()。
请注意,该类的回调方法设计为由PHP内部调用,而不是从用户空间代码调用。
SessionHandlerInterface定义了几个方法:
SessionHandlerInterface {
/* 方法 */
abstract public close ( void ) : bool
abstract public destroy ( string $session_id ) : bool
abstract public gc ( int $maxlifetime ) : int
abstract public open ( string $save_path , string $session_name ) : bool
abstract public read ( string $session_id ) : string
abstract public write ( string $session_id , string $session_data ) : bool
}
接口的抽象方法作用如下:
简单代码实例(redis):
class SessionManager{
private $redis;
private $sessionSavePath;
private $sessionName;
private $sessionExpireTime = 30;
public function __construct(){
$this->redis = new Redis();
$this->redis->connect('127.0.0.1',6379); //连接redis
//注册类
ini_set('session.save_handler','user');
$retval = session_set_save_handler(
array($this,"open"),
array($this,"close"),
array($this,"read"),
array($this,"write"),
array($this,"destory"),
array($this,"gc")
);
session_start();
}
public function open($path,$name){
return true;
}
public function close(){
return true;
}
/**
* read session by session_id
* @param string $session_id
* @return mixed
*/
public function read($id){
$value = $this->redis->get($id);
if($value){
return $value;
}else{
return "";
}
}
public function write($id,$data){
if($this->redis->set($id,$data)){
$this->redis->expire($id,$this->sessionExpireTime);
//设置过期时间
return true;
}
return false;
}
public function destory($id){
if($this->redis->delete($id)){
return true;
}
return false;
}
/**
* this function is no use because of redis expire
* @param int $maxlifetime
* @return bool
*/
public function gc($maxlifetime){
return true;
}
//析构函数
public function __destruct(){
session_write_close();
}
}
$session = new SessionManager();
$_SESSION['fpf'] = "pop";
echo $_SESSION['fpf'];
就目前我所用到的php框架,CI和Laravel都基于这个接口对重新设计了seesion管理,可以下载源码进行学习,非常棒的学习资料。
提示:
php也允许开发者以很简单的方式将session存储器由默认的files替换为redis或memcache,只需要下载相应的扩展即可。以redis为例:
ini_set(“session.save_handler”, “redis”);
ini_set(“session.save_path”, “tcp://127.0.0.1:6379”);
session_start();
$_SESSION[“user”]=“sgao”;
如果可以修改php.ini文明加密,可以直接改session.save_handler和session.save_path值。
特别注意的是一定要有redis扩展,通过phpinfo()查看如下图:
如果没有redis扩展,红色圈定部分只有files和user这两个选项的,当然,你下了memcache扩展,这里就会出现memcache选项。
PHP7 SESSION新特性
php7之前session_start()函数是不可传参的,但php7可以了,例如:
<?php
session_start([
'cache_limiter' => 'private', //在读取完毕会话数据之后马上关闭会话存储文件
'cookie_lifetime'=>3600, //SessionID在客户端Cookie储存的时间,默认是0,代表浏览器一关闭SessionID就作废
'read_and_close'=>true //在读取完会话数据之后, 立即关闭会话存储文件,不做任何修改
]);