session和cookie的内部原理

来源:互联网 发布:续命八丸 知乎 编辑:程序博客网 时间:2024/05/20 15:36

cookie的工作流程:
客户端访问服务器,服务器调用response.addCookie()方法,产生响应时,会产生set-cookie响应头,将cookie文本发送给客户端,客户端会将cookie文本保存起来,当客户端再次请求服务器时,会产生cookie请求头,将之前服务器发送的cookie信息,再发送给服务器,服务器就可以根据cookie信息跟踪客户端的状态。
cookie的工作原理:
a.服务器通过随着响应发送一个http 的Set-Cookie 头,在客户机中设置一个cookie(多个cookie 要多个头)。 
b.客户端自动向服务器端发送一个http 的cookie 头,服务器接收读取。 
C.如果是持久化cookie,浏览器将在客户端的磁盘上创建一个cookie 文件,并在里面写入:
    TestCookie=something from somewhere; 
    这一行就是我们用 setcookie('TestCookie','something   from  somewhere','/'); 的结果。也可以用 
    header('Set-Cookie: TestCookie=something from somewhere; path=/');的结果。

cookie的分类:
1 存放在客户端浏览器的缓存中,当浏览器不关闭,cookie信息一起存在,浏览器一关闭,cookie消失
2 存放在客户端的文件中,并可以设置cookie过期时间,过期时间之内,即使浏览器关闭,也可以将cookie信息发送给服务器,超过过期时间,cookie消失。


cookie信息是以文本方式(不一定是txt文件,大多是二进制文件)存放在客户端的,所以容易引起一些安全隐患,所以不要把隐秘信息以cookie方式保存。


cookie相关操作(新建+读取+删除)
设置cookie:
    a.可以用 setcookie()

$value = 'something from somewhere';  setcookie("TestCookie", $value); /* 简单 cookie设置 */   setcookie("TestCookie", $value, time()+3600); /* 有效期 1个小时 */   setcookie("TestCookie", $value, time()+3600, "/~rasmus/",".example.com", 1); /* 有效目录 /~rasmus,有效域名 example.com及其所有子域名 */ 

设置多个 cookie  变量:setcookie('var[a]','value');  用数组来表示变量,但他的下标不用引号。这样就可以用$_COOKIE[‘var’][‘a’]来读取该COOKIE 变量。


  b. 使用 header()设置cookie;
     header("Set-Cookie: name=$value[;path=$path[;domain=xxx.com[;...]]");

$value = 'something from somewhere';   header("Set-Cookie:name=$value"); 

读取cookie:

print $_COOKIE['TestCookie'];  

删除cookie

    只需把有效时间设为小于当前时间,和把值设置为空。例如:

setcookie("name", "", time()-1);  



//////////////////////////////////////////

session的工作流程:
当用户第一次访问站点时,PHP会用session_start()函数为用户创建一个sessionID,这就是针对这个用户的唯一标识,每一个访问的用户都会得到一个自己独有的session ID,这个session ID会存放在响应头里的cookie中,之后发送给客户端。这样客户端就会拥有一个该站点给他的session ID

当用户第二次访问该站点时,浏览器会带着本地存放的cookie(里面存有上次得到的session ID)随着请求一起发送到服务器,服务端接到请求后会检测是否有session ID,如果有就会找到响应的session文件,把其中的信息读取出来;如果没有就跟第一次一样再创建个新的。

通常站点的退出功能,实际上就是调用一下session_destroy()函数(也有可能更复杂些),把该用户的session文件删除,再把用户的cookie清除。这样客户端和服务端就算没有联系了。

图中的红框部分就是一次完整的HTTP请求,因为HTTP是无状态的,所以一次请求完成后客户端和服务端就不再有任何关系了,谁也不认识谁。但由于一些需要(如保持登录状态等),必须让服务端和客户端保持联系,session ID就成了这种联系的媒介了。



session的工作原理:

最最核心的概念就是:网页间跳转的额外数据,保存在服务器,用一个id标识,浏览器要维持session,需要每次提交都带上这个id.

