`
victorwmh
  • 浏览: 213702 次
  • 性别: Icon_minigender_1
  • 来自: 宇宙
社区版块
存档分类
最新评论

PHP Session原理分析及使用

    博客分类:
  • php
阅读更多

     之前在一个叫魔法实验室的博客中看过一篇《php session原理彻底分析》的文章,作者从session的使用角度很好阐述了在代码运行过程中,每个环节的变化以及相关参数的设置及作用。本来想把原文转帖过来,但是原博客被关闭了。不知是这次大范围的重新备案,还是其他什么原因所致。通过百度快照找到一些原文资料,没找到的将按之前的理解重新整理,以使大家对session能有更多了解。

楔子:Session大白话

Session,英文翻译为“会话”,两个人聊天,从第一句问好,到最后一句再见,这就构成了一个会话。PHP里的session主要是指客户端浏览器与服务端数据交换的对话,从浏览器打开到关闭,一个最简单的会话周期。计算机语言一般怎么实现会话呢?举个通俗的例子:
服务端好比一个理发店,客户端好比每一个去理发的客人,很多理发店都有这种促销手段,连续消费10次的客人,可以免费一次,大概有三种方式来实现:
1、理发师傅记性太好,你来过几次,他看一眼就知道——这叫协议本身支持会话;
2、每个客人发一个会员卡,你每次消费,都要带着这个卡片,消费一次记录一笔,当然还要加盖印章——这叫通过cookie实现会话,缺点是安全性不高,我完全可以伪造会员卡或者公章;
3、理发店准备一个大帐本,客人每人对应一个会员号或者自己的个人资料,甚至密码,每个客人来消费,报一下自己的会员号,再把消费次数记录到大帐本里——这就是session实现会话,客人脑子里的会员号就是保存在客户端的SESSIONID,大帐本就是保存在服务端的session数据,这样相比第二种方法,安全性要高很多,除非你说你把自己的会员号和密码都搞丢了,这叫做伪造客户端的SESSIONID。
 
因为http协议是无状态的,所以php要实现会话只能通过后面两种方式,前一种cookie,缺点已经说了,安全性不高,所以重要的会话会选择使用session。session会话必须依靠一个标识,也可以理解成一个暗号,就是SESSIONID。这是个经过加密的串,保存在客户端,通常在cookie里,客户端与服务端的每次交流都是通过这个SESSIONID,客户端先自报家门,服务器才能找到你在服务端保存的会话数据,继续通话。

php.ini常用session设置

[服务端]
session.save_handler = files
默认为file,定义session在服务端的保存方式,file意为把sesion保存到一个临时文件里,如果我们想自定义别的方式保存(比如用数据库),则需要把该项设置为user;
 
session.save_path = "/tmp/"
定义服务端存储session的临时文件的位置。
 
session.auto_start = 0
如置1,则不用在每个文件里写session_start(); session自动start。
 
session.gc_probability = 1
session.gc_divisor = 100
session.gc_maxlifetime = 1440
这三个配置组合构建服务端session的垃圾回收机制session.gc_probability与session.gc_divisor构成执行session清理的概率,理论上的解释为服务端定期有一定的概率调用gc函数来对session进行清理,清理的概率为:gc_probability/gc_divisor 比如:1/100  表示每一个新会话初始化时,有1%的概率会启动垃圾回收程序,清理的标准为session.gc_maxlifetime定义的时间。
 
[客户端]
session.use_cookies = 1
sessionid在客户端采用的存储方式,置1代表使用cookie记录客户端的sessionid,同时,$_COOKIE变量里才会有$_COOKIE[‘PHPSESSIONID’]这个元素存在;
 
session.use_only_cookies = 1
也是定义sessionid在客户端采用的存储方式,置1代表仅仅使用 cookie 来存放会话 ID。一般来说,现在客户端都会支持cookie,所以建议设置成1,这样可以防止有关通过 URL 传递会话 ID 的攻击。
 
session.use_trans_sid = 0
相对应于上面那个设置,这里如果置1,则代表允许sessionid通过url参数传递,同理,建议设置成0;
 
session.referer_check = 
这个设置在session.use_trans_sid = 1的时候才会生效,目的是检查HTTP头中的"Referer"以判断包含于URL中的会话id是否有效,HTTP_REFERER必须包含这个参数指定的字符串,否则URL中的会话id将被视为无效。所以一般默认为空,即不检查。 
 
session.name = PHPSESSID
定义sessionid的名称,即变量名,通过浏览器http工具可以查看PHPSESSID的值;
 
session.hash_function = 0
选择session_name的加密方式,0代表md5加密,1代表sha1加密,默认是0,但是据说用sha1方式加密,安全性更高;
 
session.hash_bits_per_character = 4
指定在session_name字符串中的每个字符内保存多少位二进制数,这些二进制数是hash函数的运算结果。
4   bits:   0-9,   a-f 
5   bits:   0-9,   a-v 
6   bits:   0-9,   a-z,   A-Z,   "-",   ","
 
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fieldset="
指定重写哪些HTML标签来包含sid(session_id)(仅在"session.use_trans_sid"打开的情况下有效),URL重写器将添加一个隐藏的"<input>",它包含了本应当额外追加到URL上的信息。 
 
session.cookie_lifetime = 0
保存sessionid的cookie文件的生命周期,如置0,代表会话结束,则sessionid就自动消失,常见的强行关闭浏览器,就会丢失上一次的sessionid;
 
session.cookie_path = /
保存sessionid的cookie文件在客户端的位置;
 
session.cookie_domain = /
保存sessionid的cookie的域名设置,这跟cookie允许的域名的访问权限设置有关,一般来说想让自己网站所有的目录都能访问到客户端的cookie,就应该设置成“/”如需要详细了解,可以看下setcookie()函数的domain参数相关设置和使用方法;
 
session.bug_compat_42 = 1
session.bug_compat_warn = 1
这两个可以说几乎是快要被废弃的设置,是为了老版本的php服务的,主要是针对session_register函数,因为php5的register_global默认是关闭状态,所以在php5里根本用不到session_register这个函数;并且php6就要废除这个设置,直接定义为关闭,所以没必要研究这两个了;


session_start()做了些什么?

假设php.ini中session的几个关键参数配置为:
session.save_handler = files
session.use_cookies = 1
session.name = PHPSESSID
session.save_path = "/tmp/"

 

下面通过代码样例阐述,在一个会话过程中session_start的作用。

程序1:
<?php
session_start();
$_SESSION['uname'] = 'monkey';
$_SESSION['ukey'] = 20119999;
?>


程序1执行后,session_start()会做两件事:


1、在客户端生成一个存放PHPSESSID的cookie文件,这个文件的存放位置和存放方式跟程序的执行方式有关,不同的浏览器也不尽相同,这一步会产生一个序列化后的字符串——PHPSESSID;查看浏览器中的cookie信息,可以安装相关插件。firefox中httpfox,web developer等都是很好的工具。


2、在服务端生成一个存放session数据的临时文件,存放的位置由session.save_path参数指定,名称类似于“sess_85891d6a81ab13965d349bde29b2306c”,“sess_”代表这是个session文件,“85891d6a81ab13965d349bde29b2306c”即此次会话的PHPSESSID,跟客户端的PHPSESSID值是一样的。
用编辑器打开“sess_85891d6a81ab13965d349bde29b2306c”文件,会看到一串“uname|s:6:"monkey";ukey|i:20119999;”这样的内容。这个文件里存放的就是$_SESSION变量的具体内容,每个变量用“;"分号隔开。


格式为:变量名 | 变量类型 : [长度] : 值; 例如: uname|s:6:"monkey"; 表示SESSION变量uname的类型为字符串,值长度为6,值为monkey.

那么问题来了,上面说的两件事,是在程序执行到session_start(),就完成的吗?这两件事,谁先谁后呢?
让试验来证明,稍微改动一下程序:

程序2:
<?php
session_start();
$_SESSION['uname'] = 'monkey';
$_SESSION['ukey'] = 20119999; 
 
sleep(30);
?> 

先把客户端和服务端的session数据通通删除,然后执行程序2,趁着程序里的sleep30秒的工夫,去查看客户端和服务端的session情况,发现:在程序执行过程中,客户端并没有建立保存PHPSESSID的cookie文件,服务端却已经有了保存session内容的临时文件,但是文件里没有内容,等30秒时间过了之后,客户端的cookie文件才会生成,服务端的session文件里才有了内容。


由此推断大致流程应该为:在程序执行到session_start()的时候,服务端首先生成PHPSESSID,并生成相对应的session文件,但是在程序进行$_SESSION赋值的时候,并没有把相应的值写入到session文件里,姑且臆断为保存在内存里吧,到了程序执行完毕后,才会在客户端生成保存PHPSESSID的cookie文件,并把$_SESSION变量里的值写入服务端的session文件里,至于最后两个步骤谁先谁后,暂时还没有想到好办法来证明。
 

为了更进一步论证,删除客户端和服务端的session相关内容执行程序3,观察第一次和第二次的结果:
程序3:
<?php
session_start();
$_SESSION['uname'] = 'monkey';
$session_id = session_id();
$sess_file = "/tmp/sess_".$session_id;
$content = file_get_contents($sess_file);
 
echo '***'.$_COOKIE['PHPSESSID'] .'***';
echo '<br />' . $_SESSION['uname'] . '<br />';
echo '***'.$content.'***';
?> 
 

上面说的是第一次sessin_start()的执行方式,也就是一套程序里,第一个session_start()出现的时候所做的事情,下面来看之后的session_start():

假设的php.ini配置:session.cookie_lifetime = 0       

程序4:
<?php
session_start(); 
echo $_SESSION['uname'];
echo $_SESSION['ukey'];
?> 

现在,客户端已经有了保存PHPSESSID的cookie文件,服务端也有了保存session内容的sess_文件,执行程序4,会打印出正常的内容。这时,如果强行关闭浏览器,再执行程序4,结果会怎样呢?

 

首先,session.cookie_lifetime设置成0,表示客户端保存PHPSESSID的cookie文件的生存周期为0,浏览器如果处于开启状态,PHPSESSID的值会保存在内存中,一旦强行关闭,保存PHPSESSID的cookie文件会同时销毁,但是服务端并没有执行session_destroy(),所以,服务端的session数据文件还在,但是当浏览器再次打开执行程序4,发现什么都没有输出,由此推理:


session_start()首先会去获取客户端cookie里的PHPSESSID,然后与“sess_”组成文件名,去服务端查找这个文件,然后取出文件里的内容,把内容放到$_SESSION全局变量里以供使用。浏览器强行关闭,再打开,之前的PHPSESSID丢失,这时遇到session_start()就相当于上面说的第一次执行,会生成一个新的PHPSESSID,这个PHPSESSID匹配不到之前那个服务端的sess_文件,所以取不到内容。当然,服务端也有能跟这个PHPSESSID匹配的文件,不过,那个文件还是空的。


所以,有的系统为了实现同一用户只能在一台机器甚至一个浏览器登录的机制,如果没有修改session.cookie_lifetime的设置,就会出现强行关闭浏览器之后,在服务端session生存期截止前该,用户登录不进去的情况,比较好的办法是把session.cookie_lifetime设置成一个比较大的值,反正一个cookie文件存在时间久一些也没什么影响。

 

分享到:
评论

相关推荐

    基于.NET Ocelot网关的GatewayProject设计源码

    该项目为基于.NET框架的Ocelot网关解决方案——GatewayProject的设计源码,包含39个文件,涵盖15个C#源代码文件、11个JSON配置文件、3个项目文件、2个解决方案文件、1个Git忽略文件、以及其他几种类型文件。该系统集成了Ocelot网关,适用于构建分布式微服务架构中的API网关功能。

    编程心得体会.pptx

    编程心得体会.pptx

    3DMAX镂空星花球建模插件FloralStarBall下载

    就是那个3DMAX镂空星花球建模,再也不用手动做了,使用这个插件可以一键生成! 3DMAX镂空星花球建模插件FloralStarBall,经典星形球体的美丽变体。星形图案以花卉风格排列,赋予物体独特的视觉美感。它将成为任何Math Art收藏、桌面展品甚至柔性塑料印刷的应力释放器的绝佳补充。 一键生成竟然不费吹灰之力!

    c语言电子时钟程序.zip

    c语言电子时钟程序

    城市小学生课间活动现状及改进措施分析

    内容概要:本文对城市小学生课间活动的现状进行了研究,通过观察和访谈的方式,分析了当前小学生课间活动存在问题的具体表现,主要包括课间活动中学生参与度较低、活动种类单一、活动时间不足等问题,并提出了相应改善措施。 适合人群:教育工作者、小学教师、校长及相关研究者。 使用场景及目标:旨在通过分析现状,为提升课间活动质量提供具体策略,以期优化校园文化,促进学生健康成长和发展。 阅读建议:读者可通过本文深入了解当前城市小学存在的课间活动问题,并从中获取切实可行的解决方案和改进建议。同时,文章强调了提高课间活动质量和多样性的必要性和途径。

    备战19届全国大学生智能汽车竞赛源码+文档说明.zip

    备战19届全国大学生智能汽车竞赛源码+文档说明.zip,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战19届全国大学生智能汽车竞赛源码+文档说明.zip备战1

    基于springboot的墙绘产品展示交易平台的设计与实现源码(java毕业设计完整源码+LW).zip

    用户信息管理: 用户信息新增:添加新用户的信息。 用户信息修改:对现有用户信息进行修改。 黑名单管理: 黑名单添加:将用户添加到黑名单中。 黑名单删除:从黑名单中移除用户。 黑名单修改:对黑名单中的用户信息进行修改。 商品分类管理: 商品分类添加:增加新的商品分类。 商品分类删除:移除不再需要的商品分类。 商品分类修改:对商品分类信息进行修改。 商品信息管理: 商品信息添加:添加新的商品信息。 商品信息删除:删除商品信息。 商品信息修改:对商品信息进行修改。 商品评价管理: 商品评价删除:删除不当或过时的商品评价。 商品评价添加:添加新的商品评价。 商品评价修改:对商品评价进行修改。 订单管理管理: 订单管理删除:删除订单信息。 订单管理修改:对订单信息进行修改。 项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:springboot,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3

    三菱fx5U控制三轴伺服定位 (BOM表,CAD电气图纸,plc程序,人机界面)

    三菱fx5U控制三轴伺服定位。 (BOM表,CAD电气图纸,plc程序,人机界面)

    Java反编译工具:jd-jui

    软件功能: jd-jui能以java文件的方式查看jar中的class文件 安装: 该软件无需安装,下载并解压后,双击exe文件即可启动 使用: 启动jd-jui后,点击左上角的 File -> Open -> 打开需要查看源码的jar包,即可查看源代码

    utlog.sqlite

    utlog.sqlite

    基于C#的库存管理系统

    【基于C#的库存管理系统】是一个使用C#编程语言开发的软件应用,旨在帮助企业或个人高效地管理和跟踪库存。在库存管理中,系统的功能通常包括物品的入库、出库、库存查询、库存盘点以及生成相应的报表,以确保库存水平保持在最佳状态,避免过度存储造成的资金占用或库存短缺带来的损失。

    帮助文档能够很好的支撑前端技术学习

    帮助文档能够很好的支撑前端技术学习

    西门子1200与ABB机器人TCP 通信案例.zip

    西门子1200与ABB机器人TCP 通信案例.zip

    微信小程序源码-亿家旺生鲜云订单零售系统的设计与实现-微信端-毕业设计源码-期末大作业.zip

    亿家旺生鲜云订单零售系统是一个基于微信小程序的项目。该项目主要功能丰富多样,从前台来看,用户能够在首页查看系统核心内容与导航,浏览详细的商品信息、获取商品资讯、管理自己的订单、评价订单、收藏商品、充值账户、在线购买服务等,还可查看和管理购物车。后台功能则包括管理系统用户信息、商品分类、商品信息、订单评价、进行系统整体设置与维护以及处理订单信息等。 在技术框架方面,开发语言为Java,采用SSM(Spring、SpringMVC、MyBatis)框架后端技术,前端使用Vue,数据库是MySQL。其开发目的是满足人们对生鲜食品的需求,借助信息技术提供一个便捷、安全、高效的生鲜购物平台,连接用户与供应商,提升生鲜行业的服务质量和效率。项目为完整毕设源码,先看项目演示,希望对需要的同学有帮助。

    拯救者PC,新年主题壁纸

    拯救者PC,新年主题壁纸

    工业物联网监控平台可视化java项目springboot开发iot二次开发源 SpringBoot物联网风电监测系统源码 统源码 iot物联网风电能源电场监控系 基于SpringBoot的物联网系统

    工业物联网监控平台可视化java项目springboot开发iot二次开发源 SpringBoot物联网风电监测系统源码 统源码 iot物联网风电能源电场监控系 基于SpringBoot的物联网系统 易读易懂、界面简洁美观。 核心技术:Spring, MyBatis,shiro没有任何其它重度依赖。 数据设计 电厂信息 电厂信息包括电厂编号、风机总数、总装机量等 风机配置信息 风机编号、风机品牌、功率、实际功率、所在位置(坐标),所属电厂、启动时间、安装时间、运行状态等。 风机数据统计 分别对风机的风速、转速、发电量、功率、偏航次数、 偏航角度等进行年月日统计。 有一个jar包可能需要你自己去找

    帝国CMS7.5仿《六皮游戏网》源码/手游门户网站模板

    非常大气漂亮的手游模板,个人觉得比现在官方改版的要漂亮,模板优化好美观大气赏心悦目,本程序带有多端同步生成插件维护好省心。是一个专注于手机游戏的综合门户网站,提供手游下载、好玩的手游推荐、手游排行榜、热门手游攻略、手游视频解说、行业新闻。集安卓Android、苹果iOS及多终端的手游平台,Get最新手游技巧!

    化学工程中无约束优化数值实验及参数估计研究

    内容概要:本文探讨了两个无约束优化问题及其相关数值实验。首先讨论了一阶反应动力学的参数估计问题,涉及线性常微分方程组的解及其与实验数据的最佳拟合。其次,详细分析了一个复杂的无约束优化问题,提供了多种求解方法(基本牛顿法、信赖域法、拟牛顿法)的结果和比较,旨在评估不同算法的性能。最后,作者对实验过程中遇到的问题及解决方案进行了总结,并分享了对无约束最优化算法的理解。 适用人群:适用于化学工程、数学建模和优化领域的研究人员及学生。 使用场景及目标:用于理解和应用各种无约束优化算法,提高科研工作者和学生的算法选择能力和实际操作经验。 其他说明:文中引用了多部权威教材和技术手册,如《数学规划基础》和《非线性规划:概念、算法及化工过程的应用》,为理论背景提供了可靠依据。此外,还提供了详细的数值实验步骤和算法实现细节,便于读者复现和深入研究。

    2025跨年源码 跨年烟花html源代码

    【跨年烟花html源代码】是一种用于网页设计的创意元素,它通过JavaScript和HTML结合,为网站增添节日气氛,特别是新年到来之际。这种特效能够模拟烟花绽放的效果,为用户带来视觉上的惊喜。在网页上实现跨年烟花效果,通常会涉及以下几个关键知识点: 1. HTML基础:HTML(超文本标记语言)是网页设计的基础,用于构建网页结构。在这个项目中,HTML将用于创建烟花展示的容器,比如一个全屏的div元素,以及可能的控制按钮等交互元素。 2. CSS样式:CSS(层叠样式表)负责网页的布局和样式。在跨年烟花效果中,CSS可以用来设置烟花的颜色、大小、位置以及烟花爆炸后的粒子效果。使用CSS动画和过渡效果可以实现烟花升空、绽放和消失的动态过程。 3. JavaScript核心:JavaScript是实现动态效果的关键,它负责烟花的发射、运动轨迹、碰撞检测以及爆炸效果。JavaScript中的Math对象会被大量使用,以生成随机的烟花方向和速度。同时,定时器(setTimeout或requestAnimationFrame)用于控制烟花发射的间隔和动画帧率。 4. Canvas AP

    基于微信小程序+SpringBoot的校园二手交易平台(源码+数据库+说明文档+效果图)毕业设计

    Java毕业设计——基于微信小程序+SpringBoot的校园二手交易平台 软件架构 系统分为三个端,分别是客户端、管理端、服务端; 客户端:使用原生微信小程序实现 管理端:使用Layui实现 服务端:使用Java SpringBoot实现 用到的所有技术栈: 客户端:微信小程序 管理端:Html、Css、JavaScript、Layui、Ajax、JQuery 服务端:Java JDK8、SpringBoot、Mybatis 数据库:MySQL 工具:Idea、HBuilderX、微信小程序开发者工具、xampp、Navicat 安装教程 启动MySQL服务,新建数据库second_market,导入数据库文件second_market.sql 启动服务端,在idea中打开SecondMarketServer,修改application.yml文件中的数据库连接信息,启动项目 启动管理端,在HBuilderX中打开SecondMarketManager;修改AppConfig.js中的服务器信息, 配置web服务器,可以使用Nginx或者Apache,我使用xam

Global site tag (gtag.js) - Google Analytics