PHP会话技术(cookie与session)详解

Posted eyes++

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP会话技术(cookie与session)详解相关的知识,希望对你有一定的参考价值。

一:会话技术初步认识

会话技术介绍: web会话可以简单理解为:用户打开一个浏览器,访问某一个web站点,在这个站点点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。

HTTP协议的特点是无状态/无连接,当一个浏览器连续多次请求同一个web服务器时,服务器是无法区分多个操作是否来自于同一个浏览器(用户)。会话技术就是通过HTTP协议想办法让服务器能够识别来自同一个浏览器的多次请求,从而方便浏览器(用户)在访问同一个网站的多次操作中,能够持续进行而不需要进行额外的身份验证。

会话技术分类:
1). cookie技术
cookie技术是在HTTP协议下,服务器或脚本可以维持客户工作站上信息的一种方式,cookie是由Web服务器保存在用户浏览器(客户端)上的小文本文件(HTTP协议响应头),它可以包含有关用户的信息。无论何时用户链接到服务器,Web站点都可以访问cookie信息。

2). session技术
session直接翻译成中文比较困难,一般都翻译成时域,在计算机专业术语中,session是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经历的时间。以及如果需要的话,可能还有一定的操作空间。session技术是将数据保存到服务器端,无论何时用户链接到服务器,Web站点都可以访问session信息。session技术的实现是依赖cookie技术的。

3). 两种会话技术的区别
a). 安全性方面:
session存储在服务器端,安全性高
cookie存储在浏览器端,安全性低
b). 数据大小方面
session数据存储不限
cookie的数量和大小都有限制(一个网站最多20个cookie,长度最多4k)
c). 可用数据类型
session 可以存复杂数据(自动序列化)
cookie只能存储简单数据,数值或字符串

二:php 的 COOKIE 技术

(1). COOKIE 工作原理

cookie技术:服务器将数据通过HTTP相应到浏览器上,浏览器可以在以后携带对应的cookie数据访问服务器。

1、第一次请求时,PHP通过setcookie函数将数据通过http协议响应头传输给浏览器
2、浏览器在第一次响应的时候将cookie数据保存到浏览器
3、浏览器后续请求同一个网站时,会自动检测是否存在cookie数据,如果存在,就将在请求头中将数据携带到服务器
4、PHP执行时会自动判断浏览器请求中是否携带cookie,如果携带,则自动保存在$_COOKIE中
5、利用$_COOKIE访问cookie数据

(2). COOKIE 基本使用

设置COOKIE信息
setcookie()函数用来设定cookie信息
其参数为: setcookie(名字, 值)

1). cookie名的设置: 字符串, 第一个参数
2). cookie值的设置: 第二个参数
3). cookie值的类型要求: 必须是简单类型中的整数或者字符串

以下是演示:
打开浏览器设置,查看网站cookie信息,可见cookie已经设置成功了。

读取COOKIE信息
可以使用$_COOKIE数组获得COOKIE信息。

由下图可见,因为setcookie.php文件和getcookie.php文件在同一服务器下,所以getcookie.php可以拿到setcookie.php设置的cookie信息。

(3). COOKIE 高级——生命周期

COOKIE生命周期:COOKIE在浏览器生存时间(浏览器在下次访问服务器时是否携带对应的COOKIE)

1). 默认(不设定)时的生命周期:不设定周期默认是关闭浏览器(即会话结束)
2).设定为一个常规日期戳的周期: 通过setcookie函数第三个参数可以限定生命周期,是用时间戳管理,从格林威治时间开始
3).设定为“0”的周期:设置生命周期时用0代替时间戳,表示普通设置,会话结束就过期
4).删除一个cookie的做法:服务器没有权限去操作浏览器上的内容,因此无法直接删除,但可以通过设置生命周期来让浏览器自动判定cookie是否有效,无效的话浏览器会自动清除。

(4). COOKIE 高级——作用范围

作用范围:不同的文件夹层级中,设定的COOKIE默认是在不同文件夹下有访问限制,上层文件夹中设定的COOKIE可以在下层(子文件夹)中访问,而子文件夹中设定的COOKIE不能在上层文件夹中访问。

setcookie(名字,, 生命周期, 作用范围)

1). 默认(不设定)的范围: 就是使用COOKIE默认的作用范围

2). 设定为 “/” 的含义: 告知浏览器当前COOKIE的作用范围是网站根目录,在setcookie的第四个参数里设置。例如下面的设置,该cookie名为password,值为12345,7天后过期,作用范围是网站根目录,即网站下所有页面都可以访问该cookie。

setcookie('password', 12345, time() + 7*24*60*60, '/');

(5). COOKIE 高级——跨子域

