温故PHP之Cookie和Session

前言

学习iOS以来,已经有一段时间不碰PHP了,这两天翻《Head First PHP & MySQL》温习PHP的时候(第7章),发现自己之前对Cookie和Session并没有理解透彻,所以看完后决定写点学习笔记。

  • cookie是浏览器存储在用户计算机中的一小段数据。cookie和PHP变量十分相似,只不过关闭浏览器或计算机后cookie还存在,更重要的是cookie可以删除。

  • 可以从PHP或其他语言访问cookie,而且cookie不仅可以跨多个页面(脚本)持久保存,甚至可以跨多个浏览器会话持久存储。

  • cookie由键-值对组成,每个键-值可以有一个失效日期,如果没有指定失效日期,则cookie会在浏览器关闭时销毁。

  • 设置cookie,获取cookie以及销毁cookie

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //设置cookie
    setcookie('userid', '2345'); //没有设置失效时间,则会在浏览器关闭后立即销毁
    setcookie('userid', '1234', time()+60);//设置当前时间以后60秒失效

    //通过超全局变量获取cookie
    if(empty($_COOKIE['userid'])){}//判断是否设置了该cookie

    //销毁cookie只需要设置它的到期日期在过去的任意时间即可
    setcookie('userid', '', time()-3600);//设置userid这个cookie的到期日期在一个小时以前或其他过去时间,浏览器就会销毁该cookie

Session

如果用户设置浏览器禁用cookie,这样对cookie的存取操作就会失败,所以我们不能完全依赖cookie,此时可以考虑使用session。

  • 和cookie不同的是,session存储在服务器端,这样就不会受到浏览器限制。
  • 由于session数据保存在服务器上,这比存储在cookie中更安全,也更可靠。
  • session比cookie能存储更多类型和大小的数据。
  • session(会话)的缺点就是,无法对一个session变量在数据存储时间上做太多控制,会话一结束就会自动销毁会话变量,而会话在关闭浏览器时就结束。
  • session变量由键-值对组成,但是和cookie不同的时,session变量没有失效日期,以为它随着浏览器关闭就销毁。
  • 所有要使用session数据的页面都要调用session_start()开始一个会话,如果会话不存在,就建立一个会话,并分配一个会话ID,如果已经存在一个会话,则使用已有会话。
  • 在会话开始后,可以直接操作$_SESSION全局变量存取会话变量

    1
    2
    3
    session_start(); //开始一个会话
    $_SESSION['username'] = 'haha';
    if (isset($_SESSION['username'])){}//判断该会话变量是否存在
  • session_destroy()结束一个会话,但它不会自动销毁任何会话变量。所以如果希望用户关闭浏览器之前清空会话变量,就必须手动删除。

    1
    $_SESSION = array();//快速有效的清空会话变量

    但还没有完全结束,因为session在后台实际上会使用cookie,如果浏览器支持cookie,会话可能会设置一个cookie临时存储会话ID,所以要完全关闭一个会话,还必须删除可能在浏览器上自动创建来存储会话ID的cookie

    1
    2
    3
    4
    //会话ID存储在以会话命名的一个cookie中
    if (isset($_COOKIE[session_name()])) {
    setcookie(session_name, '', time()-10);
    }
  • 完整的操作一个会话的过程如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //开始一个会话
    session_start();//开始会话后,所有脚本共享会话变量
    //存取会话变量、检查会话变量...
    $_SESSION['username'] = 'haha';

    //结束会话的正确姿势
    $_SESSION = array();//清空会话变量
    if (isset($_COOKIE[session_name()])) {
    setcookie(session_name, '', time()-10);
    }
    session_destroy(); //最后再结束会话

但是问题依然存在的是,如果用户禁用了cookie,那么session会随着浏览器的关闭而结束。而会话如何响应cookie被禁用取决于服务器上php.ini配置文件中的相关配置项。

1
2
3
session.use_cookies
session.use_only_cookies
session.use_trans_sid

Watch!
禁用cookie的情况下要让会话正常工作,还需要另外一个机制在不同页面传递会话ID,这个机制需要将会话ID追加到每个页面的URL后面,如果服务器上的php.ini中文件中session.use_trans_id被设置为1(true),这就会自动发生。如果你无法直接修改php.ini文件,cookie被禁用时就必须利用类似下面的代码手动地向会话页面的URL追加会话ID。

1
<a href="index.php?<?php echo SID; ?>">view index</a>

但是现在仍不能扭转关闭浏览器即结束会话的命运,而这对于需要记住用户登陆状态的应用至关重要。

我们发现不管是session还是cookie都有各自的优缺点,那么是否可以尝试一下Cookie+Session的方案。

这种方案在技术上并没有增加多少复杂度,只需要同时设置Cookie和Session并且同时销毁即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
session_start();//开始会话

$_SESSION['userid'] = '12345';
setcookie('userid', '12345', time()+3600);//一个小时候失效

//然后在其他脚本中共享cookie和session数据了

//手动注销数据

if (isset($_SESSION['userid'])) {//先销毁session数据
$_SESSION = array();
if (isset($_COOKIE[session_name()])) {
setcookie($_COOKIE[session_name],'',time()-100);
}
session_destroy();
}

setcookie('userid', '', time()-100);//再销毁cookie

但是cookie+session仍然不能防止用户禁用cookie,所以我们还需要寻求更好的方案。

avatar

神无

舍悟离迷,六尘不改。