session使用过期时间设为0cookie,并且将一个称为session ID的唯一标识符(一长串字符串),在服务器端同步生成一些 session文件(可以自己定义 session的保存类型),与用户机关联起来。web应用程序存贮与这些 session 相关的数据,并且让数据随着用户在页面之间传递.访问网站的来客会被分配一个唯一的标识符,即所谓的 SESSION ID。它要么存放在客户端的cookie,要么经由  URL  传递.SESSION 允许用户注册任意数目的变量并保留给各个请求使用。当来客访问网站时,PHP会自动(如果session.auto_start被设为1)或在用户请求时(由session_start()明确调用或session_register() 暗中调用)检查请求中是否发送了特定的SESSION ID。如果是,则之前保存的环境就被重建。

session ID的传递有两种方式:

a.通过 cookie 传送 SESSION ID

使用 session_start()调用 session,服务器端在生成session文件的同时,生成变量session name(默认为PHPSESSID)及其对应值为唯一标识用户的session ID(哈希值)(服务端和客户端保存着同样的session ID信息,这就是两者保持联系的钥匙。)并向客户端发送该变量session name(默认为PHPSESSID)及其对应值为唯一标识用户的session ID(哈希值)。服务器端将通过该 cookie 与客户端进行交互。一个被sessionID唯一标识后的用户创建的各种session变量及对应值经php内部序列化后保存在服务器机器上的文本文件中,和客户端的变量名默认情况下为PHPSESSID 的cookie 进行对应交互.即服务器自动发送了http 头:

header('Set-Cookie: session_name()=session_id();  path=/'); 或setcookie(session_name(),session_id()); 

即:header('Set-Cookie: PHPSESSID=pcnnftkmkm9nua33uot8fmb8a3;  path=/'); 或setcookie(PHPSESSID,pcnnftkmkm9nua33uot8fmb8a3); 

当从该页跳转到的新页面并调用session_start()后,PHP 将检查与给定ID 相关联的服务器端存贮的session数据,如果没找到,则新建一个数据集。

 

b.通过URL传送 session ID

只有在用户禁止使用cookie的时候才用这种方法,因为浏览器cookie 已经通用,为安全起见,可不用该方法。 
    <a href="p.php?<?php print session_name()?>=<?php print session_id() ?>">xxx</a>,也可以通过 POST 来传递session 值。

、、、、、、、、、、、、、、、、、、、、、

如果客户端禁止使用cookie,可以使用如下办法:

a、设置php.ini中的session.use_trans_sid= 1或者编译时打开打开了--enable-trans-sid选项,让PHP自动跨页传递session id。 
b、手动通过URL传值、隐藏表单传递session id。 
c、用文件、数据库等形式保存session_id,在跨页过程中手动调用。

link:http://apps.hi.baidu.com/share/detail/41643457

 

session也可以在禁用cookie的情况下使用:
php.ini中session.use_cookies=1,改为0,session会保存在服务器端,而不是客户端的cookie。

可以通过session.save_path来查看服务器的session存放位置

session相关操作(新建+读取+删除)

设置session:

// page1.php   session_start();   echo 'Welcome to page #1';   /* 创建 session变量并给 session变量赋值 */   $_SESSION['favcolor'] = 'green';   $_SESSION['animal'] = 'cat';   $_SESSION['time'] = time();  // 如果客户端使用 cookie,可直接传递 session到page2.php   echo '<br /><a href="page2.php">page 2</a>';  // 如果客户端禁用 cookie   echo '<br /><a href="page2.php?' . SID . '">page 2</a>';   /* 默认php5.2.1下,SID只有在 cookie被写入的同时才会有值,如果该 session   对应的 cookie 已经存在,那么 SID将为 (未定义)空   */   

读取session

//page2.php   session_start();  print $_SESSION['animal']; // 打印出单个 session   var_dump($_SESSION); // 打印出page1.php传过来的 session值  



删除session

session_destroy();      // 第一步: 删除服务器端 session文件,这使用   setcookie(session_name(),'',time()-3600);      //  第 二 步 : 删 除 实 际 的session:  $_SESSION = array();     // 第三步: 删除$_SESSION全局变量数组 

------------------------------------------------------------------------------------------------------------------------------

一个简单的示例:

session_start();  if (isset($_SESSION['test_sess'])){   $_SESSION['test_sess']++;  }else{   $_SESSION['test_sess'] = 0;  }  echo $_SESSION['test_sess'];  

使用的一个叫做httplookhttp包嗅探工具来抓包:

 

