PHP中cookie和session的区别实例分析


Posted in PHP onAugust 28, 2014

cookie和session是PHP程序设计中非常重要的技巧。深入理解并掌握cookie和session的应用是进行PHP程序设计的基础。本文就以实例形式来分析一下二者之间的区别。具体分析如下:

1.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

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=/');的结果.
 
2. 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()之前调用.
控制客户端缓存时间用 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 会话处理函数处.

相信本文所述对大家更好的理解PHP中cookie与session的用法有一定的借鉴价值。

PHP 相关文章推荐
fgetcvs在linux的问题
Jan 15 PHP
深入PHP数据加密详解
Jun 18 PHP
php设计模式之单例、多例设计模式的应用分析
Jun 30 PHP
php smarty truncate UTF8乱码问题解决办法
Jun 13 PHP
php读取文件内容到数组的方法
Mar 16 PHP
php字符串分割函数用法实例
Mar 17 PHP
php算法实例分享
Jul 14 PHP
优化WordPress中文章与评论的时间显示
Jan 12 PHP
PHP解压ZIP文件到指定文件夹的方法
Nov 17 PHP
PHP PDOStatement::debugDumpParams讲解
Jan 30 PHP
PHP PDOStatement::fetchColumn讲解
Jan 31 PHP
PHP获取类私有属性的3种方法
Sep 10 PHP
PHP实现视频文件上传完整实例
Aug 28 #PHP
PHP获取表单所有复选框的值的方法
Aug 28 #PHP
PHP中echo和print的区别
Aug 28 #PHP
什么情况下可以不写PHP的闭合标签“?&gt;”
Aug 28 #PHP
PHP防盗链代码实例
Aug 27 #PHP
如何让搜索引擎抓取AJAX内容解决方案
Aug 25 #PHP
使用php方法curl抓取AJAX异步内容思路分析及代码分享
Aug 25 #PHP
You might like
Ping服务的php实现方法,让网站快速被收录
2012/02/04 PHP
PHP 利用AJAX获取网页并输出的实现代码(Zjmainstay)
2012/08/31 PHP
如何使用php判断服务器是否是HTTPS连接
2013/07/05 PHP
php+ajax实现图片文件上传功能实例
2014/06/17 PHP
如何把php5.3版本升级到php5.4或者php5.5
2015/07/31 PHP
PHP让网站移动访问更加友好方法
2019/02/14 PHP
JavaScript实现Sleep函数的代码
2007/03/04 Javascript
javascript 子窗体父窗体相互传值方法
2010/05/31 Javascript
最新的10款jQuery内容滑块插件分享
2011/09/18 Javascript
基于jQuery的倒计时实现代码
2012/05/30 Javascript
jQuery父级以及同级元素查找介绍
2013/09/04 Javascript
JS实现网页游戏中滑块响应鼠标点击移动效果
2015/10/19 Javascript
jQuery css() 方法动态修改CSS属性
2016/09/25 Javascript
js带闹铃功能的倒计时代码
2016/09/29 Javascript
微信小程序 页面跳转传递值几种方法详解
2017/01/12 Javascript
fckeditor部署到weblogic出现xml无法读取及样式不能显示问题的解决方法
2017/03/24 Javascript
JavaScript 程序错误Cannot use 'in' operator to search的解决方法
2017/07/10 Javascript
iscroll实现下拉刷新功能
2017/07/18 Javascript
Three.js利用性能插件stats实现性能监听的方法
2017/09/25 Javascript
javascript变量提升和闭包理解
2018/03/12 Javascript
vue自定义底部导航栏Tabbar的实现代码
2018/09/03 Javascript
JavaScript解析及序列化JSON的方法实例分析
2019/01/04 Javascript
Vue实现数据表格合并列rowspan效果
2020/11/30 Javascript
javascript实现前端成语点击验证
2020/06/24 Javascript
vue监听dom大小改变案例
2020/07/29 Javascript
python搭建简易服务器分析与实现
2012/12/15 Python
在Python中实现贪婪排名算法的教程
2015/04/17 Python
Python编程之event对象的用法实例分析
2017/03/23 Python
Python中实例化class的执行顺序示例详解
2018/10/14 Python
调整Jupyter notebook的启动目录操作
2020/04/10 Python
python实现三壶谜题的示例详解
2020/11/02 Python
基于CSS3 animation动画属性实现轮播图效果
2017/09/12 HTML / CSS
英国领先的家庭时尚品牌:Peacocks
2018/01/11 全球购物
外贸销售员求职的自我评价
2013/11/23 职场文书
小学三年级数学教学反思
2016/02/16 职场文书
Windows Server 2019 域控制器安装图文教程
2022/04/28 Servers