Session 的概念

Session 和 Cookie 一样,也是针对 HTTP 的局限性而提出的一种保持客户端和服务器端会话连接状态的机制。

Session 被称为会话,指用户在进入网站到浏览器关闭(或退出网站)这段时间内与 Web 系统的会话过程。

Session 的存储 

Session 保存在服务器端,默认情况以文件的形式保存在服务器硬盘上,每个 Session 一个文件,文件名如:sess_j64kv3np0ft2u00aun0cilqdo2,里面保存的内容结构是:变量名 | 类型:长度:值;

例如:

name|s:3:"dee";level|i:2;

在 php.ini 中,session.save_handler 定义了存储和获取 Session 数据的处理器的名字,默认为 files,表示使用文件形式保存 Session:

session.save_handler = files

也可以设置成用户自定义方式存储 Session 的 user 或者 memcache 来使 Session 保存到关系型数据库或者 Memcache 等内存服务器中。

在 php.ini 中,session.save_path 表示 Session 存储的位置,在 WAMPSERVER 环境下的默认值是:

session.save_path = "d:/wamp/tmp"

表示 Session 文件存储在 d 盘 wamp/tmp 目录下; Windows 环境中在该配置被注释的情况下 Session 可能保存在 C:\Windows\Temp 目录下,Linux 环境中在该配置被注释的情况下 Session 保存在 /tmp 或 /var/lib/php/session 目录下。

当 Session 保存在 Memcache 中时可以修改该配置,例如:

session.save_path = "tcp://127.0.0.1:11211,tcp://127.0.0.1:11212"

以上配置代表将 Session 保存到两台 Memcache 服务器中。

当 Session 以文件形式保存时,默认是保存在硬盘的一个目录下,当 Session 比较多时,磁盘读取文件会比较慢,通常一个目录下文件数量超过 2000 个时,读写这个目录就会比较慢。此时可以考虑将 Session 分目录存放。session.save_path 有一个可选的 N 参数来决定 Session 文件分布的目录深度,格式是:

session.save_path = "N;MODE;/path"

N 表示要设置的目录级数,MODE 表示目录的权限属性,默认为 600(Windows 中不需要设置),/path 表示 Session 文件存放的根目录路径每一级目录分别以 0 - 9 和 a - z 共 36 个字符作为目录名,这样存放 Session 的目录可以达到 36^36 个。创建文件夹的工作需要 PHP 来完成。

例如,2 级目录即 N = 2 时可以这样设置:

<?php
//设置Session目录分级与保存路径
ini_set('session.save_path', "2;/wamp/tmp"); //创建2级目录
$string = '0123456789abcdefghijklmnopqrstuvwxyz';
$length = strlen($string);
for($i = 0; $i < $length; $i++) {
for($j = 0; $j < $length; $j++) {
createfolder('d:/wamp/tmp/'.$string[$i].'/'.$string[$j]);
}
} function createfolder($path) {
if(!@file_exists($path)) {
createfolder(@dirname($path));
@mkdir($path, 0777);
}
} session_start();
$_SESSION['name'] = 'dee'; echo session_id();

打印出的 Session ID 为 3b9ptga94p7b5v1s33dnacrf95,那么 PHP 会根据该 ID 的前两位字符来存储 Session 文件,即该 Session 文件存储在 d:/wamp/tmp/3/b 下:

如果使用了 N 参数并且大于 0,那么 PHP 将不会自动回收过期的 Session,需要通过 shell 或者 cron 来清除过期的文件。

Session 的开启

通过 session_start 函数创建新会话或者重用现有会话,在 session_start 函数之前页面不能有任何的输出内容(当 php.ini 中 的output_buffering = Off 时)。

当自动开启会话或者通过 session_start() 手动开启会话的时候, PHP 内部会调用会话管理器(save_handler)的 open 、 read 和 gc 回调函数。

