PHP session与cookie

PHP session与cookie的实现原理

PHP SESSION原理

session是在服务器端保持用户会话数据的一种方法,对应的cookie是在客户端保持用户数据。HTTP协议是一种无状态协议,服务器响应完后就失去了与浏览器的联系,cookie引入浏览器,使得数据跨越页面交换。

首先客户端和服务器端建立一一联系,每个客户端都有一个唯一标识,这样服务器才能识别出来。建议唯一标识的方法有两种:cookie或者通过GET方式指定。默认配置的PHP使用session的时会建立一个名叫”PHPSESSID”的cookie(可以通过php.ini修改session.name值指定),如果客户端禁用cookie,你也可以指定通过GET方式把session id传到服务器(修改php.ini中session.use_trans_sid等参数)。

客户端将session id传递到服务器,服务器根据session id找到对应的文件,读取的时候对文件内容进行反序列化就得到session的值,保存的时候先序列化再写入。

事实就是这样,如果服务器不支持session或者你想自定义session,完全可以DIY,通过PHP的uniqid生成永不重复的session id,然后找个地方存储session的内容即可,还可以把session存储在MySQL数据库中。

所谓的session其实就是客户端一个session id,服务器端一个session file,新建session时,告诉服务器要生成一个cookie以及准备好session文件,要不然你的session内容怎么存;读取session时告诉服务器,赶紧根据session id把session文件反序列化。

session影响系统性能

session在大访问量网站上确实影响系统性能,影响性能的原因之一由文件系统设计造成,在同一个目录下超过10000个文件时,文件的定位将非常耗时,PHP支持session目录hash,我们可以通过修改php.ini中session.save_path =“2;/path/to/session/dir”,那么session将存储在两级子目录中,每个目录有16个子目录[0~f],不过好像PHPsession不支持创建目录,你需要事先把那么些目录创建好 。

还有一个问题就是小文件的效率问题,一般我们的session数据都不会太大(1~2K),如果有大量这样1~2K的文件在磁盘上,IO效率肯定会很差。可以通过缓存memcache和mysql数据库提供效率。

session的同步

前端可能有很多台服务器,用户在A服务器上登录了,种下了session信息,然后访问网站的某些页面没准跳到B服务器上去了,如果这个时候B服务器上没有session信息又没有做特殊处理,可能就会出问题了。

session同步有很多种,如果你是存储在memcached或者MySQL中,那就很容易了,指定到同样的位置即可,如果是文件形式的,你可以用NFS统一存储。

(NFS是Network File System的简写,即网络文件系统.网络文件系统是FreeBSD支持的文件系统中的一种,也被称为NFS. NFS允许一个系统在网络上与他人共享目录和文件。通过使用NFS,用户和程序可以像访问本地文件一样访问远端系统上的文件。)

还有一种方式是通过加密的cookie来实现,用户在A服务器上登录成功,在用户的浏览器上种上一个加密的cookie,当用户访问B服务器时,检查有无session,如果有当然没问题,如果没有,就去检验cookie是否有效,cookie有效的话就在B服务器上重建session。这种方法其实很有用,如果网站有很多个子频道,服务器也不在一个机房,session没办法同步又想做统一登录那就太有用了。

当然还有一种方法就是在负载均衡那一层保持会话,把访问者绑定在某个服务器上,他的所有访问都在那个服务器上就不需要session同步了。

<?php

session_start();

if(isset($_SESSION[‘test_sess’])){

     $_SESSION[‘test_sess’]++;

}else{

     $_SESSION[‘test_sess’] = 0;

}

echo$_SESSION[‘test_sess’];

?>;

第一次请求服务器:

GET/test.php HTTP/1.1

