首页 > 技术文章 > cookie 和 session 机制

share123 2015-04-13 10:10 原文

cookie机制

    Cookie实际上是Web服务端与客户端(典型的是浏览器)交互时彼此传递的一部分内容,内容可以是任意的,但要在允许的长度范围之内。客户端会将它保存在本地机器上(如IE便会保存在本地的一个txt文件中),由客户端程序对其进行管理,过期的Cookie会自动删除。
    每当客户端访问某个域下某个目录中的网页时,便会将保存在本地并且属于那个域下对应目录的有效Cookie信息附在网页请求的头部信息当中一并发送给服务端。

Cookie文件的保存位置

    Windows 2000/XP:C:\Documents and Settings\\Cookies\目录下。
  (此处的为你登录系统时使用的用户名,在开始->运行中输入cookies便可打开该目录),命名规则为@.txt。

    Win 7:C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Cookies目录下。
  (要去除文件夹选项中的"隐藏受保护的操作系统文件",才能看到)

Cookie文件的格式

IE的Cookie文件实际上就是一个txt文本文件,只不过换行符标记为Unix换行标记(0x0A),由于记事本对Unix换行标记不兼容,打开后内容全在一行看起来不方便,我们可以用EditPlus打开,打开之后,会看到形式如下的内容:

复制代码
1 name
2 value
3 domain/
4 1600
5 1263382784
6 30020896
7 452781968
8 30020892
9 *
复制代码

内容说明:
第一行 Cookie变量名
第二行 Cookie变量值
第三行 该Cookie变量所属域,形如csdn.net/、blog.csdn.net/或blog.csdn.net/lixianlin/
第四行 可选标志
第五行 该Cookie过期时间(FILETIME格式)的高位整数
第六行 该Cookie过期时间(FILETIME格式)的低位整数
第七行 该Cookie创建时间(FILETIME格式)的高位整数
第八行 该Cookie创建时间(FILETIME格式)的低位整数
第九行 Cookie记录分隔符(为一个星号* )

补充一下,第三行中Cookie变量所属域,如csdn.net/,它是一个根域,也就是一级域,表示该Cookie变量在该根域下的所有目录中的网页都有效,不管访问该域下的哪个目录中的网页,浏览器都会将该Cookie信息附在网页头部信息当中发送给服务端;
blog.csdn.net/,是一个二级域,表示该Cookie只对blog这个二级域下目录中的网页有效;
blog.csdn.net/lixianlin/,是一个二级域下的目录,只有访问blog这个二级域下lixianlin这个目录中的网页时,才会把该Cookie信息附在请求头部信息当中发送给服务端。
需要指出的是csdn.net/和www.csdn.net/并不相同,前者是根域,后者是一个二级域,只是人们习惯了www这样的形式,所以大多数的网站首页都用 http://www.xxx.com/这样的二级域来访问。

