Session技术与Cookie相似,都是用来存储使用者的相关资料。但是最大不同之处在于Cookie是将数据存放于客户端计算机中,而Session则是将数据存放于服务器系统下。
在Web技术发展史上,虽然Cookie技术的出现是一个重大的变革,但Cookie是在客户端计算机中保存资料,所以引起了一个争议。用户有权阻止Cookie的使用,使Web服务器无法通过Cookie来跟踪用户信息。而Session技术是将使用者相关的资料存放在服务器的系统之下,所以使用者无法停止Session的使用。
可以把Cookie比喻成第一次去商场时为你提供的会员卡,并有用户自己保存。如果用户下次再去商场购物时忘记带卡了,或者是把卡弄丢了,这样用户就不能再以会员的身份购物了。但是如果商场在为用户办理会员卡以后,再由商场保存这张卡,用户就不用每天都把卡放在身上了。但是商场的会员特别多,你每次来时,商场怎么知道你是这里的会员呢?所以在用户办理会员卡时,商场会要求用户保存会员卡的卡号。下次这个用户再来购物时,商场就可以通过用户提供的卡号查询到会员的登记信息。
Session就是这样,在客户端仅需要保存由服务器为用户创建的一个Session标识符(相当于会员卡卡号),称为Session ID,而在服务器端(文件/数据库/Memcache中)保存Session变量的值。Session ID是一个既不会重复,又不容易找到规律的,由32位十六进制数组成的字符串。Session ID会被保存在客户端的Cookie里,如果用户阻止Cookie的使用,则可以将Session ID保存在用户浏览器地址栏的URL中。当用户请求Web服务器时,就会把Session ID发送给服务器,再通过Session ID提取保存在服务器中的Session变量。可以把Session中保存的变量,当做是这个用户的全局变量,同一个用户对每个脚本的访问都共享这些变量。
当某个用户想Web服务器发送请求时,服务器首先检查这个客户端的请求是否已经包含了一个Session ID。如果包含,说明之前已经为此用户创建国Session ID,服务器则按该Session ID把Session检索出来使用。如果客户端请求不包含Session ID,则为该用户创建一个Session,并且生成一个与此Session关联的Session ID,在本次相应中被传送给客户端保存。
配置SESSION
在PHP配置文件中,有一组和Session相关的配置选项。通过对一些选项重新设置新值,就可以对Session进行配置,否则使用默认的Session配置。在php.ini文件中和Session有关的,一些有意义选项及其描述如下表所示。
选项名 | 描述 | 默认值 |
session.auto_start | 在客户访问任何页面时自动开启并初始化Session,默认禁止(因为类定义必须在会话之前被载入,所以若打开这个选项,你就不能在会话中存放对象) | 禁用(0) |
session.cookie_domain | 传递会话ID的Cookie作用域(默认为空时会根据Cookie规范去自动生成主机名) | none |
session.cookie_lifetime | Cookie中Session ID在客户机上保存的有效期(秒),0表示延续到浏览器关闭时 | 0 |
session.cookie_path | 传递会话ID的Cookie作用路径 | / |
session.name | 会话的名称,用在客户端Cookie里会话ID标识名,只能包含字母和数字 | PHPSESSID |
session.save_path | 对于files处理器,此值是创建会话数据文件的路径 | /tmp |
session.use_cookies | 是否使用Cookie在客户端保存会话ID,1表示允许 | 1 |
session.use_trans_sid | 是否使用明码在URL中显示SID(会话ID)。(基于URL的会话管理总是比基于Cookie的会话管理有更多的风险,所以应当禁用) | 默认禁止(false) |
session.gc_probability |
定义在每次初始化会话时,启动垃圾回收程序的概率,这个概率计算公式如下: session.gc_probability/session.gc_divisor 对会话页面访问频繁,概率就越小。建议值为1/1000~5000 |
1/1000 |
session.gc_divisor | ||
session.gc_maxlifetime | 超过此参数所指的秒数后,保存的数据将被视为‘垃圾’并由垃圾回收程序清理 | 1440(24分钟) |
session.save_handler | 存储和检索与会话关联的数据的处理器名字,可以使用(files、user、sqlite、memcache)中的一个值,默认为文件(files),如果想要使用自定义的处理器(如基于数据库或者Memcache的处理器),可用“user” | files |
Session的声明与使用
Session的设置不同于Cookie,必须先启动,在PHP中必须调用session_start()函数,以便让PHP核心程序,将和Session相关的内建环境变量预先载入至内存中。
bool session_start(void)
这个函数没有参数,且返回值均为TRUE。有两个主要作用,一是开始一个会话,二是返回已经存在的会话。
当第一次访问网站时,session_start()函数就会创建一个唯一的Session ID,并自动通过HTTP的响应头,将这个Session ID保存在客户端Cookie中。同时,也在服务器端创建一个以这个Session ID命名的文件,用于保存这个用户的会话信息。当同一个用户再次访问这个网站时,也会自动通过HTTP的请求头将客户端Cookie中保存的Session ID再携带过来,这时session_start()函数就不会再去分配一个新的Session ID,而是在服务器的硬盘上去寻找和这个Session ID同名的Session文件,将之前为这个用户保存的会话信息读出,在当前脚本应用达到跟踪这个用户的目的。所以在会话期间,同一个用户在访问服务器上的任何页面时,都是同一个Session ID。
如果你是使用基于Cookie的Session,在使用该函数开启Session之前,不能有任何输出的内容。因为基于Cookie的Session是在开启的时候,调用session_start()函数会生成一个唯一的Session ID,需要保存在客户端计算机的Cookie中,和setcookie()函数一样,有头信息的设置过程,所以在调用之前不能有任何的输出,空格或空行也不行。
如果不想在每个脚本都使用session_start()函数开启Session,可以在php.ini里设置“session.auto_start=1”,则无须每次使用Session之前调用session_start()函数。但启用该选项也有一些限制,即不能将对象放入Session中,因为类定义必须在启动Session之前加载。所以不建立使用php.ini的session.auto_start属性来开启Session。
注册一个会话变量和读取Session
在PHP中使用Session变量,除了必须要启动之外,还要经过注册的过程。注册和读取Session变量,都要通过访问 $_SESSION数组完成。但必须在调用session_start()函数开启Session之后才能使用。$_SESSION总是具有全局范围,因此不需要对$_SESSION使用global关键字。
session_start();
$_SESSION['username'] = "skygao";
$_SESSION['uid'] = 1;
执行该脚本后,两个Session变量就会被保存在服务器端的某个文件中,该文件的位置是通过php.ini文件,在session.save_path属性执行的目录下,为这个访问的用户单独创建的文件,用来保存注册的Session值。例如,某个保存Session变量的文件名为“sess_1uebcnr0cd3ocbjg36s8ep0105”,文件名中含Session ID,所以每个访问用户在服务器都有自己的保存Session变量的文件。该文件的内容结构如下所示:
变量名|类型:长度:值;
本例在Session中注册了两个变量,如果在服务器找中找到为该用户保存Session变量的文件,打开后可以看到如下内容:
username|s:6:"skygao";uid|i:1;
注销变量与销毁Session
当使用完一个Session变量后,可以将其删除,当完成一个会话后,也可以将其销毁。销毁和当前Session有关的所有资料,可以调用session_destroy()函数结束当前的会话,并清空会话中所有资源。
bool session_destroy(void)
相对于session_start()函数(创建Session文件),该函数用来关闭Session的运作(删除Session文件),如果成功则传回TRUE,销毁Session资料失败则返回false。但该函数并不会释放和当前Session相关的变量,也不会删除保存在客户端Cookie中的Session ID。因为$_SESSION数组和自定义的数组在使用上是相同的,所以我们可以使用unset()函数来释放Session中注册的单个变量。
unset($_SESSION['username']);
unset($_SESSION['uid']);
一定要注意,不要使用unset($_SESSION)删除整个$_SESSION数组,这样将不能再通过$_SESSION超全局数组注册变量。但如果想把某个用户在Session中注册的所有变量都删除,可以直接将数组变量$_SESSION赋上一个空数组。
$_SESSION = array();
PHP默认的Session是基于Cookie的,Session ID被服务器存储在客户端的Cookie中,所以销毁Session时也要清除Cookie中保存的Session ID,而这就必须借助setcookie()函数完成。在Cookie中,保存Session ID的Cookie标示名称就是Session的名称,这个名称是php.ini中,通过session.name属性指定的值。在PHP脚本中,可以通过调用session_name()函数获取Session名称。删除保存在客户端Cookie中的Session ID,代码如下:
if(isset($_COOKIE[session_name()])){
setcookie(session_name(),'',time() - 3600,'/');
}
通过前面的介绍可以总结出,Session的注销过程共需要4个步骤,在下例中,提供完整的4个步骤代码,运行该脚本就可以关闭Session,并销毁与本次会话相关的所有资源,代码如下所示:
session_start();
//第一步:开启Session并初始化 $_SESSION = array();
//第二步:删除所有Session变量,也可以用unset($_SESSION[xxx])逐个删除 if(isset($_COOKIE[session_name()])){
setcookie(session_name(),'',time() - 3600 ,'/');
}
//第三步:如果使用基于Cookie的Session,使用setcookie()删除包含SESSION ID的Cookie session_destroy();
//第四步:最后彻底销毁Session
使用“$_SESSION = array();”清空$_SESSION数组的同时,也将这个用户在服务器端对应的Session文件内容清空,而使用session_destroy()时,则是将这个用户在服务器端对应的Session文件删除。