第一次请求服务器:

GET /test.php HTTP/1.1 Accept: */* Referer: http://localhost/ Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322) Host: localhost Connection: Keep-Alive

 

服务器第一次返回:

HTTP/1.1 200 OK Date: Fri, 26 Aug 2005 07:44:22 GMT Server: Apache/2.0.54 (Win32) SVN/1.2.1 PHP/5.0.4 DAV/2 X-Powered-By: PHP/5.0.4 Set-Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 1 Keep-Alive: timeout=15, max=99 Connection: Keep-Alive Content-Type: text/html; charset=utf-8 Content-Language: Off

第二次请求服务器:

GET /test.php HTTP/1.1 Accept: */* Referer: http://localhost/ Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322) Host: localhost Connection: Keep-Alive Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3

服务器第二次返回:

HTTP/1.1 200 OK Date: Fri, 26 Aug 2005 07:44:23 GMT Server: Apache/2.0.54 (Win32) SVN/1.2.1 PHP/5.0.4 DAV/2 X-Powered-By: PHP/5.0.4 Set-Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 1 Keep-Alive: timeout=15, max=98 Connection: Keep-Alive Content-Type: text/html; charset=utf-8 Content-Language: Off

仔细对比这些输出,第二次请求比第一次请求多出来的就是: 
Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3 

这个header将会向服务器发送一个cookie信息,告诉服务器我有一个cookie,名字叫PHPSESSID,内容是bmmc3mfc94ncdr15ujitjogma3 
这个cookie是怎么来的呢?看第一次服务器返回的信息里边有: 
Set-Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3; path=/ 

这是服务器向客户端浏览器写一个cookie,名字是PHPSESSID,值是bmmc3mfc94ncdr15ujitjogma3,这个值实际就是所谓的session_id 
继续看第二次向服务器发出的请求,仍然向服务器发送了PHPSESSID这个cookie 

可以得到以下结论: 
1
、只要使用了session,就会通过cookie的方式向客户端浏览器发送session 
2、每次向服务器发出请求的时候,本地浏览器会把cookie附带在请求信息中


session常见问题

一、session是怎么保存的?怎么去查看其内容?

session是以文件的形式保存的。php.ini中有个配置项--session.save_path="";这个里面填写的路径,将会使session文件保存在该路径下。session文件的命名格式是:"sess_[PHPSESSID的值]"。每一个文件,里面保存了一个会话的数据。其实只要使用代码$_SESSION['user_id'] = $value;就会促发phpsession机制,结果往对应的session文件中写入一个值。

二、session.save_path路径下这么多的session文件,php是如何确定要调用哪个session文件的

php是依据,一个名为PHPSESSIDcookie,根据它的值,确定要调用哪个session文件的。去浏览器中,可以看到一个cookie名为PHPSESSID,假如它的值为"sess_adbjsf2q1ass26oootd163sf84",那么,当访问服务器的时候,就会调用session目录下名为"sess_sess_adbjsf2q1ass26oootd163sf84"的文件。其实,PHPSESSID就是一个会话id,以此来确定,哪个是你的会话数据。

以下是在浏览器查看cookie所看到的


cookie的名字PHPSESSID是可以改的,php.ini session.name = PHPSESSID就是设置该cookie的名字。php.ini中有个配置项--session.save_path= "";这个里面填写的路径,将会使session文件保存在该路径下。

 

三、说说sessioncookie有关联的地方

PHPSESSID这个cookie有绑定关系。其他,不管你设置什么cookie,使用session的时候是不会用到这些值的。也无法获取到。比如同步登陆,设置即使设置了cookie,而你的应用是依据session判断是否为登陆状态的(事实上也必须如此,因为session保存在服务器端,安全性更高,哪个依据cookie认为你已经登陆,那么很惨)。所以,这样的情况就会出现,即使成功设置了cookie。也还是不能同步登陆。

四、经常遇到的现象:为什么删除一个session文件,之后生成一个session文件,新的文件名字还是与原来一样?(但是文件里面的内容会变化)

理解到session文件的命名规则是:“sess_PHPSESSID。那么,就很容易明白了。因为,客户端存在cookiePHPSESSID。客户端发送请求后,会将该cookie发送给服务器(php可以使用$_COOKIE['PHPSESSID']看到其内容),这样的话,还是会根据PHPSESSID生成一个session文件的。

