本文从Cookies的存储谈起,然后介绍如何使用PHP和JavaScript来读取和写入Cookies。最后是一个实现“记住我”的案例。文章最后还给出了若干最佳实践。本文能带给您丰富的Cookies知识——即便您有相关的经验。


第一步:理解Cookies


我们旅程的第一站是讨论一下Cookies到底是什么!虽然你可能已经使用过它们,但你应该还是能在此找到很有价值的东西——所以继续往下看吧!


摘要


你可以简单的把Cookies理解为存储在你电脑里的文本文件。在向Web服务器请求时,你的浏览器就创建这么一个文件。此后,Web服务器能读取和写入内容到这个文件。虽然这个功能看上去很危险——毕竟没有人喜欢其他人在他电脑上写文件。有一些合理的限制来规范操作,以保证这些操作的安全:



  • Web服务器只能访问其对应域名下的Cookies。当浏览器向服务器发送请求时,浏览器就创建一个新的Cookies,并且只对应该服务器的域名或一个子域名(如果需要的话,服务器可以选择一个子域名)。意思是,Cookies是属于设置它的那个。比如说,lorui.com无法访问8310.org的Cookies,反之亦然。

  • HTTP协议规定,Cookies不能大于4096字节(bytes,4KB)。

  • 每个域名对应的Cookies数量是有限制的。每个浏览器的限制是不同的,一般的限制是20个。这是为了防止单个域名占用过多的客户硬盘空间。

  • 客户硬盘里的Cookies总数是有限制的。这个限制也是因浏览器而异,一般是限制在300个Cookies左右。当超出这个限制时,在创建新的Cookies之前,会把最旧的删除。


Cookies是有过期时间(有效期)的。这个时间是用来设置浏览器删除服务器不再需要的旧Cookies的时间。如果有效期为空,在与服务器的连接中断时,该Cookies就会被删除。一般是在浏览该站点的浏览器窗口或Tab(标签页)被用户关闭时、或者用户关闭整个浏览器的时候。这种Cookies一般叫作“会话Cookies”(session cookies),主要用来存储临时的设置。


技术


下面从技术层面来讨论。Cookies通过HTTP协议来传送。浏览器使用该协议从服务器接收Cookies以及向服务器发送Cookies。当请求一个Cookies之后,每一次Web页面被读取的时候通过浏览器将其发送到服务器。下面,我们可以看到一个服务器请求一个新Cookies时的片断(这个片断是HTTP响应的一部分)


足间舞ROOM


Set-Cookie: Name=content data; expires=Fri, 31-Dec-2010 23:59:59 GMT; path=/; domain=.lorui.com

别害怕,它是非常容易理解的!



  • Set-Cookie用来让浏览器知道该服务器想创建一个新Cookies。

  • Name是这个Cookies的名字。一个域名下的每个Cookies都要有不同的名字,这样浏览器就能管理所有Cookies。在名称之后的=content data里,“content data”是这个Cookies包含的数据。这个数据可以是字符串或者是数字等等。就是说,只要在4KB之内就行。

  • expries=用来控制有效期。有效期的格式是Wdy, DD-Mon-YYYY HH:MM:SS GMT(别问我为什么要定义成这个格式,因为我也不知道。)别担心,大部分编程语言都有函数供你方便的使用。浏览器会自动删除一个过期的Cookies。

  • domainpath
  • 需要更深入一点的讨论。domain是该Cookies可用的域名。如果域名是“php.lorui.com”,该Cookies将只发送到这个域名所在服务器;如果域名是“lorui.com”,该Cookies将发送到lorui.com的任意子域名的任意服务器上,包括lorui.com本身。
  • path是cookies将要发送到域名的路径。意思是,如果这个path设定为“/images/”,而且domain设定为“php.lorui.com”,那么只有在浏览器从“php.lorui.com/images/”请求文件时,cookies才会发送到服务器上。如果path设定为“/”,那么不管请求的文件在服务器的什么位置,这个cookies都会发送到服务器上。


在一下步中,我们将讨论这些属性如何使用到编程语言中。


第二步:如何读写Cookies


可以通过多种方法创建Cookies,但本教程将把焦点放在PHP和JavaScript上面。


PHP


首先请记住,在PHP里创建Cookies时,必须在发送任何数据到浏览器之前设置Cookies。意思是,你永远必须在任何输出之前初始化新Cookies。包括(但不限于)echo()print()命令,以及<html>或<body>标签。当然也有例外,但这是一个好的惯例。


<?php 
/***创建 cookie***/
$name = 'user_name'; an-introduction-to-cookies
$value = 'Lorui';
//time() 以秒数形式获取当前时间,我们给它加上60秒 * 30 = 30分钟
//将这个cookie的有效期设置为30分钟
//请记住,有效期是秒数,PHP会把它转化成正确的格式
$expireDate = time() + 60 * 30;
$path = '/example/';
$domain = 'test.lorui.com';
$secure = false; //仅当建立HTTPS时提交该COOKIES
$httponly = true; //将COOKIES设置为仅对HTTP协议有效(不包括JavaScript)
setcookie( $name, $value, $expireDate, $path, $domain, $secure, $httponly);
?>

上面的代码看起来很熟悉吧,除了$secure$httponly之外。如果$secure设置为true,则强制cookies仅在启用了HTTPS的时候发送,一般是设置为false。$httponly设置cookies仅通过HTTP协议有效,换句话说,像Javascript和VBScript这些客户端脚本无法访问这个cookies。这是为了帮助遏制恶意攻击,比如“跨站点脚本攻击”(XSS,Cross Site Scripting),同时你并不会使用诸如Javascript的客户端脚本编辑这个Cookies。还有需要澄清一点,$httponly并不是说这个cookies不能通过HTTPS发送,事实上是可以的。另外,上面的代码片断可以简化为:


<?php
setcookie('user_name',
'LoRui',
time() + 60 * 30,
'/example/',
false,
true);
?>

很好!现在我们已经可以创建Cookies了,但我们还想读出它们来。很幸运,PHP在一个cookies创建之后,让一切都变得那么简单。在PHP里,有一个叫$_COOKIES[]的环境变量,通过它可以获取cookies的值。要使用它,只需将cookies的名称插入到[]内,就像这样:


足间舞ROOM


<?php
$cookie_value = $_COOKIES['cookie的名称'];
?>

环境变量可以像其它变量一样直接使用。如果你想的话,它和$_GET[]$_POST[]一样,也可以像普通变量一样直接处理(当你确定cookies的索引是正确的之后)。


如果你修改cookies的有效期、域名或路径,你只要使用setcookie()并使用和原cookies一样的名称就可以了。如果你修改的有效期已经过去了,该cookies将会被删除。


JavaScript


Cookies同样可以在客户端读取和写入。即使JavaScript不是一个好的读取和写入Cookies解决方案。JavaScript使用document.cookie对象来处理cookies,就像下面的代码片断所示:



var expriedate = new Date(); //获取当前时间
expriedate.setHours(expriedate.getHours() + 5);
document.cookie = 'cookiename=user_name; expries=' + expriedate.toUTCString() + 'path=/example/; domain=test.lorui.com';

你可能已经注意到了,它的语法和HTTP协议的记法很相似。这种方式存在很多优势,但也要看到一些潜在的问题。下面就是“痛苦”的读取cookies的代码片断。



var cookie_name = 'user_name';
var text_arr = document.split(';');
for(var i = 0; i < text_arr.length; i++){
var text_piece = text_arr[i];
while(text_piece(0) == ' ') text_piece = text_piece.substring(1, text_piece.length);
if(text_piece.indexOf(cookie_name) == 0)
return text_piece.substring(cookie_name.length, c.length);
}

是的,很辛苦!你可以把上面的代码封装成函数,以便简化操作及复用。


第三步:Cookies能做什么


你知道吗?Cookies是Netscape发明的,想通过它来实现在一个网上商城创建购物车。感谢Cookies!它让人们从网上商城断开连接后,依然能在购物车里保存东西。


今天,我们能在你能想到的各种场合使用Cookies。你可以使用它来保存诸如名称、语言、位置或屏幕大小等用户设置。它可以改善用户体验,用户你可以为客户优化服务并记住这些优化。例如,你可以将用户的首选语言保存到cookies中,然后在用户每次访问你的网站时,使用该首选语言对网站内容进行显示。


当然,cookies还能做很多有趣的事情!在下一步里,我将给你呈现一个很酷的代码片断。


第四步:写很酷的东西


好的!我们现在可以开始写一些了不起的代码了!下面是一段“福利”代码(就是额外赠送的好东西,网友有福了),使用cookies创建“重新登录”(relogin,“记住我”)机制。


“记住我”(Remember me)登录代码片断


该片段含有一些MySQL代码。如果你不清楚MySQL也不要紧张。虽然这个片段有一点点难,但只要有一些基础的PHP和Cookies知识就很容易明白了。


实现“记住我”功能,我们必须做几件事。第一,我们需要一个包含username(用户名)、password(密码)和identification(标识)字段。第二,我们需要一个唯一的值(借助数据库里的identification)来通过Cookies标识客户端的安全。在这个片断里,我们使用SHA-1加密字符串,让它成为一个标识。只要合理使用,它将提供卓越的安全性。


很多人只在cookies里插入用户名和密码,并将其自动发送到服务器。这是任何时候都要避免的!Cookies通常由不安全的连接发送,因此其内容很容易被潜在的攻击者看到。


<?php
$username = 'Lorui';
//从两个随机数和用户名里创建一个加密标识
$digest = sha1(strval(rand(0, microtime(true)) . $username . strval(microtime(true))));
//保存到数据库(假设数据库已经连接成功)
mysql_query('UPDATE users SET reloginDigest="'.$digest.'" WHERE username="'.$username.'"');
//设置Cookies
setcookie('regionID', $digest, time() + 60 * 60 * 24 * 7, '/', 'lorui.com', false, true);
//假设用户已经登出并且cookies已经设置
/** 通过Cookies验证用户 **/
$digest = $_COOKIES['regionID'];
$digest = mysql_real_escape_string($digest); //过滤任何恶意内容
//检查数据库里的标识

足间舞ROOM


$result = mysql_query('SELECT username FROM users WHERE reloginDigest="'.$digest.'"');
//标识存在
if(mysql_num_rows($result) == 1){
$user_data = mysql_fetch_object($result);
$username = $user_data->username;
echo $username.'你已经成功登录。';
} else { //标识不存在,或者找到多个标识(这个是不应该发生的情况)
echo '登录失败';
}

第五步:最佳实践


你已经到达了本次旅程的尾部。最后我总结一下几个最佳实践:



  • 决不在Cookies里插入敏感数据。用户可能在公用的电脑上浏览网站,所以不要在Cookies里留下任何个人信息。

  • 不要相信任何来自Cookies的数据(注:本句话可以扩充为:不要相信任何来自外部的数据)。始终对字符串和数字进行过滤!攻击者可能写一段恶意数据通过Cookies发送到服务器上。

  • 尝试估计Cookies的使用期,然后设置对应的有效期。

  • 始终设置secure和httponly。如果你的应用程序不需要在JavaScript里编辑Cookies,启用httponly。如果你有一个永续的HTTPS连接,启用secure。它可以保证数据的完整和机密。


上一篇 下一篇