php--->cookie和session

cookie和session

cookie和session理解
  • HTTP协议本身是无状态的,这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没有必要纪录彼此过去的行为,每一次请求之间都是独立的,好比一个顾客和一个自动售货机或者一个普通的(非会员制)大卖场之间的关系一样。
  • 但是现实业务中是需要一些认证用户身份的
  • 让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:
    1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。
    2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
    3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。
    由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。
理解cookie机制
  • cookie机制的基本原理就如上面的例子一样简单,但是还有几个问题需要解决:“会员卡”如何分发;“会员卡”的内容;以及客户如何使用“会员卡”。
    • 正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。
    • 而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示,如果某家分店还发行了自己的会员卡,那么进这家店的时候除了要出示麦当劳的会员卡,还要出示这家店的会员卡。
    • 如果不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。
    • 存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式。对于IE,在一个打开的窗口上按Ctrl-N(或者从文件菜单)打开的窗口可以与原窗口共享,而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie;对于Mozilla Firefox0.8,所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的window.open打开的窗口会与原窗口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。
//添加cookie
setcookie("name","zxf",time()+3600);
//数组
 
/$arr = array(1,2,3); 
 $arr_str = serialize($arr); 
 setcookie("a",$arr_str,time()+3600); 
 
//获取cookie
  
var_dump($_COOKIE);
 
//更新cookie
 
setcookie("name","aaa",time()+3600);
 
//删除cookie
 
setcookie("name","",time()-20);
理解session机制
  • session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
  • 当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识- 称为session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来在这次会话中使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端,返回给客户端的同事在响应头信息上会有set-cookie参数,即默认是用cookie保存的。如果客户端没有禁用cookie,保存这个session id的方式可以采用cookie,这样在同次会话中交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。如果浏览器禁止了cookie,必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。
session 存储问题
  • 默认情况下,PHP.ini 中设置的 SESSION 保存方式是 files(session.save_handler = files),,file意为把sesion保存到个临时文件里,如果我们想自定义别的方式保存(比如用数据库),则需要把该项设置为user。
  • 或者是将session保存到关系型数据库中或者非关系型数据库中
session的生存时间
  • 在php.ini里,修改session.gc_maxlifetime=1440 //默认时间
  • Session 还提供了一个函数 session_set_cookie_params(); 来设置 Session 的生存期的,该函数必须在 session_start() 函数调用之前调用:
$lifeTime = 24 * 3600; 
session_set_cookie_params($lifeTime); 
session_start();
$_SESSION["admin"] = true; 
session自动过期回收机制
  • PHP会根据全局变量session.gc_probability/session.gc_divisor(同样可以通过php.ini或者ini_set()函数来修改)的值,来决定是否启动一个GC(Garbage Collector)。默认情况下,session.gc_probability =1,session.gc_divisor =100,也就是说有1%的可能性会启动GC。

  • GC 的工作,就是扫描所有的session信息,用当前时间减去session的最后修改时间(modifieddate),同session.gc_maxlifetime参数进行比较,如果生存时间已经超过gc_maxlifetime,就把该session删除。

gc_maxlifetime无效的情况
  • 在 默认情况下,session信息会以文本文件的形式,被保存在系统的临时文件目录中。在Linux下,这一路径通常为\tmp,在Windows下通常为C:\Windows\Temp。当服务器上有多个PHP应用时,它们会把自己的session文件都保存在同一个目录中。同样地,这些PHP应用也会按一定机率启动GC,扫描所有的session文件。

  • 问题在于,GC在工作时,并不会区分不同站点的session。举例言之,站点A的gc_maxlifetime设置为2小时,站点B的gc_maxlifetime设置为默认的24分钟。当站点B的GC启动时,它会扫描公用的临时文件目录,把所有超过24分钟的session文件全部删除掉,而不管它们来自于站点A或B。这样,站点A的gc_maxlifetime设置就形同虚设了。

  • 找到问题所在,解决起来就很简单了。修改session.save_path参数,或者使用session_save_path()函数,把保存session的目录指向一个专用的目录,gc_maxlifetime参数工作正常了。

gc_maxlifetime 过时没有立马删除
  • 只能保证session生存的最短时间,并不能够保存在超过这一时间之后session信息立即会得到删除。因为GC是按机率启动的,可能在某一个长时间内都没有被启动,那么大量的session在超过gc_maxlifetime以后仍然会有效。解决这个问题的一个方法是,把session.gc_probability/session.gc_divisor的机率提高,如果提到100%,就会彻底解决这个问题,但显然会对性能造成严重的影响。另一个方法是自己在代码中判断当前session的生存时间,如果超出了gc_maxlifetime,就清空当前session。
浏览器禁用cookie时,session使用
  • 客户端(浏览器)禁用了cookie,那么服务器端变不会接收到session id,此时需要显示传递session id了。两种方法:手动通过URL传递session id;隐藏表单传递session id。

  • 可以设置php.ini中
    session.use_trans_sid=1,表示当客户端浏览器禁止cookie的时候,页面上的链接会基于url传递SESSIONID。但是很多人仅仅设置了这一个选项并没有达到效果
    php.ini 文件中还有两个选项
    session.use_cookies=1
    session.use_only_cookies=1
    session.use_cookies表示是否开始基于cookies的session会话
    session.use_only_cookies 表示是否只开启基于cookies的session的会话方式

  • 所以如果想要在浏览器开启cookie的时候用基于cookie的方式,在 未开启cookie的时候使用url的方式就进行如下设置(最常用的方式,推荐)
    在php.ini文件中
    session.use_trans_sid=1
    session.use_only_cookies=0
    session.use_cookies=1
    或者 在php程序中
    ini_set(“session.use_trans_sid”,”1″);
    ini_set(“session.use_only_cookies”,0);
    ini_set(“session.use_cookies”,1);

  • 接受url中 sessionid;(借用session_id()函数来获取/设置 当前会话 ID。

session_id($_REQUEST['session_id']);
session_start();  //session_id()在前
print_r($_SESSION);
session cookie和persistentcookie
  • session cookie针对某一次会话而言,会话结束sessioncookie也就随着消失了,而persistentcookie只是存在于客户端硬盘上的一段文本(通常是加密的),而且可能会遭到cookie欺骗以及针对cookie的跨站脚本攻击,自然不如session cookie安全了。
  • 通常sessioncookie是不能跨窗口使用的,当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的sessionid,这样我们信息共享的目的就达不到了,此时我们可以先把sessionid保存在persistentcookie中,然后在新窗口中读出来,就可以得到上一个窗口SessionID了,这样通过session cookie和persistentcookie的结合我们就实现了跨窗口的session tracking(会话跟踪)。

参考:https://blog.csdn.net/keda8997110/article/details/16922815

posted @ 2018-04-26 09:39  技术-刘腾飞  阅读(138)  评论(0编辑  收藏  举报