Session即会话,批一种持续性的、双向的链接。Sesstion和Cookie本质上没有什么区别,都是针对HTTP协议的局限性而提出的一种保持客户端和服务器间保持会话连接状态的机制。
Session的实现可以有多种,如URL重写、Cookie,通过在Cookie中存储sessionID实现Session传递。
针对Web网站来说,Session批用户在浏览器某个网站时,从进入网站到浏览器关闭这段时间内会话。由此可知,session实际上是一个特定的时间概念。使用session可以在网站的上下文不同页面间传递变量、用户身份认证、程序状态记录等。常见形式就是配合cookie使用,实现保存用户登录状态功能。和cookie一样,session_start()必须在程序最开始执行,前面不能有任何输出内容,否则就会出现以下警告
Warning: Cannot send session cookie-headers already sent
类似这样的警告信息通常是因为当前页面被包含或者包含了BOM头。
有时候,确实需要输出或者不能控制前面是否有输出,可以这么做
ob_start();
Session的工作有理
我们看到,HTTP协议本身美工不能支持服务器端保存客户端的状态信息。为了解决这一问题,于是引入了session的概念,用其来保存客户端的状态信息。
session通过一个称为PHPSESSID的Cookie和服务器联系。session是通过sessionID判断客户端用户的,即session文件的文件名。
用一个形象的比喻解释session的工作方式。假设web server是一个商场的存包处,一个顾客(HTTP Request)第一个来到存包处,管理员把顾客的物品存放在某柜子里面(这个柜子就相当于session),顾客下一次来的时候,要把号码牌交给存包处的管理员。管理员根据号码牌找到相应的柜子,根据顾客的请求,取出、更换、添加柜子的物品,存包处也可以让顾客的号码牌和号码牌对应的柜子失效。顾客的忘性很大,管理员在顾客回去的时候都要提醒顾客记住自己的号码牌。这样,顾客下次来的时候,就会带着号码牌回来。
sessionID实际上是在客户端和服务器端之间通过HTTP Request和HTTP Response会来传去。sessionID按照一定的算法生成,必须包含在HTTP Request里面,保证唯一性和随机性,以确保session的安全。如果没有设置session生存周期,sessionID存储在内存中,关闭浏览器后该ID自动注销;重新请求该页面,会重新注册一个sessionID。如果客户端没有禁用cookie,cookie在启动session会话的时候扮演的是存储sessionID和Session生存期的角色。可以手动设置session的生存期,代码如下 :
$lifeTime = 24*3600; setcookie(session_name(),session_id(),time()+$lifeTime,‘/‘);
也可以使用session_set_cookie_params()函数设置session的生存期。
session过期后,PHP会对其进行回收。因此,session并非随着浏览器的关闭而消失的。
如果客户端禁用cookie怎么办?没办法,所有生存周期都是浏览器进程,只要关闭浏览器,再次请求页面又要重新注册session。
那么怎么传递sessionID呢?通过URL或者隐藏表单。
php.ini中把session_use_trans_sid设成1,这样连接就会自己加Session的ID。
session以文件的形式存放在本地硬盘的一个目录中,所以当session比较我时,磁盘读取文件就会比较慢。经验告诉我们,当一个目录的文件数超过2000时,读写这个目录就会地很慢。于是想到把session分目录存放。
php.ini里session设置部分中一一项:session.save_path="N;MODE;/path"。这项设置可以给session存放目录进行多级散列,其中“N”表示要设置的目录级数,“MODE”表示目录的权限属性,默认为600。Windows基本不用设置。“path”表示session文件存放 目录的路径,比如设置为下面的格式:
session.save_path="2;/tmp/phpsession"
上述代码表示把/tmp/phpsession目录作为PHP的session文件存放根目录,在该目录下进行两级目录散列,第一级目录分别以0~9和a~z共36个字符作为目录名,这样存放session的目录可以达到3636个。
注意:这里的子目录需要自己手动创建,当然是写代码。以后的session将按sid的前两位存入对应的目录中去。
session的回收是被动的,为了保证过期的session能被正常回收,可以修改php配置文件中的session.gc_divisor参数以提高回收率(太大了会增加负载),或者设置一量判断是否过期。对于设置分级目录存储的session,php不会自动回收,需要自己实现其回收机制。