PHP cookie和session的分析

PHP cookie和session的分析
 

cmpan(at)qq.com
流水孟春
lib.cublog.cn

转载请注


1. PHP COOKIE

cookie 是一种在远程浏览器端储存数据并以此来跟踪和识别用户的机制。
PHP
http 协议的头信息里发送 cookie, 因此 setcookie() 函数必须在其它信息被输出到浏览器前调用,这和对 header() 函数的限制类似。

1.1
设置 cookie :
   
可以用 setcookie() setrawcookie() 函数来设置 cookie 。也可以通过向客户端直接发送 http 头来设置 .
1.1.1
使用 setcookie() 函数 设置cookie:
bool setcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure [, bool httponly]]]]]] )
    
name:   cookie
变量名
     value:   cookie
变量的值
     expire: 
有效期结束的时间 ,
     path:   
有效目录 ,
     domain:
有效域名 , 顶级域唯一
     secure: 
如果值为 1, cookie 只能在 https 连接上有效 , 如果为默认值 0, http https 都可以 .
例子 :
< ? php
$ 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 变量 .

1.1.2.
使用 header() 设置cookie ;
header("Set-Cookie: name=$value[;path=$path[; domain=xxx.com [;...]]");
后面的参数和上面列出 setcookie 函数的参数一样 .
比如:

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

1.2 Cookie的读取:

直接用php内置超级全局变量 $_COOKIE就可以读取浏览器端的cookie.
上面例子中设置了cookie"TestCookie",现在我们来读取:

print $_COOKIE[ 'TestCookie' ] ;

COOKIE是不是被输出了?!

1.3 删除 cookie
只需把有效时间设为小于当前时间 , 和把值设置为空 .例如:
setcookie("name","",time()-1);
header() 类似 .

1.4 常见问题解决 :

1) 用setcookie()时有错误提示,可能是因为调用setcookie()前面有输出或空格.也可能你的文档使从其他字符集转换过来,文档后面可能带有BOM签名(就是在文件内容添加一些隐藏的 BOM 字符).解决的办法就是使你的文档不出现这种情况.还有通过使用ob_start()函数有也能处理一点.
2) $_COOKIE magic_quotes_gpc 影响 , 可能自动转义
3) 使用的时候 , 有必要测试用户是否支持 cookie
<!--[if !supportLineBreakNewLine]-->

1.5 cookie 工作机理 :

有些学习者比较冲动,没心思把原理研究,所以我把它放后面.
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 from somewhere ; path=/
浏览器将在客户端的磁盘上创建一个cookie文件,并在里面写入:

TestCookie = something from somewhere ;
/

这一行就是我们用setcookie( 'TestCookie' , 'something from somewhere' , '/' ) ; 的结果.也就是用header( 'Set-Cookie: TestCookie=something from somewhere; path=/' ) ; 的结果.
<!--[endif]-->



2. PHP Session

session 使用过期时间设为 0 cookie, 并且将一个称为 session ID 的唯一标识符 ( 一长串字符串 ) ,在服务器端同步生成一些session文件(可以自己定义session的保存类型),与用户机关联起来 .web 应用程序存贮与这些 session 相关的数据 , 并且让数据随着用户在页面之间 传递 .

访问网站的来客会被分配一个唯一的标识符,即所谓的会话 ID。它要么存放在客户端的 cookie,要么经由 URL 传递。

会 话支持允许用户注册任意数目的变量并保留给各个请求使用。当来客访问网站时,PHP 会自动(如果 session.auto_start 被设为 1)或在用户请求时(由 session_start() 明确调用或 session_register() 暗中调用)检查请求中是否发送了特定的会话 ID。如果是,则之前保存的环境就被重建。

2.1 sessionID 的传送

2.1.1 通过 cookie 传送 sessin ID

     使用 session_start() 调用session,服务器端在生成session文件的同时,生成session ID哈希值和默认值为 PHPSESSID的session name,并向客户端发送变量为 (默认的是)PHPSESSID(session name ),值为一个128位的哈希值.服务器端将通过该cookie与客户端进行交互.
   session变量的值经php内部系列化后保存在服务器机器上的文本文件中,和客户端的变量名默认情况下为
PHPSESSID的coolie进行对应交互.
     即服务器自动发送了http头:header('Set-Cookie: session_name()=session_id() ; path=/');
setcookie( session_name() , session_id()) ;
   
当从该页跳转到的新页面并调用 session_start() ,PHP 将检查与给定 ID 相关联的服务器端存贮的 session 数据 , 如果没找到 , 则新建一个数据集 .

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

2.2 session基本用法实例

< ? php
// 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将为(未定义)空
 */

? >

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


2.3 使用 session 函数控制页面缓存 .
    很多情况下,我们要确定我们的网页是否在客户端缓存,或要设置缓存的有效时间,比如我们的网页上有些敏感内容并且要登录才能查看,如果缓存到本地了,可以直接打开本地的缓存就可以不登录而浏览到网页了.

    使用 session_cache_limiter('private'); 可以控制页面客户端缓存 , 必须在 session_start() 之前调用 .