会话管理器默认为文件(file), 也可以是 SQLite 或者  Memcached 扩展, 还可以通过 session_set_save_handler() 设定的用户自定义会话管理器,并通过 read 回调函数返回现有的(经过序列化的)会话数据, PHP 会自动反序列化数据并且赋给 $_SESSION 超级全局变量。

Session ID 及其传递

Session 的唯一标识 Session ID,是由 32 位十六进制数组成的字符串,php.ini 中 session.use_cookies 的默认值为 1,即默认通过 Cookie 来进行保存和传递:

session.use_cookies = 1

通过设置也能在客户端禁用了 Cookie 之后通过 URL 或者隐藏表单进行 session_id 的 GET 或 POST 传递。

如果需要在 Cookie 被禁用时仍然能使用 Session,需要修改 php.ini 中的几个配置:session.use_only_cookies 和 session.use_trans_sid,这两个参数的默认值分别是 1 和 0,分别代表在客户端仅仅使用 Cookie 来存放 Session ID ,和指定不启用透明 Session ID 支持(即在 URL 中不自动加上 Session ID 的参数):

session.use_only_cookies = 1
session.use_trans_sid = 0

需要把这两个配置修改为:

session.use_only_cookies = 0
session.use_trans_sid = 1

此时如果禁用了 Cookie,则 URL 的格式为 格式为 a.php?PHPSESSID=session_id

将 session_id 通过 URL 进行传递的缺点有:1. 安全性,将 session_id 暴露在了 URL 中 2. 当禁用了 Cookie 后,如果 URL 中没有传递 session_id(例如重复访问第一个设置 Session 的页面),就会使系统不能重用现有会话而重新生成新的会话。

例 在 FireFox 40.0.3 下,设置禁用 Cookie:

”工具“ -- ”选项“ -- ”隐私“ -- ”使用自定义历史记录设置“ -- 取消勾选 ”接收来自站点的Cookie“

session_url_set.php:

<?php
header("Content-type:text/html;charset=utf-8"); ini_set('session.use_trans_sid', 1);
ini_set('session.use_only_cookies', 0); session_start(); $_SESSION['user'] = 'dee'; echo session_id();
echo '<pre>';
print_r($_SESSION);
echo '<a href="session_url_get.php" target="_blank">跳转</a>';

输出:

session_url_get.php

<?php

ini_set('session.use_trans_sid', 1);
ini_set('session.use_only_cookies', 0); session_start(); echo session_id();
echo '<pre>';
print_r($_SESSION);

输出:

session_id 自动成为 URL 参数。

但是此时再次刷新 session_url_set.php 时,会重新生成新的 Session:

当用户向服务器服务器发出请求时,服务器会首先检查请求中是否已经包含了 Session ID(通过请求头中 Cookie 中的 PHPSESSID 或者 URL 中的参数 PHPSESSID ),如果包含则服务器会重复使用该 Session ID,如果不包含,则生成一个新的 Session ID。

注意:URL 自动带上 Session ID 参数的条件是 ① 当前 Cookie 中不包含 Session ID ;② session.use_trans_sid 设置为 1 ;③ session.use_only_cookies 设置为 0

可以通过修改 php.ini 中的 session.name 来修改 Seeesion Name,默认这是 PHPSESSID:

session.name = PHPSESSID

可以通过在 PHP 脚本中输入 session_name() 来查看当点的 Session Name :

echo session_name();

可以通过 session_id() 来查看当前的 Session ID:

echo session_id();

输出的值和对应的 Session 文件名相对应,例如 Session ID 是 j64kv3np0ft2u00aun0cilqdo2,文件名是 sess_j64kv3np0ft2u00aun0cilqdo2。

注销变量和销毁 Session

Session 的注销包括 4 个步骤:

<?php

//1.开启 Session
session_start(); //2.删除所有的 Session 变量
$_SESSION = array(); //3.如果是基于 Cookie 的 Session,则删除该 Cookie
if(isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time() - 1, '/');
} //4.彻底销毁 Session
session_destroy();

