PHP 中 SESSION 工作原理
PHPSESSID 生成
生成规则是根据hash_func散列来生成的,相关的参数有:
- 客户端IP
- 当前时间(秒)
- 当前时间(微妙)
- PHP自带的随机数生产器
hash_func 是 phpinfo中的 session.hash_function 配置。如下:
; Select a hash function for use in generating session ids. ; Possible Values ; 0 (MD5 128 bits) ; 1 (SHA-1 160 bits) ; This option may also be set to the name of any hash function supported by ; the hash extension. A list of available hashes is returned by the hash_algos() ; function. ; http://php.net/session.hash-function session.hash_function=0
PHPSESSID 示例
例如:访问米扑代理首页 https://proxy.mimvp.com ,查看 Cookie: PHPSESSID=01h0717afdteigg9nqn61vuek3;
Request Headers 如下:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7,pt;q=0.6 Cache-Control: no-cache Connection: keep-alive Cookie: PHPSESSID=01h0717afdteigg9nqn61vuek3; Hm_lvt_51e3cc975b346e7705d8c255164036b3=1578379811,1578564397,1578630437,1579153880; userinfo=MmzihmtvapW12cGE6Mzp7czoxMDoidXNlcl9lbWFpbCI7czozOToiTW16aWhtdHZhcFcxMmNITmhaRzFwYmtCdGFXMTJjQzVqYjIwTzBPIjtzOjg6InVzZXJfcHdkIjtzOjU3OiJNbXppaG10dmFwVzEyY0dWbU0yTTVPVGsxT1RSbE5XSXdabUk1TmpWbU56VTBZekV5WVRaak1EaGkiO3M6MTM6InVzZXJfcmVtZW1iZXIiO3M6MTk6Ik1temlobXR2YXBXMTJjREVPME8iO30O0O; Hm_lpvt_51e3cc975b346e7705d8c255164036b3=1579420011 DNT: 1 Host: localhost:8086 Pragma: no-cache Referer: http://localhost:8086/sadmin/ Sec-Fetch-Mode: navigate Sec-Fetch-Site: same-origin Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
PHP session工作原理
以下以cookie传输PHPSESSID描述。
1. 客户端请求一个php的服务端地址。
2. 服务端收到请求,此次php脚本中包含session_start()。
3. 服务端会生成一个PHPSESSID。(默认session存储方式为session.save_handler=files,文件形式存储。生成的session文件名规则即为sess_PHPSESSID,session文件存在session.save_path中。)
4. 服务端响应首部Response Headers:Set-Cookie:PHPSESSID=37vjjasgjdv2ouk1uomhgqkv50; path=/。在客户端生成一个cookie保存此PHPSESSID。
5. 此时,客户端的cookie里面包含了PHPSESSID,之后客户端的每次请求首部Request Headers:Cookie:PHPSESSID=37vjjasgjdv2ouk1uomhgqkv50。
6. 服务端之后每次接收到客户端的请求就都能根据这个PHPSESSID来找到服务端的session文件,通过对这个session文件的读写操作即实现了session的超全局变量属性。
如果客户端禁用了cookie,由于无法使用cookie传递PHPSESSID,那么客户端每次请求,服务端都会重新建立一个session文件,而无法通过通过PHPSESSID来重用session文件,所以session也就失效了。
这种情况可以设置session.use_trans_sid 来传输PHPSESSID,具体实现方式与cookie的区别就是将PHPSESSID通过HTTP的GET传输。每次请求的地址里面都会补全PHPSESSID参数”url?PHPSESSID=37vjjasgjdv2ouk1uomhgqkv50”来实现。详见米扑博客:PHP Session 与 Cookie 详解
PHP cli 模式通过session_id()使用session
官网说明
可以通过它来获取当前会话的PHPSESSID,也可以通过它来设置当前的会话PHPSESSID。
PHP cli模式下可以通过设置这个,达到使用session的目的,非常方便。
例如:vim test_php_session.php
<?php // session_id('01h0717afdteigg9nqn61vuek3'); session_start(); $_SESSION[md5(rand(100,999))] = rand(100,999); var_dump($_SESSION);
未使用session_id()的时候,在cli模式下运营此php脚本三次:
$ /usr/local/php/bin/php test_php_session.php array(1) { ["3cec07e9ba5f5bb252d13f5f431e4bbb"]=> int(794) } $ /usr/local/php/bin/php test_php_session.php array(1) { ["ff4d5fbbafdf976cfdc032e3bde78de5"]=> int(856) } $ /usr/local/php/bin/php test_php_session.php array(1) { ["d240e3d38a8882ecad8633c8f9c78c9b"]=> int(668) }
可以看到由于cli模式下没有传输PHPSESSID,所以每次都是一次性的随机生成和使用 session 文件,session没有生效。
查看下session文件:
$ cd /System/Volumes/Data/private/var/folders/wq/vgx37qxd0jjcmkry1y729k340000gn/T/ $ ls -l sess_* -rw------- 1 homer staff 39 1 19 15:33 sess_0ecf2f025d848553f12a564fcdc8718c -rw------- 1 homer staff 39 1 19 15:34 sess_74d0dd6eb98ec4281c10b310f3fd4da1 -rw------- 1 homer staff 39 1 19 15:34 sess_ec5ee38e126e37df462f2bbe3eeb02dd
这三个session文件是我们三次cli执行生成的,三个session文件的内容如下:
$ more sess_0ecf2f025d848553f12a564fcdc8718c 3cec07e9ba5f5bb252d13f5f431e4bbb|i:794; $ $ more sess_74d0dd6eb98ec4281c10b310f3fd4da1 ff4d5fbbafdf976cfdc032e3bde78de5|i:856; $ $ more sess_ec5ee38e126e37df462f2bbe3eeb02dd d240e3d38a8882ecad8633c8f9c78c9b|i:668;
首先,将之前的session文件删除掉
rm -f sess_*
然后,如果我们使用session_id(),为cli脚本设定固定的PHPSESSID
例如:vim test_php_session.php
<?php session_id('01h0717afdteigg9nqn61vuek3'); session_start(); $_SESSION[md5(rand(100,999))] = rand(100,999); var_dump($_SESSION); ?>
然后cli运行脚本三次:
$ /usr/local/php/bin/php test_php_session.php array(1) { ["274ad4786c3abca69fa097b85867d9a4"]=> int(472) } $ $ /usr/local/php/bin/php test_php_session.php array(2) { ["274ad4786c3abca69fa097b85867d9a4"]=> int(472) ["4c27cea8526af8cfee3be5e183ac9605"]=> int(797) } $ $ /usr/local/php/bin/php test_php_session.php array(3) { ["274ad4786c3abca69fa097b85867d9a4"]=> int(472) ["4c27cea8526af8cfee3be5e183ac9605"]=> int(797) ["01161aaa0b6d1345dd8fe4e481144d84"]=> int(122) }
最后,查看下session文件,就只有一个我们设置的session文件:
$ cd /System/Volumes/Data/private/var/folders/wq/vgx37qxd0jjcmkry1y729k340000gn/T/ yg-mac:T homer$ ll sess_* -rw------- 1 homer staff 117 1 19 15:52 sess_01h0717afdteigg9nqn61vuek3
session文件内容:
$ more sess_01h0717afdteigg9nqn61vuek3 274ad4786c3abca69fa097b85867d9a4|i:472;4c27cea8526af8cfee3be5e183ac9605|i:797;01161aaa0b6d1345dd8fe4e481144d84|i:122;
这样,在PHPcli模式下,session就可以使用了。
session_id()的作用,即为PHP脚本自己设定了PHPSESSID,而不需要传输PHPSESSID。
另外,cli模式下,session可以使用,apache的ab测试,session也就可以使用了。
通过设置 PHPSESSID 保存到 cookie,实现免用户名密码登录
$cookieParams = session_get_cookie_params(); session_set_cookie_params( 3600,// 设置sessionID在cookie中保存的时长 BASE_DATA_PATH.'/session', $cookieParams['domain'], $cookieParams['secure'] ); session_regenerate_id(true);
说明:该方式存在安全风险,建议把member_id存到cookie再次进入的时候进行登陆操作。
ThinkPHP URL 自己带上参数 PHPSESSID
碰到个问题,ThinkPHP项目程序本地测试没问题,传到服务器后第一次访问,页面的所有URL会自己带上类似?PHPSESSID=28954583914413546c6e881cfa7c8117 这样的参数,再点击刷新下页面后访问才正常。
浏览器并没有禁止cookie,本地访问正常也证实了这点,第一猜想是服务器的环境配置与项目代码某些地方冲突所影响。
检测了服务器的关于cookie的配置对比本地的,发现session.use_trans_sid这个项的配值是不同的,本地关闭,服务器是开着的。
PHP中的会话在默认情况下是使用客户端的cookie来保存session_id的,所以当客户端的cookie出现问题的时 候就会影响会话了。其实会话不一定必须依赖cookie,当客户端的cookie被禁用或出现问题时,PHP会自动把session_id附加在URL 中,这样再通过 session_id就能跨页使用会话变量了。但这种自动的附加也是有一定条件的,首先,在php.ini文件中的 session.use_trans_sid = 1或者编译时打开了--enable-trans-sid选项,其次,运行PHP的服务器必须是UNIX/Linux系统,Windows操作系统不具备 此项功能。
上面的引用就说明了这点,在linux系统下,在session.use_trans_sid开启的时候,导致项目会自己加上PHPSESSID参数来达到跨页会话。
最后解决是:ini_set('session.use_trans_sid', 0); //在项目代码初始化的位置加入这句
其实还有个怀疑,可能项目某配置出现问题。待查。
Ps,这问题也反面教了件事,在处理跨页会话跨域会话的时候,session.use_trans_sid或许能起到奇效。
ThinkPHP PHPSESSID 过期问题
1、问题场景:
浏览器打开网页,停留N分钟,再次刷新网页,PHPSESSID变了,登陆的用户也就自然退出了
2、分析问题:
找不到导致PHPSESSID变的原因
session.cookie_lifetime = 0
例如:
ini_set('session.use_cookies', 1); // 使用COOKIE保存SESSIONID的方式 ini_set('session.cookie_domain', 'proxy.mimvp.com');
3、讨论问题:
PHP 采用的是 ThinkPHP 框架 v3.23
ThinkPHP 官网:http://www.thinkphp.cn
ThinkPHP 是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架 ,创立于2006年初,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,已经成长为国内最领先和最具影响力的WEB应用开发框架,众多的典型案例确保可以稳定用于商业以及门户级的开发。
session一定要用 session_set_save_handler 重写.
其实你设定过期时间一年后,但是其他没有保存为一年后的用户还会触发session的gc,从而强制回收你的session.
<?php 'SESSION_OPTIONS'=>array('type'=> 'db', // session采用数据库保存 'expire'=>7200, // session过期时间,如果不设就是php.ini中设置的默认值 ), 'SESSION_TABLE' =>'v4_session', // 必须设置成这样,如果不加前缀就找不到数据表,这个需要注意 ?>
两种方法重写:
1. 存储redis、mysql等数据库, 过期时间你自己控制.
2. 存储文件files,技巧是强制修改session文件的时间为未来的时间,这样其他用户触发gc后就没法回收你的session文件了.
session是跟随cookie存数据,问题是cookie这边sessid过期换掉了,而不是session过期
session.gc_maxlifetime = 1440; 指定最后一次访问后的 1440 秒失效
但是否真的失效,取决于 session.gc_probability 和 session.gc_pisor 比值(失效概率)
对于 ThinkPHP,你有 'expire'=>7200 那么应在最后一次访问的 7200 秒(2小时)后失效 如果不是这样,那就放弃 ThinkPHP
跟程序没关系,程序存到数据库的都是正常的。
7200是有效的是因为PHPSESSID 值失效(a变b),a在数据库里是存在,但b是不存在的,所以相当导致用户的整个session失效
服务器上session失效,网页刷新当然重新分配了一个sessionid啊
session.cookie_lifetime=0 指的是在浏览器关闭时删除cookie、session,除非手动删或者被其他软件强清了
不知道对不对,PHPSESSID 是根据cookie传到客户端,用来判断用户的唯一性,如果cookie设置0秒,会自动清空,客户端没有PHPSESSID,服务端当然会重新分配一个,所以就注销了。
服务器session没有失效,存的数据库。。。
是因为存在coookie 的 PHPSESSID 值变了,而这个phpsessid在数据库里是没数据的
对的,问题是系统配置是2个小时,有时候10分钟有时候1个小时PHPSESSID就被重新分配了(同一个页面一直刷新)
找不出原因 session和cookies那点事说难不难,说简单也不简单,整到完美磨合,俩合作完美无间要仔细研究下,不过封装好以后就省事了.
你看看你是不是session_id($_COOKIES['sess_id']);没有这样接管.
还有cookies的作用域问题,作用路径问题,查查setcookie参数你就知道了...
正常不会这样,既然tp(ThinkPHP)设置了7200实效,根据session.gc处理,只会在7200秒后执行清除
你可以检查是否有其他程序导致session实效。
之前做法是,把session保存在cookies,如果判断session失效但cookie没有实效,则把cookie复制入session处理。
已经找出问题
<?php function session($name='',$value='') { ini_set('session.gc_maxlifetime', $name['expire']); // ini_set('session.cookie_lifetime', $name['expire']);} ?>
参考推荐:
Linux curl 命令模拟 POST/GET 请求 (推荐)
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2020-04-21 05:14:06
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!