跨子域:在同一级别域名下,一个一级域名可以有多个子域名,他们之间是搭建在不同服务器上,比如腾讯官网是www.qq.com,腾讯公益是gongyi.qq.com。它们之间是搭建在不同服务器上的,但是可以通过COOKIE设置实现对应的COOKIE共享访问(默认是不允许的)。

1). 设定cookie的有效域名:不同域名(包含主机)之间不能共享COOKIE,可以通过设置setcookie的第五个参数来控制。

setcookie(名字,, 生命周期, 作用范围, 有效域名)

2). 不设定时的默认有效域名是不跨域的。如下实例,在www.qq.com执行这行代码默认不共享COOKIE,即为默认值。

setcookie('password', 12345, time() + 7*24*60*60, '/', 'www.qq.com');

3). 跨子域的设定方法:在设定域名访问的时候用设定上级域名即可。如下实例,这行代码执行后,所有qq.com的域名都可以共享该COOKIE。

setcookie('password', 12345, time() + 7*24*60*60, '/', 'qq.com');

(6). COOKIE 高级——数组数据

cookie本身只支持简单数据(数字或者字符串),能够保留的数据本身有限,也不成体系,如果需要使用cookie来保留一组数据的话,就要想办法凑成数组(cookie不支持数组)。

下图可见,cookie本身不支持保存数组

因此需要伪装数组:

1). 设置形式:setcookie(‘c1[k1]’, 值)

<?php

// 伪装数组
setcookie('goods_ids[0]', 1);
setcookie('goods_ids[1]', 2);
setcookie('goods_ids[2]', 3);
setcookie('goods_ids[3]', 4);

echo '<pre>';
var_dump($_COOKIE);

效果如下,值得注意的是,我第一次打开并没有读取到goods_ids的cookie,刷新后拿到了,推测应该是虽然是先执行setcookie函数,但浏览器先执行完成var_dump($_COOKIE)。

由下图浏览器设置所示,推测应该在$_COOKIE中以数组形式存在,但在浏览器中,依然是个体存在。

2).读取形式: $_COOKIE[‘c1’][‘k1’]

三:PHP 的 SESSION 技术

(1). SESSION 工作原理

session与浏览器无关,但是与cookie有关。

  • PHP碰到 session_start() 时开启 session 会话,会自动检测 sessionID
    • 如果 cookie 中存在,则使用现成的
    • 如果 cookie 中不存在,则创建一个 sessionID ,并通过响应头以 cookie 形式保存到浏览器上。
  • 初始化超全局变量 $_SESSION 为一个空数组
  • PHP通过 sessionID 去指定位置( session 文件存储位置)匹配对应的文件
    • 不存在该文件,则创建一个 sessionID 命名文件
    • 存在该文件,则读取文件内容(反序列化), 将数据存储到 $_SESSION 中
  • 脚本执行结束,将 $_SESSION 中保存的所有数据序列化存储到 sessionID 对应的文件中

(2). SESSION 基本使用

启用 session ,任何时候都需要开启 session (脚本使用到$_SESSION 就开启一次)
$_SESSION 是通过 session_start() 函数的调用才会定义的,没有直接定义。因此下图用法是错误的。

这才是正确的用法,session 的使用需要开启session_start()

设置 SESSION 信息
如果想存储数据到 session 中, 那么只要不断给$_SESSION 数组添加元素即可。

读取 SESSION 信息
$_SESSION 就是一个数组,存储什么数据,什么方式存储的,就可以通过什么方式访问。
会话技术的目的就是实现跨脚本共享数据:在一个脚本中定义数据,在另一个脚本中保存数据。
由图中红色字体部分可知,为什么 session_use.php 脚本能拿到 session.php 设置的值了。

(3). SESSION 删除数据

删除 session 就是将 session 数据清理掉($_SESSION拿不到)
删除一个SESSION信息

unset($_SESSION['名字'])


删除全部SESSION信息
删除全部 session 就是让 $_SESSION 变成一个空数组。下面方式只是清除数据,而非清除session文件。清除 session 文件的方法在后面的销毁session会介绍。

$_SESSION = array();

(4). SESSION 相关配置

SESSION 的基础配置

1). session.name : 指session名字,即保存到cookie中sessionID对应的名字

2). session.auto_start :是否自动开启session(即无需手动session_start()),默认是关闭的。

3). session.save_handler : session 数据的保存方式,默认是文件形式

4). session.save_path : session 文件默认存储的位置
如果你的session.save_path显示是在’\\tmp’中,那么说明文件默认被存储在系统临时文件夹中,这是不安全的,因为有可能面临访问权限问题。因此建议修改路径。

然后我们可以根据上面的存储路径找到服务器的session文件,如下所示

SESSION 的常用配置

1). session.cookie_lifetime : sessionID在浏览器端对应的COOKIE的生命周期,默认是会话结束,即浏览器关闭。