此时 保存 Session ID 的 Cookie已经被清除,Session 文件的内容已经被清空,但是服务器上的 Session 文件的删除则需要依赖 Session 的垃圾回收机制。

Session 的生存周期和垃圾回收机制

默认情况下,Session ID 存储在 Cookie 中,该 Cookie 默认设置过期时间为 0,即随着浏览器关闭而消失(Cookie 保存在内存中),php.ini 的设置:

session.cookie_lifetime = 0

关闭浏览器后该 Session ID 自动注销,如果重新请求该页面则会重新注册一个新的 Session ID。

但是 Session 文件可能仍然存在,原因是 Session 的垃圾回收机制。和 Session 的垃圾回收机制相关的函数是:session_start(),在调用该函数时启动回收机制,相关的 3 个配置分别是 :session.gc_maxlifetime,表示 Session 文件的过期时间,默认为 1440 秒即 24分钟能、session.gc_probabilitysession.gc_divisor,后面两个配置的默认值分别是 1 和 1000,代表 session_start() 函数每调用 1000 次触发一次 Session 文件的全部扫描,把过期的 Session 文件删除:

session.gc_maxlifetime = 1440
session.gc_probability = 1
session.gc_divisor = 1000

过期的 Session 文件的判断标准是:文件的修改时间和当前时间相差是否大于 session.gc_maxlifetime。当用户每进行一个操作哪怕是一个刷新页面的动作时,都会修改 Session 文件的修改时间。

可以手动设置 Session 的生命周期:

$life_time = 3600 * 24;
setcookie(session_name(), session_id(), time() + $life_time, '/');

经过设置,在关闭浏览器后,保存 Session ID 的 Cookie 的生命周期达到了 24 小时,也就是在 24 小时内即使关闭了浏览器,下次再访问该页面时 PHP 会重用该 Session。

可以通过设置较短的 session.gc_maxlifetime 和 较小的 session.gc_divisor 来观察 Session 的过期机制:

把 session.gc_maxlifetime 设为 10(秒),即 10 秒内用户没有任何操作(包括刷新)的话,10 秒后该会话即成为过期 Session;把 session.gc_divisor 分别设为 1 和 2,也就是 session.gc_probability /  session.gc_divisor = 1 或 1/2,意思是每一 或 两次访问网站(页面),都将扫描所有的 Session 文件,同时将过期的 Session 文件从硬盘上删除(当 Session 以 files 形式存储时),来观察 Session 的垃圾回收机制。注意 session.cookie_lifetime 要和 session.gc_maxlifetime 设置为相同的值。

session_cookie_set.php

<?php
header("Content-type:text/html;charset=utf-8"); ini_set('session.cookie_lifetime', 10);
ini_set('session.gc_maxlifetime', 10);
ini_set('session.gc_divisor', 1); session_start(); $_SESSION['username'] = 'deathmask'; echo session_id();
echo '<pre>';
print_r($_SESSION);
echo '<a href = "session_cookie_get.php" target="_blank">跳转</a>';

session_cookie_get.php

<?php

ini_set('session.cookie_lifetime', 10);
ini_set('session.gc_maxlifetime', 10);
ini_set('session.gc_divisor', 1); session_start(); echo session_id();
echo '<pre>';
print_r($_SESSION);

观察硬盘上 Session 文件的删除情况。

参考:

session.save_path目录大量session临时文件带来的服务器效率问题

PHP设置session定期自动清理的例子

PHP session 暫存檔過多的注意事項

PHP Session文件的散列存储及过期删除