更多参数见 http://blog.chinaunix.net/u/27731/showart.php?id=258087 的客户端缓存控制 .

    
控制客户端缓存时间 session_cache_expire(int); 单位 (s). 也要在 session_start() 前调用 .

    这只是使用session的情况下控制缓存的方法,我们还可以在header()中控制控制页面的缓存.

2.4 删除 session

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

2.5 session PHP 大型 web 应用中的使用

对于访问量大的站点 , 用默认的 session 存贮方式并不适合 , 目前最优的方法是用数据库存取 session. 这时 , 函数 bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback destroy, callback gc ) 就是提供给我们解决这个问题的方案 .
该函数使用的 6 个函数如下 :

1.   bool open() 用来打开会话存储机制 ,

2.   bool close() 关闭会话存储操作 .

3.   mixde read() 从存储中装在 session 数据时使用这个函数

4.   bool write() 将给定 session ID 的所有数据写到存储中

5.   bool destroy() 破坏与指定的会话 ID 相关联的数据

6.   bool gc()  对存储系统中的数据进行垃圾收集

例子见php手册 session_set_save_handler() 函数 .
如果用类来处理 ,
session_set_save_handler(
    array('className',' open '),
    array('className',' close '),
    array('className',' read '),
    array('className',' write '),
    array('className','destroy'),
    array('className','gc'),
)
调用 className 类中的 6 个静态方法 .className 可以换对象就不用调用静态方法 , 但是用静态成员不用生成对象 , 性能更好 .

2.6 常用 session 函数 :

bool   session_start(void); 初始化 session
bool   session_destroy(void)
: 删除服务器端 session 关联文件
string session_id()
当前 session id
string session_name()
当前存取的 session 名称 , 也就是客户端保存 session ID cookie 名称 . 默认 PHPSESSID
array  session_get_cookie_params()
与这个 session 相关联的 session 的细节 .
string session_cache_limiter()
控制使用 session 的页面的客户端缓存
ini    session_cache_expire()
控制客户端缓存时间
bool   session_destroy()    
删除服务器端保存 session 信息的文件
void   session_set_cookie_params ( int lifetime [, string path [, string domain [, bool secure [, bool httponly]]]] ) 设置与这个 session 相关联的 session 的细节
bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback destroy, callback gc ) 定义处理 session 的函数 ,( 不是使用默认的方式 )
bool session_regenerate_id([bool delete_old_session]) 分配新的 session id


2.7 session 安全问题
攻击者通过投入很大的精力尝试获得现有用户的有效会话 ID, 有了会话 id, 他们就有可能能够在系统中拥有与此用户相同的能力 .
因此 , 我们主要解决的思路是效验 session ID 的有效性 .

< ? php

if ( ! isset ( $ _SESSION [ 'user_agent' ] ) ) {
    $ _SESSION [ 'user_agent' ] = $ _SERVER [ 'REMOTE_ADDR' ] . $ _SERVER [ 'HTTP_USER_AGENT' ] ;
}

/* 如果用户session ID是伪造 */
elseif ( $ _SESSION [ 'user_agent' ] ! = $ _SERVER [ 'REMOTE_ADDR' ] . $ _SERVER [ 'HTTP_USER_AGENT' ] ) {
   
session_regenerate_id ( ) ;
}
? >


2.8 Session
通过 cookie 传递和通过SID传递的不同 :
php5.2.1 session 的默认配置的情况下 , 当生成 session 的同时 , 服务器端将在发送 header set-cookie 同时 生成预定义超级全局变量 SID( 也就是说 , 写入 cookie 和抛出 SID 是等价的 .), $_COOKIE['PHPSESSID'] 存在以后 , 将不再写入 cookie, 也不再生成超级全局变量 SID, 此时 ,SID 将是空的 .



2.9 session使用实例

< ? php
/**
 * 效验session的合法性
 *
 */

function sessionVerify( ) {
    if ( ! isset ( $ _SESSION [ 'user_agent' ] ) ) {
        $ _SESSION [ 'user_agent' ] = MD5 ( $ _SERVER [ 'REMOTE_ADDR' ]
        . $ _SERVER [ 'HTTP_USER_AGENT' ] ) ;
    }
    /* 如果用户session ID是伪造,则重新分配session ID */
    elseif ( $ _SESSION [ 'user_agent' ] ! = MD5 ( $ _SERVER [ 'REMOTE_ADDR' ]
    . $ _SERVER [ 'HTTP_USER_AGENT' ] ) ) {
        session_regenerate_id ( ) ;
    }
}

/**
 * 销毁session
 * 三步完美实现,不可漏
 *
 */

function sessionDestroy( ) {
    session_destroy ( ) ;
    setcookie ( session_name ( ) , '' , time ( ) - 3600) ;
    $ _SESSION = array ( ) ;
}
? >


注明:

    session 出现头信息已经发出的原因与cookie一样.
    在php5中,所有php session 的注册表配置选项都是编程时可配置的,一般情况下,我们是不用修改其配置的.要了解php的session注册表配置选项,请参考手册的Session 会话处理函数处.

      session的保存数据的时候,是通过系列化$_SESSION数组来存贮,所以有系列化所拥有的问题,可能有特殊字符的值要用base64_encode函数编码,读取的时候再用base64_decode解码

你可能感兴趣的:(PHP,session,server,服务器,header,callback)