2). session.cookie_path : sessionID 在浏览器存储之后允许服务器访问的路径(COOKIE有作用范围)。默认是网站根目录。

3). session.cookie_domain : COOKIE允许访问的子域(COOKIE可以跨子域),默认是不能跨子域

SESSION 配置的两种形式

1). 在php.ini中配置,即全局配置, 配置方法见上图。
2). 在脚本中配置,指PHP可以通过 ini_set 函数在运行中设定某些配置项(只会对当前运行的脚本有效), 一般把这种配置称之为项目级。

PHP ini_set 函数格式:

string ini_set(string $varname, string $newvalue)  

以下是一个示例,考虑到早期版本可能没有ini_set函数,因此在前面加一个错误抑制符。

@ini_set('session.save_path', 'E:/');

(5). SESSION 销毁session

系统提供了函数: session_destroy(), 该函数会自动根据 session_start() 得到的 sessionID 去找到指定的 session 文件, 并把其删除。

(6). SESSION 垃圾回收

session会话技术诞生后, session文件并不会自动清除,如果每天有大量session文件产生但又都是失效的,那么会增加服务器的压力并且影响session效率。
垃圾回收,是指session机制提供了一种解决垃圾session文件的方式,给session文件指定周期,通过session文件最后更改时间与生命周期进行结合判定,如果已经过期则删除对应的session文件,如果没有过期则保留,这样就可以及时清理无效的僵尸文件,从而提升空间利用率和session工作效率。

1). 任何一次session开启(session_start),session都会尝试去读取session文件
2). 读取session文件后,有可能触发垃圾回收机制(在session系统中也是一个函数:自己有一定几率调用)
3). 垃圾回收机制会自动读取所有session文件的最后编辑时间,然后加上生命周期(配置文件)与当前时间进行比较(所有session文件),过期则删除,有效则保留。

垃圾回收参数设置
1). session.gc_maxlifetime = 1440 : 规定的session文件最大的生命周期是1440秒,即24分钟。
2). session.gc_probability = 1 :垃圾回收概率因子(分子)
3). session.gc_divisor = 1000 : 垃圾回收概率分母
由session.gc_probability和session.gc_divisor知默认触发回收的概率是千分之一。实际开发中可以根据用户量进行调整。

(7). SESSION 禁用cookie时使用session

设置浏览器禁止cookie:
依次执行 session.php 文件和 session_use.php 文件,发现 session_use.php 已经无法拿到 session
数据了。

禁止COOKIE不能使用SESSION的原因
session技术需要利用到cookie技术来保存sessionID,从而使得PHP能够在跨脚本的时候得到相同的sessionID,从而访问同一个session文件。

禁止COOKIE后如何使用SESSION
让session_start在开启之前 拿到原来的sessionID(另一个脚本的)

实现无COOKIE使用SESSION
方案一: 利用PHP提供的session函数: session_id 和 session_name 来获得和设置sessionID或者name从而解决session_start产生新的sessionID的情况(手动操作)
1). 在session保存数据的脚本中获取sessionID和名字

<?php

// 开启 session
session_start();

// 获取sessionID和名字
$id = session_id();  // 获取是在session_start执行之后
$name = session_name();  // 拿到名字(即php.ini 中的 session.name)

echo $name . '=' . $id;

2). 接下来就是想办法把数据传递给另外一个脚本:表单传值(URL或form表单)

session.php 文件代码:

<?php

// 开启 session
session_start();

// 设置内容
$_SESSION['name'] = 'eyes++';

// 获取sessionID和名字
$id = session_id();  // 获取是在session_start执行之后
$name = session_name();  // 拿到名字(即php.ini 中的 session.name)

// 传递给另外一个脚本
echo "<a href='session_use.php?{$name}={$id}'>click</a>";

session_use.php 文件代码:

<?php

// 接收数据
$name = session_name();
$id = $_GET[$name];

// 设定sessionID,该操作可以阻止session_start产生新的ID
session_id($id);

// 开启session
session_start();

// 访问
var_dump($_SESSION);

方案二: 利用session机制中的已经提供的解决方案自动操作(通过配置实现)
原因1:默认session配置只允许使用cookie保存sessionID: cookie_only
原因2: 默认关闭了其它能够传递数据的方式,只保留了cookie
1). 修改PHP配置文件,开启其他方式传输sessionID,关闭只允许使用cookie传输功能。
2). 重启apache。一旦配置开启,PHP会自动将sessionID和session名字在其他位置绑定数据,同时还会在session_start的时候,考虑通过表单传递数据,而非只有cookie。

以上是关于PHP会话技术(cookie与session)详解的主要内容,如果未能解决你的问题,请参考以下文章

Cookie/Session机制详解

Cookie/Session机制详解

Cookie/Session机制详解

Cookie和Session详解

Cookie/Session机制详解

Cookie/Session机制详解