PHP会话控制:Session与Cookie详解
本文介绍了PHP会话控制,主要阐述以下几点内容:
•会话控制的产生背景/概念
•cookie的维护与生命周期(有效时间)
•session的维护与生命周期(回收机制)
•cookie与session之间的区别与联系
•问题1:禁用cookie后session为什么会失效?
•问题2:IE浏览器下丢失session,每次刷新页面,都会生成新的sessionID(Firefox浏览器正常)
•session、cookie简单实例
理解会话控制的概念
理解一个概念就需要理解他的背景及产生的原因,这里引入WEB环境及其HTTP协议。会话控制产生的背景:
阅读过HTTP协议相关资料的同学都会知道HTTP协议是WEB服务器与客户端(浏览器)相互通信的协议,它是一种无状态协议,所谓无状态,指的是不会维护http请求数据,http请求是独立的,不持久的。也就是说HTTP协议没有一个内建的机制来维护两个事务之间的状态或者说是关系吧。当一个用户在请求一个页面后再去请求另外一个页面时,HTTP将无法告诉我们这两个请求是否来自同一个用户。
由此我们就会觉得很奇怪了,平时我们在论坛逛帖子或电商网站购物时,只要我们在这个站点内,不论我们怎么跳转,从一个页面跑到另一个页面,网站总会记得我是谁,比如告诉你购买了哪些东西。这是怎么做到的呢,估计大家猜到了,这就是运用了HTTP会话控制。在网站中跟踪一个变量,通过对变量的跟踪,使多个请求事物之间建立联系,根据授权和用户身份显示不同的内容、不同页面。
PHPSession会话控制:
PHP的session会话是通过唯一的会话ID来驱动的,会话ID是一个加密的随机数字,由PHP生成,在会话的生命周期中都会保存在客户端。我们知道客户端(也就是浏览器)保存数据的地方只有cookie,所以PHP的会话ID一般保存在用户机器的cookie中。了解cookie后我们知道,浏览器是可以禁用cookie的,这样会话就会失效。所以PHP会话控制还有一种模式,就是在URL中传递会话ID。如果在浏览网站时我们稍加留心的话,有些URL中有一串看起来像随机数字的字符串,那么其实很有可能就是URL形式的会话控制。
讲到这里,有些人可能会有疑问了,客户端只是保存一个会话ID,那么会话控制中保存的会话变量比如你购物时买的物品列表等,它们是存放在哪个地方的呢?很显然,会话变量是在服务器端使用的,那么这些会话变量必定存放在服务器端。默认情况下,会话变量保存在服务器的普通文件中(也可以自己配置使用数据库来保存,可以Google一下),会话ID的作用就像是一把钥匙,在服务器端保存会话的文件中找到该会话ID对应的会话变量,比如购买物品的列表。
那么会话控制的整个过程可能就像这个样子,用户登录或者第一次浏览某个站点的页面时,该站点会生成一个PHP的会话ID并通过cookie发送到客户端(浏览器)。当用户点击该站点的另一个页面时,浏览器开始连接这个URL。在连接之前,浏览器会先搜索本地保存的cookie,如果在cookie中有任何与正在连接的URL相关的cookie,就将它提交到服务器。而刚好在登陆或第一次连接时,已经产生了一个与该网站URL相关的cookie(保存的会话ID),所以当用户再次连接这个站点时,站点就可以通过这个会话ID识别出用户,从服务器的会话文件中取出与这个会话ID相关的会话变量,从而保持事务之间的连续。
接下来我们了解下两个重要的概念:cookie和session
关于cookie的维护与生命周期
cookie是在服务器端被创建并写回到客户端浏览器,浏览器接到响应头中关于写cookie的指令则在本地临时文件夹中。
创建了一个cookie文件,其中保存了你的cookie内容,cookie内容的存储是键值对的方式,键和值都只能是字符串。例如:
文件:Cookie:administrator@localhost/
内容格式:voteID100101localhost/15361167667230343893360385046430343691*
cookie的创建:
setcookie()函数设置cookie,函数原型如下 setcookie(name,value,expire,path,domain);
注释:cookie标题头必须在发送其他标题头之前发送,否则就无效(这是cookie的限制,而不是PHP的限制)。在发送cookie时,cookie的值会自动进行URL编码,在取回时进行自动解码(为防止URL编码,请使用setrawcookie()取而代之)。
cookie的维护:
cooke有四个标识符:cookie的name,domain,path,secure标记。要想在将来改变这个cookie的值,需要发送另一个具有相同cookiename,domain,path的Set-Cookie消息头,这将以一个新
的值来覆盖原来cookie的值。然而,如果仅仅只是改变这些选项的某一个也会创建一个完全不同的cookie,如只是更改了name值。
cookie失效时间:
可以设置过期时间,如果不设置则是会话级别的,即关闭浏览器就会消失。当cookie创建时包含了失效日期,这个失效日期则关联了以name-domain-path-secure为标识的cookie。要改变一个cookie的失效日期,你必须指定同样的组合。当改变一个cookie的值时,你不必每次都设置失效日期,因为它不是cookie标识信息的组成部分。例如:
setcookie(vote,$id+1,time()+3600*24); setcookie(vote,$id);
在cookie上的失效日期并没有改变,因为cookie的标识符是相同的。实际上,只有你手工的改变cookie的失效日期,否则其失效日期不会改变。这意味着在同一个会话中,一个会话cookie可以变成一个持久化cookie(一个可以在多个会话中存在的),反之则不可。为了要将一个持久化cookie变为一个会话cookie,你必须删除这个持久化cookie,这只要设置它的失效日期为过去某个时间之后再创建一个同名的会话cookie就可以实现。
需要记得的是失效日期是以浏览器运行的电脑上的系统时间为基准进行核实的。没有任何办法来来验证这个系统时间是否和服务器的时间同步,所以当服务器时间和浏览器所处系统时间存在差异时这样的设置会出现错误。
cookie自动删除:
cookie会被浏览器自动删除,通常存在以下几种原因:
会话cooke(Sessioncookie)在会话结束时(浏览器关闭)会被删除
持久化cookie(Persistentcookie)在到达失效日期时会被删除,如:
setcookie("vote","",time()-3600);
如果浏览器中的cookie限制到达,那么cookies会被删除以为新建cookies创建空间。
关于session的维护与生命周期
Session是由应用服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器创建生成一个唯一的sessionID,用该sessionID为标识符来存取服务器端的Session存储空间,在会话期间,分配给客户端的唯一sessionID,用来标识当前用户,与其他用户进行区分。通过SessionID接受每一次访问的请求,从而识别当前用户,跟踪和保持用户的具体资料,以及session变量,可在session中存储数字或文字资料.比如session_name.这些信息都保存在服务器端。当然,sessionID也可以作为会话信息保存到数据库中,进行session持久化。这样可以跟踪用户的登陆次数、在线与否、在线时间等从而维护HTTP无状态事物之间的关系。session的内容存储是键值对的列表,键是字符串类型,session的存储更方便,值可以是对象。
在session会话期间,session会分别保存在客户端和服务器端两个文件,客户端可以是cookie方式保存的sessionID(默认的保存方式)或通过url字符串形式传递。服务器端一般以文本的形式保存在指定的session目录中。在服务器端我们可以通过session.use_cookies来控制客户端使用哪一种保存方式。如果定义为cookie保存方式,我们可以通过session.cookie_lifetime(默认值0,闭浏览器就清除)来控制被保存在client上的cookie的有效期。而如果客户端用cookie方式保存的sessionID,则使用“临时”的cookie保存(cookie的名称为PHPSESSID,通过Firebug你可以了解到详细的信息,该名称你可以通过php.inisession.name进行更改),用户提交页面时,会将这一SessionID提交到服务器端,来存取session数据。这一过程,是不用开发人员干预的。
Session的创建:
session_start() //开始一个会话及返回已经存在会话
功能:初始化Session,也标识着session生命周期的开始。要使用session,必须初始化一个session环境,有点类似于OOP概念中调用构造函数构创建对象实例一样。session初始化操作,声明一个全局数组$_SESSION,映射寄存在内存的session数据。如果session文件已经存在,并且保存有session数据,session_start()则会读取session数据,填入$_SESSION中,开始一个新的session生命周期。
说明:这个函数没有参数,且返回值为true,如果使用基于cookie的sessin,那么在session_satrt()之前不能有任何的输出,包括空白
如果在php.ini中session.auto_start=1开启,则在每个页面执行session_start(),不需要手工设置,该选项默认为关闭状态,开启后不能将对象放入session中。
SessionID:
用户session唯一标识符,随机生成的一串字符串,具有唯一性,随机性。主要用于区分其它用户的session数据。用户第一次访问web页面的时候,php的session初始化函数调用会分配给当前来访用户一个唯一的ID,也称之为session_id。
获得session_id():
echo$_COOKIE['PHPSESSID'].'<br/>'; echo$_COOKIE[session_name()].'<br/>'; echosession_id().'<br/>';
session数据:
我们把需要通过session保存的用户状态信息,称为用户session数据,也称为sessiondata。一般是在当前session生命周期内,相应的$_SESSION数据。一旦调用了session_start()初始化session,就意味着开始了一个session生命周期。也就是宣布了,可以使用相关函数操作$_SESSION来管理session数据。这个session生命周期产生的数据并没有实时地写入session文件,而是通过$_SESSION变量寄存在内存中。$_SESSION是一个全局变量,类型是Array,映射了session生命周期的session数据,寄存在内存中。在session初始化的时候,从session文件中读取数据,填入该变量中。在session(生命周期)结束时,将$_SESSION数据写回session文件。
注册一个会话变量:
从PHP4.1以后,会话变量保存在超级全局数组$_SESSION中。要创建一会话变量,只需要在数组中设置一个元素,如:
$_SESSION['domain']=blog.jb51.net; $_SESSION['poll']=$_SESSION[poll]+1;
使用一个会话变量:
echo$_SESSION['blogdomain']; //打印出blog.jb51.net,使用会话前必须先使用session_start()函数启动一个会话
注销Session变量/销毁会话:
unset($_SESSION); //销毁单个会话变量 如:unset($_SESSION['blogdomain']); #unset($_SESSION)这个函数会将全局变量$_SESSION销毁,而且还没有可行的办法将其恢复。用户也不再可以注册$_SESSION变量,所以此函数千万不可使用。
session_unset();//多项释放。将所有登陆在session文件里的变量释放出来 #在session生命周期,从当前session中注销全部session数据,让$_SESSION成为一个空数组。它与unset($_SESSION)的区别在于:unset直接删除$_SESSION变量,释放内存资源;另一个区别在于,session_unset()仅在session生命周期能够操作$_SESSION数组,而unset()则在整个页面(page)生命周期都能操作$_SESSION数组。session_unset()同样不进行任何IO操作,只影响$_SESSION数组。
$_SESSION=array(); //多项释放,释放所有登录在$_SESSION参数里的变量
session_destroy(); #当使用完一个会话后,首先应该注销所有的变量,然后再调用该函数结束当前的会话,并清空会话中的所有资源,删除服务器上的session文件.该函数不会unset(释放)和当前session相关的全局变量,也不会删除客户端的sessioncookie #如果说session_start()初始化一个session的话,而它则注销一个session。意味着session生命周期结束了。在session生命周期结整后,session_unset,$_SESSION['domain']都将不能操作$_SESSION数组,而$_SESSION数组依然可以被unset()等函数操作。这时,session意味着是未定义的,而$_SESSION依然是一个全局变量,他们脱离了关映射关系。 通过session_destroy()注销session,除了结束session生命周期外,它还会删除sesion文件,但不会影响当前$_SESSION变量。即它会产生一个IO操作。