Session 知识点再整理(一)基本概念和原理的更多相关文章

  1. Session 知识点再整理(二) 自定义 Session 存储机制

    对于访问量大的网站,用默认的 Session 存储方式(以文件存储)不适合,因为文件的 I/O 开销会非常大,另外 Session 机制本身使 Session 不能跨机访问,在 Web 集群中无法达到 ...

  2. Cookie 知识点再整理

    1. Cookie  是存储在客户端 内存 或者 硬盘(例如火狐把 Cookie 存储在 C:\Documents and Settings\用户名\Application Data\Mozilla\ ...

  3. 【体系结构】有关Oracle SCN知识点的整理

    [体系结构]有关Oracle SCN知识点的整理 1  BLOG文档结构图   BLOG_Oracle_lhr_Oracle SCN的一点研究.pdf 2  前言部分 2.1  导读和注意事项 各位技 ...

  4. web开发前端面试知识点目录整理

    web开发前端面试知识点目录整理 基本功考察 关于Html 1. html语义化标签的理解; 结构化的理解; 能否写出简洁的html结构; SEO优化 2. h5中新增的属性; 如自定义属性data, ...

  5. 再谈mysql锁机制及原理—锁的诠释

    加锁是实现数据库并发控制的一个非常重要的技术.当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁.加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更 ...

  6. Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)

    ORACLE集群概念和原理(二) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...

  7. Java线程:概念与原理

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  8. RabbitMQ基本概念和原理

    RabbitMQ基本概念和原理 1.AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计. 2.Rabb ...

  9. Java编程的逻辑 (35) - 泛型 (上) - 基本概念和原理

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

随机推荐

  1. MVC 异常处理机制

    方法一 :web.config配置文件的 system.web 接点下添加,若为On则不会将异常信息反馈到用户,而是友好的跳转到error.htm <customErrors mode=&quo ...

  2. 转:Docker学习---挂载本地目录

    原文: http://my.oschina.net/piorcn/blog/324202 docker可以支持把一个宿主机上的目录挂载到镜像里 docker run -it -v /home/dock ...

  3. 01背包 ZOJ 3931 Exact Compression

    题目连接 题意:n个数字构建哈夫曼树,问是否存在这样一棵树使得:(Fi数字大小,Ci哈夫曼表示下,'0'的数量) 分析:每次从优先队列取出两个数字可以互换位置,这样可以01互换.设a[i] <= ...

  4. VMware 锐捷 NAT模式的服务自动关闭的解决办法

    之前一直搞不定VMware和锐捷的问题,校园网,你懂的. 后来发现,使用NAT模式联网时,锐捷会间隔性地终结windows系统的那个关于NAT联网的服务,你可以在计算机管理 - 服务,找到一个写有NA ...

  5. 快学Java NIO

    Java NIO Tutorial 地址:http://tutorials.jenkov.com/java-nio/index.html Java NIO系列教程译文地址:http://ifeve.c ...

  6. RColorBrewer包---R语言的配色方案

    // RColorBrewer包介绍 RColorBrewer包提供了3套很好的配色方案.用户只需要指定配色方案的名称,就可以用包中的brewer.pal()函数生成颜色.这3套配色方案包括: 连续型 ...

  7. jqgrid在colModel中多次调用同一个字段值

    Debug: 代码1: { name : 'input', index : 'input', width : 100, align : "center", formatter : ...

  8. hadoop2.0安装中遇到的错误:mapreduce.shuffle set in yarn.nodemanager.aux-services is invalid

    转:http://blog.csdn.net/bamuta/article/details/12995139 解决办法 : 在1个网站上找到了解决方法,(网络忘了没记)urg, my copy/pas ...

  9. Codeforces Round #353 (Div. 2) A. Infinite Sequence

    Vasya likes everything infinite. Now he is studying the properties of a sequence s, such that its fi ...

  10. ACM 盗梦空间

    盗梦空间 时间限制:3000 ms  |  内存限制:65535 KB 难度:2   描述 <盗梦空间>是一部精彩的影片,在这部电影里,Cobb等人可以进入梦境之中,梦境里的时间会比现实中 ...