Accept:*/*

Referer:http://localhost/

Accept-Language:zh-cn

Accept-Encoding:gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)

Host:localhost

Connection:Keep-Alive

服务器第一次返回:

HTTP/1.1200 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; MSIE6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)

Host:localhost

Connection:Keep-Alive

Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3

服务器第二次返回:

HTTP/1.1200 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附带在请求信息中

COOKIE

    cookie 是一种在远程浏览器端储存数据并以此来跟踪和识别用户的机制。

PHP在http 协议的头信息里发送cookie,因此setcookie()函数必须在其它信息被输出到浏览器前调用。

原理.

a.服务器通过随着响应发送一个http 的Set-Cookie 头,在客户机中设置一个cookie(多个cookie 要多个头)。

b.客户端自动向服务器端发送一个http 的cookie 头,服务器接收读取。

HTTP/1.x 200 OK

X-Powered-By: PHP/5.2.1

Set-Cookie:TestCookie=something from somewhere; path=/

Expires: Thu, 19 Nov 2007 18:52:00 GMT

Cache-Control: no-store, no-cache,must-revalidate,      post-check=0,pre-check=0

Pragma: no-cache

Content-type: text/html

这一行实现了cookie 功能,收到这行后

Set-Cookie: TestCookie=something fromsomewhere; path=/

浏览器将在客户端的磁盘上创建一个cookie 文件。

下面的同样的效果:

setcookie(‘TestCookie’,’something   from somewhere’,’/’);

header(‘Set-Cookie:TestCookie=something from somewhere; path=/’)

常见问题解决:

1) 用 setcookie()时有错误提示,可能是因为调用setcookie()前面有输出或空格。

2) $_COOKIE 受magic_quotes_gpc 影响,可能自动转义。

3) 使用的时候,有必要测试用户是否支持cookie。

下面以用户登录为例分析session和cookie

HTTP协议是一种无状态协议,服务器响应完用户的请求,就失去了与浏览器的联系,PHP是如何实现session的。

用户第一次访问服务器时,因为没有session信息,需要登录验证,用户通过表单把用户名,密码,验证码等信息提交给服务器,服务器在验证用户的合法性之前先对数据进行预处理。通过到数据库验证,用户是合法的,这个时候服务器会给浏览器信息中包含Set-Cookie: PHPSESSID=bmmc3mfc94ncdr15ujitjogma3;这样的信息,这样浏览器会把信息写到本地文件中,其中PHPSESSID为唯一标识符。同时服务器也会在指定的文件把序列化的session信息保存在文件中。当用户再次请求时,浏览器会把对应cookie中的PHPSESSID也发送给服务器,服务器得到PHPSESSID,会到session文件中验证,如果验证成功,就直接登录。从而类似的可以实现数据在不同用户页面之前的传递。session中的值是key-value。

session影响系统性能

session在大访问量网站上确实影响系统性能,影响性能的原因之一由文件系统设计造成,在同一个目录下超过10000个文件时,文件的定位将非常耗时,PHP支持session目录hash,我们可以通过修改php.ini中session.save_path =“2;/path/to/session/dir”,那么session将存储在两级子目录中,每个目录有16个子目录[0~f],不过好像PHPsession不支持创建目录,你需要事先把那么些目录创建好 。

还有一个问题就是小文件的效率问题,一般我们的session数据都不会太大(1~2K),如果有大量这样1~2K的文件在磁盘上,IO效率肯定会很差。可以通过缓存memcache和mysql数据库提供效率。

session的同步

前端可能有很多台服务器,用户在A服务器上登录了,种下了session信息,然后访问网站的某些页面没准跳到B服务器上去了,如果这个时候B服务器上没有session信息又没有做特殊处理,可能就会出问题了。

session同步有很多种,如果你是存储在memcached或者MySQL中,那就很容易了,指定到同样的位置即可,如果是文件形式的,你可以用NFS统一存储。

(NFS是Network File System的简写,即网络文件系统.网络文件系统是FreeBSD支持的文件系统中的一种,也被称为NFS. NFS允许一个系统在网络上与他人共享目录和文件。通过使用NFS,用户和程序可以像访问本地文件一样访问远端系统上的文件。)

还有一种方式是通过加密的cookie来实现,用户在A服务器上登录成功,在用户的浏览器上种上一个加密的cookie,当用户访问B服务器时,检查有无session,如果有当然没问题,如果没有,就去检验cookie是否有效,cookie有效的话就在B服务器上重建session。这种方法其实很有用,如果网站有很多个子频道,服务器也不在一个机房,session没办法同步又想做统一登录那就太有用了。

还有一种方法就是在负载均衡那一层保持会话,把访问者绑定在某个服务器上,其他所有访问都在那个服务器上就不需要

标签