前言
我们都知道Web实现是基于HTTP协议的,而HTTP协议是无状态的。即服务器只会给客户端请求提供服务,不会记录用户上一次的行为,那么就是说如果用户在第一次做过登录的操作,那么用户第二次操作的时候服务器不会认为当前请求是上一个用户的操作而是认为是不同用户的请求,每一次都需要登录,这样用户的体验感极差,那么怎么解决这个问题呢?会话服务就很好的解决了这个问题( Cookie | Session )
一丶Cookie的使用
Cookie 是HTTP协议下,服务器或脚本可以维护客户信息的一种方式,用户在浏览器上的一个很小的文本文件。【常用来记忆 用户名、密码、个性化设置、个人偏好记录等等】
Cookie 保存在客户端(用户浏览器),可以手动删除。如果浏览器上的Cookie 太多,超过了系统所允许的范围(通常限制为50个,每个不超过4kb),浏览器会自动删除。
1.使用setcookie函数创建Cookie
setcookie('name','张三');
如何才能知道是否创建成功?F12 或右键检查,查看【Application】=>【Storage】=>[Cookies].查看是否有刚刚创建的Cookie 信息
2.设置Cookie的有效时间
如上,成功创建了Cookie ,但是我们关闭浏览器,再访问相同地址的URL,再次查看Application里的Cookie 发现:Cookie 已经失效了。所以我们知道如上创建的Cookie ,默认关闭浏览器就会失效。现在我用setcookie的第三个参数来设置有效时间,设置格式:
setcookie(key,value,time()+3600) //有效时间3600秒
要删除一个Cookie
应该设置过期时间为过去,以触发浏览器的删除机制
setcookie("name", "张三", time()-3600);
3.Cookie的作用路径范围
根目录(/)
---- x
----- b.php
---- a.php
Cookie 的有效路径范围,默认的路径值是 Cookie 所处的当前目录,如图的目录结构,a.php创建的Cookie ,默认的作用范围,所以b.php能访问到, 然后b.php创建的Cookie 作用范围/x,故a.php不能访问。
setcookie(key,value,time()+3600,'/') //Cookie 将在整个域名内有效
4.Cookie的作用的有效域名
如果我们在www.study.com域名下设置Cookie ,默认的这个cCookie ookie仅在 www 这个二级域名中有效。如果此时还有一个二级域名moblie.study.com想要和www进行共享Cookie ,我们 只需如下配置第5个参数
setcookie(key,value,time()+3600,'/','study.com')
设置成子域名(例如 ‘www.example.com’),会使 Cookie 对这个子域名和它的三级域名有效(例如 w2.www.example.com)。 要让 Cookie 对整个域名有效(包括它的全部子域名),只要设置成域名就可以了(这个例子里是 ‘example.com’)
5.Cookie 与安全的HTTPS
默认值:false;设置这个 Cookie 是否仅仅通过安全的 HTTPS 连接传给客户端,设置成 true 时,只有安全连接存在时才会设置 Cookie。 如果是在服务器端处理这个需求, 我们需要仅仅在安全连接上发送此类 Cookie (可以通过 $_SERVER[“HTTPS”] 判断)
6.Cookie的JavaScript访问
默认值:false; 如果我们设置true; Cookie 即仅可通过 HTTP 协议访问。 这意思就是 Cookie 无法通过类似 JavaScript 这样的脚本语言访问。
7.Cookie的工作原理
结合上图说:当用户初次对服务器发起请求时(1),服务器会执行对应的脚本,比如demo.php文件,执行setcookie函数(2)
# demo.php
setcookie('name','niege',time()+3600);
然后服务器会在响应消息的时候在响应头里添加Set-Cookie信息,将信息Cookie 的形式发送给浏览器(3)。 如果浏览器没有禁用Cookie ,便会接受了服务器发送的Cookie 信息,就会将它保存在浏览器的缓冲区中(4)。 这样当浏览器继续访问该服务器,都会携带Cookie 发送给服务器(5),从而使服务器分辨出当时请求是由那个用户发出的(6)
8.使用Cookie注意需要主要几个点
-
cookie被附加在每个http请求响应中,无形中增加了数据流量
-
cookie在http请求中是明文传输的,所以安全性不高,容易被窃取
-
cookie是来自浏览器的数据,可以被篡改,因此服务器接收后必须验证数据的合法性
-
浏览器限制cookie的数量和大小,chrome数量在50左右,每个不超过4kb,但是在测试-版本 71.0.3578.98(正式版本)可以创建168个
二丶Session的使用
1.Session的工作原理
当第一次访问网站时,Seesion_start()
函数就会创建一个唯一的Session ID
,并自动通过HTTP的响应头,将这个Session ID
保存到客户端Cookie
中。同时,也在服务器端创建一个以Session ID
命名的文件,用于保存这个用户的会话信息。当同一个用户再次访问这个网站时,也会自动通过HTTP的请求头将Cookie
中保存的Seesion ID
再携带过来,这时Session_start()
函数就不会再去分配一个新的Session ID
,而是在服务器的硬盘中去寻找和这个Session ID
同名的Session
文件,将这之前为这个用户保存的会话信息读出,在当前脚本中应用,达到跟踪这个用户的目的。 Session
以数组的形式使用,如:$_SESSION['session名']
2.Session初始化
Session的设置不同于Cookie,必须先启动,在PHP中必须调session_start()
,函数的语法格式如下:
session_start ([ array $options = array() ] ) : bool
session_start()
会创建新会话或者重用现有会话。 如果通过 GET 或者 POST 方式,或者使用 cookie 提交了会话 ID, 则会重用现有会话
注意:session_start()
函数之前不能有任何输出
3.注册一个会话变量和读取Session
在PHP中使用Session变量,除了要启动之外,还要经过注册的过程。注册和读取Session变量,都要通过访问$_SESSION
数组完成。在$_SESSION
关联数组中的键名具有和PHP中普通变量相同的命名规则。注册Session变量的代码如下所示:
<?php
//启动session的初始化
session_start();
//注册session变量,赋值为一个用户的名称
$_SESSION["username"] = "skygao";
//注册session变量,赋值为一个用户的ID
$_SESSION["uid"] = 1;
?>
执行该脚本后,两个Session变量就会被保存在服务器端的某个文件中,该文件的位置是通过php.ini
文件,在session.save_path
属性指定的目录下
4.注销变量与销毁Session
当使用完一个Session变量后,可以将其删除,当完成一个会话后,也可以将其销毁。如果用户退出Web系统,就需要为他提供一个注销的功能,把他的所有信息在服务器中销毁。销毁和当前Session有关的所有的资料,可以调用session_destroy()
函数结束当前的会话,并清空会话中的所有资源。该函数的语法格式如下所示:
session_destroy ( void ) : bool//销毁和当前Session有关的所有资料
该函数并不会释放和当前Session相关的变量,也不会删除保存在客户端Cookie中的SessionID
。因为$_SESSION
数组和自定义的数组在使用上是相同的,所以我们可以使用unset()
函数来释放在Session中注册的单个变量。如下所示:
unset($_SESSION['键名']);
一定要注意,不要使用unset($_SESSION)
删除整个$_SESSION
数组,这样将不能再通过$_SESSION
超全局数组注册变量了。但如果想把某个用户在Session中注册的所有变量都删除,可以直接将数组变量$_SESSION
赋上一个空数组。如下所示:
$_SESSION = array();
PHP默认的Session是基于Cookie的,SessionID被服务器存储在客户端的Cookie中,所以在注销Session时也需要清除Cookie中保存的SessionID,而这就必须借助setcookie()
函数完成。在PHP脚本中,可以通过调用session_name()
函数获取Session名称。删除保存在客户端Cookie中的SessionID,代码如下所示:
<?php
//判断Cookie中是否存在session ID
if(isset($_COOKIE[session_name()]))
{
//删除包含Session ID的cookie,注意第四个参数一定要和php.ini设置的路径相同
setcookie(session_name(),'',time()-3600,'/');
}
?>
通过前面的介绍可以总结出,Session的注销过程共需要4个步骤。在下例中,提供完整的四个步骤代码,运行该脚本就可以关闭Session,并销毁与本次会话有关的所有资源。代码如下所示:
<?php
//第一步:开启Session并初始化
session_start();
//第二部:删除所有Session的变量,也可以用unset($_SESSION[XXX])逐个删除
$_SESSION = array();
//第三部:如果使用基于Cookie的session,使用setCookkie()删除包含Session ID的cookie
if(isset($_COOKIE[session_name()]))
{
setCookie(session_name(), "", time()-42000, "/");
}
//第四部:最后彻底销毁session
session_destroy();
?>
5.Session的垃圾自动回收机制
可以通过session_destroy()
函数在页面中提供一个“退出”按钮,通过单击销毁本次会话。但如果用户没有单击退出按钮,而是直接关闭浏览器,或断网等情况,在服务器端保存的Session
文件是不会删除的。虽然关闭浏览器,下次需要重新分配一个新的Session ID
重新登录,但这只是因为在php.ini
中的设置seesion.cookie_lifetime = 0
,来设定Session ID
在客户端Cookie中
的有效限期,以秒为单位指定了发送到浏览器的Cookie
的生命周期。当系统赋予Session
有效期限后不管浏览器是否开启,Session ID
都会自动消失。而客户端Session ID
消失服务器端保存的Session
文件并没有被删除。所以没有被Sessoin ID
引用的服务器端Session
文件,就成为了“垃圾”。
服务器保存的Session
文件就是一个普通文本文件,所以都会有文件修改时间。“垃圾回收程序”启动后就是根据Session
文件的修改时间,将所有过期的Session文件全部删除。通过在php.ini中设置session.gc_maxlifetime
选项来指定一个时间(单位:秒),例如设置该选项值为1440(24分钟)。“垃圾回收程序”就会在所有Session文件中排查,如果有修改时间距离当前系统时间大于1440秒的就将其删除。
session垃圾回收程序是怎样的启动机制呢?垃圾回收程序是在调用session_start()
函数时启动的。而一个网站有多个脚本,没有脚本又都要使用session_start()
函数开启会话,又会有很多个用户同时访问,这就很可能session_start()
函数在1秒内被调用N次,而如果每次都会启动Session
垃圾回收程序,这样是很不合理的。可以通过php.ini
文件中修改session.gc_probability
和session.gc_divisor
两个选项,设置启动垃圾回收程序的概率。会根据session.gc_probability/session.gc_divisor
公示计算概率,例如选项session.gc_probability=1
,而选项session.gc_divisor=100
,这样的概率就是1/100
,即session_start()
函数被调用100次才会有一次可能启动垃圾回收程序
6.Session的php.ini配置选项
配置名称 | 说明 |
---|---|
session.auto_start = 0 ; | 在请求启动时初始化session |
session.cache_expire = 180 ; | 设置缓存中的会话文档在 n 分钟后过时 |
session.cookie_lifetime = 0 ; | 设置按秒记的cookie的保存时间,相当于设置Session的过期时间,为0时表示直到浏览器被重启 |
session.auto_start = 1; | 这样就无需每次使用session之前都要调用session_start() 不建议使用.但启用该选项也有一些限制,如果确实启用了 session.auto_start ,则不能将对象放入会话中,因为类定义必须在启动会话之前加载以在会话中重建对象 |
session.cookie_path = / ; | cookie的有效路径 |
session.cookie_domain = ; | cookie的有效域 |
session.name = PHPSESSID; | 用在cookie里的session的名字 |
session.save_handler = files ; | 用于保存/取回数据的控制方式 |
session.save_path = /tmp ; | 在 save_handler 设为文件时传给控制器的参数, 这是数据文件将保存的路径 |
session.use_cookies = 1 ; | 是否使用cookies |
session.cookie_lifetime=0; | 关闭浏览器相应的cookie文件即被删除 |
session.gc_maxlifetime; | 设置过期session时间,默认1440秒(24分钟) |
session.gc_probability/session.gc_divisor; | 启动垃圾回收机制的概率(建议值为1/1000——5000) |
7.Cookie禁用时通过URL传递Session的ID
使用Session跟踪一个用户,是通过在各个页面之间传递唯一的Session ID,并通过Session ID提取这个用户在服务器中保存的Session变量。常见的Session ID传送方法有以下两种。
第一种方法是基于cookie的方式传递session ID,这种方式更优,但不总是可用, 因为用户在客户端可以屏蔽cokie;
第二种方法是通过url参数进行传递,直接将session ID嵌入到URL中去。
在Session的实现中通常都是采用Cookie的方式,客户端保存的Session ID就是一个Cookie。当客户禁用Cookie时,Session ID就不能在Cookie中保存,也就不能在页面之间传递,此时Session失效。不过PHP5在Linux平台可以自动检查Cookie状态,如果客户端禁用它,则系统自动把Session ID附加到URL上传送。而使用Windows系统作为Web服务器则无此功能。
在PHP中提出了跟踪Session的另一种机制,如果客户浏览器不支持Cookie,则PHP可以重写客户请求的URL,把Session ID添加到URL信息中。可以手动地在每个超链接的URL中都加上一个Session ID,但工作量比较大,不建议使用这种方法。如下所示:
<?php
//开启session
session_start();
//在每个URL后面附加上参数,变量名为session_name()获取名称,值通过session_id()获取
echo '<a href="demo.php?'.session_name().'='.session_id().'">连接演示</a>';
?>
在使用Linux系统做服务器时,则在编辑PHP时如果使用了–enable-trans-sid
配置选项,和运行时选项session.use_trans_sid
都被激活,在客户端禁用Cookie时,相对URL将被自动修改为包含会话ID。如果没有这么配置,或者使用Windows系统作为服务器时,可以使用常量SID。该常量在会话启动时被定义,如果客户端没有发送适当的会话Cookie,则SID的格式为session_name = session_id
,否则就为一个空字符串。因此可以无条件地将其嵌入到URL中去。在下例中使用两个脚本程序,演示了Session ID的传送方法。
<?php
session_start();
$_SESSION["username"] = "admin";
echo "session ID:".session_id()."<br>";
?>
三丶 Cookie 与 Session的区别
1.数据存放位置不同
Cookie数据存放在客户的浏览器上,Session数据放在服务器上
2.安全程度不同
Cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用Session
3.性能使用程度不同
Session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用Cookie
4.数据存储大小不同
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie,而Cession则存储与服务端,浏览器对其没有限制
5.会话机制不同
Session会话机制:Session会话机制是一种服务器端机制,它使用类似于哈希表(可能还有哈希表)的结构来保存信息
cookies会话机制:Cookie是服务器存储在本地计算机上的小块文本,并随每个请求发送到同一服务器。 Web服务器使用HTTP标头将Cookie发送到客户端。在客户端终端,浏览器解析Cookie并将其保存为本地文件,该文件自动将来自同一服务器的任何请求绑定到这些Cookie