最近在学习Laravel 这套框架,发现对PHP的会话不是很了解,因而乎看了PHP官网手册,也看了慕课网的SESSION视频教程,看完后总以为缺点什么,咦~,缺点在掘金上写篇读书笔记,唠叨唠叨,也能够检验一下本身学习的怎么样,废话很少说,直接切入正题php
在了解PHP会话技术前,咱们先讨论一件事情,那就是什么是会话。从字面意义上来讲,应该是一次会谈,一次交流,没错就是一次谈话,若是是谈话的话就须要有两个谈话对象,对计算机世界而言,谈话对象就是客户端和服务器端,客户端说一句话,服务器回答一句。程序员
上面的话说得太直白了,若是用计算机专业术语来解释会话,就是这样子的:算法
会话是浏览器和服务器之间的屡次请求和响应数组
好像似懂非懂的样子,解释一下的话,就是客户端访问服务器,到服务器作出响应,最后客户端关闭退出,在这段时间里产生的请求和响应,称为客户端和服务器的一次会话浏览器
会话的出现,对程序员来讲又有一个知识点要考了(哈哈),可不能够不用会话呢?答案是不能够的,除非你能证实你是本身。这就和现实世界是同样的,你能证实你本身嘛,不能,你要拿出你的身份证才能够证实你本身。缓存
在计算时间里是怎么解决你是你本身的这个世界难题的呢?使用HTTP协议,好像不行,HTTP协议是无状态的,它是没得期望的了。怎么办呢,计算机大佬们设计了一套会话技术,专门来处理“记住我”的问题安全
若是要理解起来仍是很麻烦的,用一张图来解释是最合适不过的 服务器
我模拟一下图中操做,就能够大体的了解PHP会话的工做原理了cookie
咱们第一次访问PHP官网,浏览器发出一个HTTP请求到服务器,服务器接收到客户端的请求。服务器发现尚未和客户端创建会话,进行session初始化操做,建立session_id,session文件等操做网络
执行代码,若是在执行的过程当中有session数据产生,则将数据存放在超全局数组$_SESSION
中,代码执行完毕,把$_SESSION
中的数据序列化后存放在session文件中,并设置一个会话cookie,cookie名为session_name()
,cookie值为session_id()
,把cookie信息携带在对客户端的响应中,一并返回给客户端
第二次你访问了PHP官网,仍是会执行session初始化,发现你发出的HTTP请求携带有session_id
,同时去读取这个session_id
对应的session文件,并把文件中的数据读取到$_SESSION
数组中,继续执行代码,若是有设置session数据,把数据暂存在$_SESSION
数组中,最后代码执行完毕,把数组中的数据序列化后存放在session文件里,一样的把sesion_id经过cookie方式存放在客户端 ,下次在访问网站的时候,发送给服务器端就是了
网站访问完了退出登陆,这个时候服务器会销毁session,把客户端的cookie设置过时,并删除服务器端的session文件
若是下次还访问PHP官网,重复以上操做
经过上面的介绍,我发现了这样一个问题,为何服务器在第一次已经给客户端发送了cookie后,在第二次、第三次...都发送cookie呢,并且内容仍是同样的,这会致使网络开销的啊。
确实如此,每次发送也很差,为何这么作呢?
我大体猜一下这其中的缘由,首先会话是有时间限制的,有的浏览器关闭退出后结束会话,有的会话是两个小时内的活跃用户
每次重置cookie,使客户端的cookie一直处于活跃状态,这样浏览器就不会清除cookie了
若是不更新的话,cookie一旦过时,用户就不能使用这个cookie,这样将致使用户必须从新登陆网站后才能够继续使用。
经过每次对用户的响应携带着cookie信息,重置cookie的过时时间,让客户端的cookie处于活跃状态。
第二种状况就是,经过每次发送cookie到客户端,重置客户端的cookie,防止客户端的cookie被篡改,这种作法是颇有限的,并不能彻底的杜绝
以上就是我想到的为何要每次都给客户端发送cookie的缘由,我也没有去验证这两种说法,后面我会去找找看是什么缘由
这篇文章不是在说session的吗,怎么上面一直在提cookie,cookie又是什么东西。cookie简单的来讲就是实现session的一种方式,session的实现也可使用URL来实现,只不过cookie要好一些,这里暂时不展开去说cookie,我会用另外一篇文章去作介绍
php中已经为咱们实现了不少处理session的方法,经过这些方法就能够去实现session的初始化、设置session数据、session销毁等等操做
这里我列出了经常使用的session方法,不知道如何使用的,能够随时在php官网进行查找,还有其余方法,你能够经过连接进行访问
在PHP中使用session_start()
就能够开始一个会话了,固然若是请求中的cookie携带了会话ID,会重用这个会话,不会建立新的会话
在PHP具体的工做会作什么工做呢,经过PHP手册咱们能够获得这些:
当会话开始的时候,PHP内部会使用会话管理器的open和read回调函数,这个会话管理器能够是PHP自带的,也能够是你本身定义的(后面我会实现一个本身的会话管理器),经过session_set_save_handler
来设置自定义的会话管理器,使用read回调函数返回的会话数据,经过反序列化数据并把数据填充到$_SESSION
全局变量中
在开启会话以前咱们能够调用session_name()
对会话命名,使用session_id()
得到sessionID
咱们在开启一个会话的时候,PHP会使用会话管理器来对会话数据进行处理,默认的PHP会话管理器是files,这将致使一个问题,它会锁定会话文件,对并发请求很大的网站来说,这将是致命的。一个比较但简单的作法是,每次修改完会话数据后,使用session_write_close()
来保存会话并释放文件锁,这种作法是很是不建议的。
推荐使用能够并发操做的会话管理器来代替文件保存管理器,首选固然是推荐Redis做为session的会话管理操做,为何不使用memcached存储session呢?网上的说法是memcaced是缓存数据而不是存储数据的,memcached的LAR算法针对每一个slab类执行,而不是针对总体,这样致使session最老的用户会掉线,具体的缘由这里就不在深究,我也没有用过memcached做为session管理
在第二次访问网站的时候,会把sessionID发送给服务器,发送sessionID方式有两种:
极力推荐使用Cookie的方式来传递会话ID,若是用户禁用Cookie,友情提示用户开启,Cookie相关的设置选项我会在会话安全中列出来
用户登出的时候要清除会话,销毁会话操做比起建立来讲是比较麻烦的,具体分为三部分,
php中的会话数据存放在全局变量$_SESSION
中,须要先把全局变量重置,重置的方法以下:
$_SESSION = array();
复制代码
不要使用unset($_SESSION)
来复位超级变量,由于这样致使没法继续使用$_SESSION
来注册会话变量
为了完全的销毁会话,须要把客户端的会话cookie删除掉
$params= session_get_cookie_params();
setcookie(session_name(),'',time()-1,$params['path'],$params['domain'],$params['secure'],$params['httponly']);
复制代码
让cookie过时就能够,这样浏览器会自动删除过时的cookie
若是开启了session.use_strict_mode配置项后,能够不用手动删除cookie,由于会话模块不会接受已通过期会话ID的cookie了,它会生产一个新的会话ID cookie,建议开启这个配置项
最后使用函数session_destroy
来删除会话数据
session_destroy();
复制代码
若是你使用的是file做为会话管理器,那么还会删除session文件
php默认会使用gc(garbage collection 垃圾回收)管理会话数据,何时启动gc进程呢?
首先经过session.gc_maxlifetime 指定了过多少秒后的数据视为垃圾会话并进行清除
垃圾收集器会在会话开启的时候,根据session.gc_probability与 session.gc_divisor 的设置来启动垃圾收集器gc。 好比,session.gc_probability 为 1,session.gc_divisor为 100,那么就有1/100的几率来启动垃圾收集器gc
若是gc_probability/gc_divisor设置的过大,会频繁的启动gc来管理会话数据;设置的过小会有不少的过时会话数据没有即时清除,浪费存储空间
gc进程处理过时会话数据也是比较粗糙的,它会遍历全部的session文件,查看文件修改时间和当前系统时间,来判断文件是否过时而删除文件
因此php自带的file会话管理器工做效率是很低的,同时也不支持并发访问会话文件,而 Redis 或 Memcached 天生就支持 key/value 过时机制的,用于做为会话处理器很是合适
至此php中的会话基本操做就是这些了,但对会话如何使用,如何保证会话是安全的,这也是很是重要的,防人之心不可无啊。
后面我会用两个章节来学习会话安全,以及Laravel中的session