五、如何查看session文件中的session值?

我在开发中发现,如果仅仅依靠session_start()$_SESSION['user_id']这样的代码,去调试,还不够全面的了解问题所在。比如,我想知道,session_start()到底在完成哪些操作?如果,想动态,实时知道session的值是如何被改写的,打开一个session文件,查看是很了然的。原来,里面就是保存的是一些被序列化后的值。也明白一个知识点,"php圣经"中讲解session的时候,提到session值做被序列化了。下面看到的session内容就是被序列化了。

打开一个session文件,内容如下:

cityID|i:0;cityName|s:3:"all";fanwe_lang|s:5:"zh-cn";fanwe_currency|a:4:{s:2:"id";s:1:"1";s:6:"name_1";s:9:"人民币";s:4:"unit";s:3:"¥";s:5:"radio";s:6:"1.0000";}_fanwe_hash__|s:32:"77c18770c6cb5d89444c407aaa3e8477";


读取规则如下

1、每一个session的值是以分号";"分开的。比如“cityID|i:0;”就是一个完整的session值结束

2、里面的读取规则:符号“|”前面表示session名称。符号后面是该session的具体信息。包括:数据类型,字符长度,内容。上面第二个就相当于使用如下php代码访问:$_SESSION['cityName'],后面的s表示数据值的长度,3表示字符长度,变量值为all

3.一个session可以保存一个数组。符号{}表示数组的内容。上面的花括号{}$_SESSION['fanwe_currency']所保存的内容。要想查看id的值,就使用代码:$_SESSION['fanwe_currency']['id']

 

 

六、怎么样理解session_start等函数所做的实际操作是什么?

 

我是这样理解的:session_start,可以看成是创建一个session文件。假如有原来的session文件,或许没有创建。引入一个。往session文件中写值,那是代码“$_SESSION['']=""; 赋值所完成的操作。
session_start()
生成一个新的session文件名时。会判断是否存在cookie名为PHPSESSID的值。如果存在,那么就会按照它的值,组合成一个文件名"sess_[phpcookie]"。所以,在目录下,老是能够看到之前删除过的session文件名。如果将浏览器中对应的cookie(PHPSESSID)删掉。那么就不会生成同样的名字了。如果不存在名为PHPSESSIDcookiephp所做的估计为:先发送一个cookie,然后按照cookie的值生成一个(我可以在浏览器中马上看到一个名为PHPSESSIDcookie)

其实,现在也更加深刻地理解了一个知识:在调用session_start()之前不能有任何输出。有输出就会报错。

session_start()已经封装了发送cookie的操作(发送一个名称为PHPSESSIDcookie到浏览器)。涉及到http的一个原理:头部信息必须在内容之前发送才行。所以,使用echo '内容';

header('Content-type:text/xml; charset=gb2312');//头部信息,不算内容

可以这样认为:session_start()内部已经进行了一次发送头部动作。所以之前不能有任何输出内容。
手册中的英文大致是这样说的:创建一个session,或者恢复当前一个session(基于request请求传递的session id,这里应该值的就是http请求时传递的名为PHPSESSIDcookie)

 

七、只要是同一个用户的操作。导航程序访问记录和团购程序访问的记录都是保存在同一个session文件中。如果是不同的域呢?假如用户访问cs.test.comdaohang.test.com,两方程序都设置了session。那么session的结果保存在同一个session文件中吗?

是的!因为:服务器是统一管理session文件的存放的。而php引擎是根据phpsessionid的值确定要操作哪个session文件。session文件名的格式是:"sess_[phpcookie]"。依次寻找对应的session文件(于是在浏览器查看名为PHPSESSIONIDcookie,过期时间是在会话结束后)。所以,只要cs.test.comdaohang.test.com使用的是同一台服务器。就算是不同的域,两方程序都设置了session。那么session的结果保存在同一个session文件中。

这样的话,假如是多台服务器的情况。那么就不得不将session保存在数据库中去。这样实现session共享

http://www.birdol.com/php/4272.html

http://blog.csdn.net/wangzhkai/article/details/4187496

http://www.cnblogs.com/wangtao_20/archive/2011/02/16/1955659.html

http://blog.csdn.net/fangaoxin/article/details/6954925










1 0
原创粉丝点击