会话技术
会话技术介绍
web会话可简单理解为:用户开一个浏览器,访问某一个web站点,在这个站点点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
HTTP协议的特点是无状态/无连接,当一个浏览器连续多次请求同一个web服务器时,服务器是无法区分多个操作是否来自于同一个浏览器(用户)。会话技术就是通过HTTP协议想办法让服务器能够识别来自同一个浏览器的多次请求,从而方便浏览器(用户)在访问同一个网站的多次操作中,能够持续进行而不需要进行额外的身份验证。
会话技术分类
- cookie技术 Cookie 是在 HTTP 协议下,服务器或脚本可以维护客户工作站上信息的一种方式。Cookie 是由 Web 服务器保存在用户浏览器(客户端)上的小文本文件(HTTP协议响应头) ,它可以包含有关用户的信息。无论何时用户链接到服务器(HTTP请求携带数据),Web 站点都可以访问 Cookie 信息
- session技术 Session直接翻译成中文比较困难,一般都译成时域。在计算机专业术语中,Session是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间。 以及如果需要的话,可能还有一定的操作空间。Session技术是将 数据保存到服务器端 ,无论何时用户链接到服务器,Web站点都可以访问Session信息:SESSION技术的实现是依赖COOKIE技术的。
两种会话技术区别(🌈身份证和银行卡的区别)
- 安全性方面 a. Session存储服务器端,安全性高 b. Cookie存储浏览器端,安全性低
- 数据大小方面 a. Cookie的数量和大小都有限制(20个/4K) b. Session数据存储不限
- 可用数据类型 a. Cookie只能存储简单数据,数值/字符串 b. Session可以存储复杂数据(自动序列化)
- 保存位置方面 a. Cookie保存在浏览器上 b. Session保存在服务器上
COOKIE
COOKIE 原理与基本使用
COOKIE原理
COOKIE技术:服务器将数据通过HTTP响应存储到浏览器上,浏览器可以在以后携带对应的COOKIE数据访问服务器。
- 第一次请求时,PHP通过setcookie函数将数据通过http协议响应头传输给浏览器
- 浏览器在第一次响应的时候将Cookie数据保存到浏览器
- 浏览器后续请求同一个网站的时候,会自动检测是否存在Cookie数据,如果存在将在请求头中将数据携带到服务器
- PHP执行的时候会自动判断浏览器请求中是否携带Cookie,如果写到,自动保存到 $_ COOKIE 中
- 利用 $_ COOKIE 访问 Cookie 数据
设置COOKIE信息
setcookie 函数用来设定 COOKIE 信息
setcookie (名字,值)
- cookie名的设置:字符串,第一个参数
- cookie值的设置:第二个参数
- cookie值的类型要求:必须是简单类型中的整数或者字符串
//设置COOKIE
setcookie('age',1);
setcookie('name','Martin');
🍎查看浏览器中的Cookie
读取COOKIE信息
🌈 COOKIE(会话技术)能够实现跨脚本共享数据
echo '<pre>';
//读取COOKIE
var_dump($_COOKIE);
🍎
array(3) {
["Phpstorm-6d42c3c3"]=>
string(36) "544459c3-a698-4c59-8a6e-02f21677a31f"
["age"]=>
string(1) "1"
["name"]=>
string(6) "Martin"
}
COOKIE 高级使用
COOKIE 生命周期
COOKIE生命周期:COOKIE在浏览器生存时间(浏览器在下次访问服务器的时候是否携带对应的COOKIE)
- 默认(不设定)时的生命周期:不设定周期默认是关闭浏览器(会话结束)
- 设定为一个常规日期戳的周期:通过 setcookie 第三个参数可以限定生命周期,是用时间戳来管理,从格林威治时间开始
//设置COOKIE setcookie('a1','a1'); //普通COOKIE,浏览器关闭失效 setcookie('a2','a2',7*24*60*60); //格林威治时间7天过期 setcookie('a3','a3',time() + 7*24*60*60); //格林威治时间从现在开始7天后过期
🍎
🐖 没有 “a2” 说明:浏览器发现本来就无效的COOKIE直接不保存
浏览器关闭后重新查看
发现只剩下 “a3”
- 设定为“0”的周期:在第三个参数设定生命周期的时候,用0代替时间戳:表示就是普通设置,会话结束过期 🌈 默认值为 0 , 即”到期时间”为”浏览会话结束时”
//0生命周期
setcookie('a4','a4',0);
🍎
- 删除一个cookie的做法:服务器没有权限去操作浏览器上的内容(不可能删除)。可以通过设定生命周期来让浏览器自动判定COOKIE是否有效:无效就清除
- 4.1 清空COOKIE数据内容
- 4.2 设定时间戳过期
//“删除”COOKIE
//setcookie('a3',''); //清空COOKIE数据内容
setcookie('a3','a3',time()); //设定时间戳过期
COOKIE 作用范围
作用范围:不同的文件夹层级中,设定的 COOKIE 默认是在不同的文件夹下有访问限制。 上层文件夹中设定的 COOKIE 可以在下层(子文件夹)中访问,而子文件夹中设定的 COOKIE 不能在上层文件夹中访问。
- 默认(不设定)的范围:就是使用COOKIE默认的作用范围 🌰father.php ```php //访问COOKIE var_dump($_COOKIE);
//设定普通COOKIE setcookie(‘father1’,’father1’);
🍎
![](/files/php/2019-10-28-PHP-15.会话技术-dc06f9f7.png)
2. 设定为 “/” 的含义:告知浏览器当前COOKIE的作用范围是网站根目录 `etcookie (名字,值,生命周期,作用范围)`
🌰son.php
```php
//访问COOKIE
var_dump($_COOKIE);
//设定普通COOKIE
setcookie('son1','son1');
//设定全局访问COOKIE(localhost) 👉 指定路径的 COOKIE , 使 father 也能访问
setcookie('global_son','global_son',0,'/');
🍎
COOKIE跨子域
跨子域:在同一级别域名下,myitcast.com(一级域名),可以有多个子域名(www.myitcast.com和gz.myitcast.com),他们之间是搭建在不同的服务器上(不同文件夹:E:/server/apache/htdocs和E:/web),但是可以通过COOKIE设置实现对应的COOKIE共享访问。但是默认是不允许跨域名访问的。 🌴
- hosts中增加映射
C:\Windows\System32\drivers\etc\hosts
加入127.0.0.1 blog.mysite.com
- Apache24
httpd-vhosts.conf
中C:\fastwork\Apache24\conf\extra\httpd-vhosts.conf
# 再配置一个 blog.mysite.com:80
# 嗯~~主要是用来测 COOKIE跨子域 效果的 👉 setcookie('xxxaa','跨域写入 COOKIE',0,'/','mysite.com');
<VirtualHost *:80>
DocumentRoot "${SRVROOT}/htdocs"
ServerName localhost
<Directory "${SRVROOT}/htdocs">
Order Deny,Allow
# Deny from all
Allow from all
Options Indexes FollowSymLinks
DirectoryIndex index.html index.htm index.php
</Directory>
</VirtualHost>
- 设定cookie的有效域名:不同的域名(包含主机)之间不能共享COOKIE
可以通过setcookie的第五个参数来控制setcookie(名字,值,生命周期,作用范围,有效域名)
- 不设定时的默认有效域名,互不相同
- 跨子域的设定方法:在设定域名访问的时候用设定上级域名即可:myitcast.com ,这个是有 所有以 myitcast.com 结尾的网站都可以共享 COOKIE
test.php
echo '<pre>';
var_dump($_COOKIE);
//设定一个本地COOKIE
setcookie('local','local',0,'/');
//指定域名COOKIE
setcookie('消消息','跨域写入COOKIE',time() + 7*24*60*60,'/','mysite.com');//格林威治时间从现在开始7天后过期
🍎 运行结果
设置中查看COOKIE
若改用设置 setcookie('消消息','跨域写入COOKIE',time()+7*24*60*60,'/','www.mysite.com');
🍎🍎
什么都写不进去…
🐖 必须是同一域名 ‘mysite.com’ 下的子域名才能彼此设置, 比如通过
localhost/test.php
去为www.mysite.com
增加 COOKIE 则无效 ; 需要使用blog.mysite.com
进行设置才能成功 。
COOKIE 数组数据
COOKIE本身只支持简单数据(数字或者字符串),能够保留的数据本身有限,也不成体系。
如果需要使用COOKIE来保留一组数据的化,想办法凑成数组。(COOKIE不支持数组)
- 设置形式: setcookie(‘c1[k1]’, 值)
- 读取形式: $_ COOKIE[‘c1’][‘k1’]
🌰
//使用“数组”保存COOKIE
//尝试保存数组
//setcookie('goods_ids',array(1,2,3,4,5));
//🍎错误: Warning: setcookie() expects parameter 2 to be string, array given in C:\fastwork\Apache24\htdocs\test.php on line 6
//伪装数组
setcookie('goods_ids[0]','abcdefghijklmn');
setcookie('goods_ids[1]','小明');
setcookie('goods_ids[2]',2333);
setcookie('goods_ids[3]',66281);
echo '<pre>';
print_r($_COOKIE);
//echo $_COOKIE['goods_ids'][1]; //🍎 小明
🍎
Array
(
[goods_ids] => Array
(
[0] => abcdefghijklmn
[1] => 小明
[2] => 2333
[3] => 66281
)
)
SESSION
SESSION 原理
Session与浏览器无关,但是与Cookie有关。
- PHP碰到session_start()时开启session会话,会自动检测sessionID a) 如果Cookie中存在,使用现成的 b) 如果Cookie中不存在,创建一个sessionID,并通过响应头以Cookie形式保存到浏览器上
- 初始化超全局变量 $_ SESSION 为一个空数组
- PHP通过 sessionID 去指定位置(session文件存储位置)匹配对应的文件 a) 不存在该文件:创建一个sessionID命名文件 b) 存在该文件:读取文件内容(反序列化),将数据存储到 $_ SESSION 中
- 脚本执行结束,将 $_ SESSION 中保存的所有数据序列化存储到 sessionID 对应的文件中
SESSION基本使用
$_ SESSION 是通过 session_start() 函数的调用才会定义的,没有直接定义
- 启用 SESSION ,任何时候都需要开启 SESSION (脚本使用到 $_ SESSION 就开启一次)
- 设置 SESSION 信息, 如果想存储数据到 SESSION 中,那么只要不断给 $_ SESSION 数组添加元素即可
- 读取 SESSION 信息, $_ SESSION 就是一个数组,存储什么数据,什么方式存的,就是可以通过什么方式访问什么数据
🌰
//必须先开启 SESSION,否则报错:
//Notice: Undefined variable: _SESSION in C:\fastwork\Apache24\htdocs\test.php on line 7 NULL
//var_dump($_SESSION);
//开启 SESSION
session_start();
//设置 SESSION 数据
$_SESSION['name'] = 'Martin';
$_SESSION['hobby'] = array('basketball','football');
//访问 SESSION 数据
//echo $_SESSION['name'];
echo '<pre>';
print_r($_SESSION);
🍎
Array
(
[name] => Martin
[hobby] => Array
(
[0] => basketball
[1] => football
)
)
会话技术的本质是为了实现跨脚本共享数据:在一个脚本中定义数据,在另外一个脚本中保存数据
🌰在test.php中定义 SESSION 数据 ,在另外的脚本中保存数据
- 删除一个SESSION信息
unset($_SESSION['name']);
, 删除 SESSION 就是将 SESSION 数据清理掉($_ SESSION拿不到) - 删除全部SESSION信息
$_SESSION = array();
, 删除全部数据就是让 $_ SESSION 变成一个空数组
🌰
echo '<pre>';
session_start();
print_r($_SESSION);
//删除一个SESSION信息
unset($_SESSION['name']);
//删除全部SESSION信息
//$_SESSION = array();
print_r($_SESSION);
🍎删除一个
Array
(
[name] => Martin
[hobby] => Array
(
[0] => basketball
[1] => football
)
)
Array
(
[hobby] => Array
(
[0] => basketball
[1] => football
)
)
🍎删除全部
Array
(
[hobby] => Array
(
[0] => basketball
[1] => football
)
)
Array
(
)
SESSION 相关配置
SESSION 基础配置 php.ini
- session.name :session名字,保存到 COOKIE 中 sessionID 对应的名字
session.name = PHPSESSID
- session.auto_start :是否自动开启 session (无需手动 session_start()),默认是关闭的
session.auto_start = 0
- session.save_handler :session 数据的保存方式,默认是文件形式
session.save_handler = files
- session.save_path:session文件默认存储的位置 , 使用系统的文件夹存储不安全,需要指定对应存储路径
;session.save_path = "/tmp" 👉 session.save_path = "C:\fastwork\Server\Sessions"
SESSION 常用配置
- session.cookie_lifetime : PHPsessionID 在浏览器端对应 COOKIE 的生命周期,默认浏览器关闭后会话结束
session.cookie_lifetime = 0
- session.cookie_path :sessionID在浏览器存储之后允许服务器访问的路径(COOKIE有作用范围),默认网站根目录
session.cookie_path = /
- session.cookie_domain :COOKIE 允许访问的子域(COOKIE可以跨子域), 默认的 PHPsessionID 只能当前主机访问
session.cookie_domain =
,保证数据 的安全
配置的两种形式
- php.ini中配置:全局配置,修改php.ini中的配置项
session.save_path = "C:\fastwork\Server\Sessions
- 🌈脚本中配置: PHP可以通过 ini_set 函数来在运行中设定某些配置项(只会对当前运行的脚本有效),把这种配置称之为项目级
@ini_set('session.save_path','C:\fastwork\Server\Sessions');
销毁 SESSION
Session删除是指删除session数据,$_ SESSION 中看不到而已;销毁session是指删除session对应的session文件。
系统提供一个函数: session_destroy(),会自动根据 session_start 得到的 sessionID 去找到指定的session文件,并把其删除。
//开启session
session_start();
//删除数据:清空$_SESSION
var_dump($_SESSION);
//测试效果
sleep(5); //脚本休息5秒执行
//销毁session
session_destroy();
SESSION 垃圾回收机制
垃圾回收机制原理
session会话技术后,session文件并不会自动清除,如果每天有大量session文件产生但是又都是失效的,会增加服务器的压力和影响session效率。
垃圾回收,是指session机制提供了一种解决垃圾session文件的方式:给session文件指定周期,通过session文件最后更改时间与生命周期进行结合判定,如果已经过期则删除对应的session文件,如果没有过期则保留。这样就可以及时清理无效的僵尸文件,从而提升空间利用率和session工作效率。
- 任何一次session开启(session_start),session都会尝试去读取session文件
- 读取session文件后,有可能触发垃圾回收机制(在session系统中也是一个函数:自己有一定几率调用)
- 垃圾回收机制会自动读取所有session文件的最后编辑时间,然后加上生命周期(配置文件)与当前时间进行比较( 所有session文件 )
a) 过期:删除
b) 有效:保留
垃圾回收参数设置
- session.gc_maxlifetime = 1440 :规定的session文件最大的生命周期是1440秒,24分钟
- session.gc_probability = 1 :垃圾回收概率因子(分子)
- session.gc_divisor = 1000 :垃圾回收概率分母
默认的触发概率是1/1000
🌈php.ini
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
测试垃圾回收效果:
- 修改生命周期为2分钟,120秒
- 修改触发几率:100%
🌰 php.ini
session.gc_divisor = 1000 session.gc_maxlifetime = 120 🍎 session 文件会很快被删除(回收)
禁用COOKIE后如何使用SESSION
禁用COOKIE不能使用SESSION原因 Session技术需要利用到COOKIE技术来保存sessionID,从而使得PHP能够在跨脚本的时候得到相同的sessionID,从而访问同一个session文件。
解决思路:最终让session_start在开启之前拿到原来的sessionID(另外一个脚本的)
实现无COOKIE使用SESSION
在PHP中,想要解决没有COOKIE也实现session技术的方式有两种:
方案1(推荐):可以利用PHP提供的session函数:session_id和session_name来获得和设置sessionID或者name从而解决session_start产生新sessionID的情况(手动操作):
- 在session保存数据的脚本中获取sessionID和名字
- 想办法将数据传递给另外一个脚本:表单传值(URL或者form表单)
- 在需要使用到session的脚本中,先接收数据
- 组织session_start产生新的ID,告诉它已经存在:session_id($id)
echo '<pre>';
//开启
session_start();
//获取sessionID和名字
$id = session_id(); //获取是在session_start之后
$name = session_name(); //拿到名字(php.ini session.name)
echo $name . ' = ' . $id . '<br>';
//设置内容
$_SESSION['name'] = 'Changbao';
//传递给另外一个脚本
echo "<a href='test2.php?{$name}={$id}'>click</a>";
🍎
PHPSESSID = 7lhv7dctiksut4trk6aj88urjb
click
另外一个脚本,test2.php
echo '<pre>';
//访问session
//接收数据
$name = session_name();
$id = $_GET[$name];
//⭐ 设定sessionID
session_id($id);
//开启session
session_start();
//访问
var_dump($_SESSION);
🍎 点击 click
array(1) {
["name"]=>
string(8) "Changbao"
}
🐖 session_id() 既可以获取 PHPSESSID 也可以为新的脚本设置 PHPSESSID
方案2:可以利用session集中已经提供的解决方案自动操作(配置)
- 原因1:默认session配置只允许使用COOKIE保存sessionID:cookie_ony
- 原因2:默认关闭了其他能够传送数据的方式,只保留了COOKIE
- 修改PHP配置文件,开启其他方式传输sessionID,关闭只允许使用COOKIE传输功能
session.use_only_cookies = 0
需要关闭,从1变成0session.use_trans_sid = 1
开启其他方式保存sid,从0变成1
- 一旦配置开启,PHP会自动将sessionID和session名字在其他位置绑定数据,同时还会在session_start的时候,考虑其他方式传递(表单)的数据,而不是只有COOKIE
对比与方案一的改变:
//保存session数据
session_start();
$_SESSION['age'] = 40;
echo "<a href='40session_nocookie4.php'>click</a>";
test2.php
//访问session数据
session_start();
var_dump($_SESSION);