附FILETIME格式定义:
typedef struct _FILETIME {
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;

 

session机制

看下边先研究SESSION是如何启动的,当打开IE浏览网站后会发出一个指令请求SESSIONID以及对各个类型数据的下载许可,如图片、声音以及FLASH。 

数据实际传输内容:IE到服务器 

复制代码
  GET / HTTP/1.1 
  Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */* 
  Accept-Language0: zh-cn 
  Accept-Encoding: gzip, deflate 
  User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) 
  Host: www.souzz.net 
  on: Keep-Alive 
复制代码

服务器会返回一个没有被使用的SESSIONID让IE使用,当时IE就对返回SESSIONID做存储并同时返回相关页面的下载数据:服务器到IE 

  HTTP/1.1 200 OK 
  Server: Microsoft-IIS/5.0 
  Date: Sun, 30 Nov 2003 16:41:51 GMT 
  Content-Length: 21174..Content-Type: text/html 
  Set-Cookie: ASPSESSIONIDCACBBBRT=IBOMFONAOJFEEBHBPIENJFFC; path=/ 
  Cache-control: private

然后就是页面HTML代码,此时这个IE程序(不是客户机)的SESSIONID就为IBOMFONAOJFEEBHBPIENJFFC。
而当IE在访问任何这个站点的ASP程序的时候,就会把IBOMFONAOJFEEBHBPIENJFFC发送给服务器,服务器就会知道IBOMFONAOJFEEBHBPIENJFFC是表示你而在服务器上设置SESSION("name")="name"。
完全可以看成是SESSION("IBOMFONAOJFEEBHBPIENJFFC")("name")="name" 或者 SESSION(SESSIONID)("name")="name" 这样,SESSION就区分开用户了。 
而当服务器反馈这个ID的时候会看这个ID有没有被使用。如果有就再换一个,反正不会让你重复。
如果想模拟某人的SESSION的ID来进行欺骗是可以的,不过要获取到对方IE传输信号,并且在保证当时这个SESSIONID没有被取消的情况下才可能实施。

复制代码
session_start();

//这种方法是将原来注册的某个变量销毁
unset($_SESSION["admin"]);

//这种方法是销毁整个 Session 文件
session_destroy(); 
复制代码


Session 是如何来判断客户端用户的呢?它是通过 Session ID 来判断的,什么是 Session ID,就是那个 Session 文件的文件名,Session ID 是随机生成的,因此能保证唯一性和随机性,确保 Session 的安全。一般如果没有设置 Session 的生存周期,则 Session ID 存储在内存中,关闭浏览器后该 ID 自动注销,重新请求该页面后,重新注册一个 Session ID。

如果客户端没有禁用 Cookie,则 Cookie 在启动 Session 会话的时候扮演的是存储 Session ID 和 Session 生存期的角色。

我们来手动设置 Session 的生存期:

session_start();
//保存一天
$lifeTime = 24 * 3600;
setcookie(session_name(), session_id(), time() + $lifeTime, "/"); 

其实 Session 还提供了一个函数 session_set_cookie_params(); 来设置 Session 的生存期的,该函数必须在 session_start() 函数调用之前调用:

//保存一天
$lifeTime = 24 * 3600;
session_set_cookie_params($lifeTime);
session_start();

如果客户端使用 IE 6.0 , session_set_cookie_params(); 函数设置 Cookie 会有些问题,所以我们还是手动调用 setcookie 函数来创建 cookie。

假设客户端禁用 Cookie 怎么办?
没办法,所有生存周期都是浏览器进程了,只要关闭浏览器,再次请求页面又得重新注册 Session。
那么怎么传递 Session ID 呢?
通过 URL 或者通过隐藏表单来传递,PHP 会自动将 Session ID 发送到 URL 上,URL 形如:http://www.openphp.cn/index.php? ... e5b44cfa01d49cf9669,其中 URL 中的参数 PHPSESSID 就是 Session ID了,我们可以使用 $_GET 来获取该值,从而实现 Session ID 页面间传递。

 

Session的存储方式

session其实分为 客户端Session 和 服务器端Session。

当用户首次与Web服务器建立连接的时候,服务器会给用户分发一个 SessionID作为标识。SessionID是一个由24个字符组成的随机字符串。用户每次提交页面,浏览器都会把这个SessionID包含在 HTTP头中提交给Web服务器,这样Web服务器就能区分当前请求页面的是哪一个客户端。这个SessionID就是保存在客户端的,属于客户端Session。

其实客户端Session默认是以cookie的形式来存储的,所以当用户禁用了cookie的话,服务器端就得不到SessionID。这时我们可以使用url的方式来存储客户端Session。也就是将SessionID直接写在了url中,当然这种方法不常用。

在PHP中可以通过定义session_set_save_handler,将服务器session数据存储在不同的介质上,比如存储在文件里,apc或memcache缓存中,或存储在数据库里。可对统计在线人数,或踢除特定会员的登陆状态等等。

 

cookie和session区别

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。(默认都是以文件方式存储)

2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。

3、单个cookie在客户端的限制是4K,每个域的cookie不能超过20个,session仅受操作系统允许的最大文件尺寸限制。

 

自己总结

1、cookie作用域问题,当你设置的cookie,其它页面取不到值时,可考虑这方面原因。
    可设置下path参数,参考"http://hi.baidu.com/brucehawking/item/ecbcb04d71d288e1bdf451d1"
    贴上我的js设置cookie函数,这里"path=/",表示作用域为服务器的localhost下,可自行更改。

复制代码
/**
 * 设置cookie
 * @param c_name cookie名
 * @param value cookie值
 * @param expiredays cookie过期时间
 * @return
 */
function setCookie(c_name, value, expiredays) {
    var exdate = new Date();
    exdate.setDate(exdate.getDate() + expiredays);
    document.cookie = c_name+ '=' +escape(value) + ';path=/;' + ((expiredays == null) ? '' : 'expires='+exdate.toGMTString());
}
复制代码

2、在同一个服务器上的所有网站会共用session,所以要注意当开发的多个项目在同一个服务器上时,session的命名要考虑到避免冲突,最好每个项目中的session都加个前缀。

3、销毁session时也要注意,不要销毁整个session,避免将同服务器下的其它站点的session销毁掉。

unset($_SESSION['[prefix_username']); //不要unset($_SESSION);

 

推荐阅读