php session的锁和并发_php技巧

本文分享PHP的session在使用过程中的锁和并发的问题,与之相关的现象有请求阻塞、session数据丢失、session数据读不到。

我登录不了了
某天,我准备登录我们一个后台系统,前去解决一个bug,在账户密码验证码都准确输入的情况下,我登录不上,经过多次实验发现主要有两个错误信息:

  • csrf验证失败
  • 验证码错误【我对码神起誓我用半角输入了我看到的验证码,且顺序一致,无多加字符】

我们的系统
我们的系统是基于phalcon 2.0.8 开发的,如你所见,我们在表单域加入了防止csrf攻击的域。也启用了验证码。

<input type="hidden"
  name="{{ security.getTokenKey() }}"
  value="{{ security.getToken() }}"/>
<img src="/login/getCaptcha" id="img-captcha"/>

我首先对这两个组件进行查阅,发现他们都是将数据存于session:

# phalcon/security.zep
# Security::getToken()
let session = <SessionInterface> dependencyInjector->getShared("session");
session->set(this->_tokenValueSessionID, token);
$this->session->set('admin_get_captcha_action', $captcha);

然后我又查阅了我们session的实现,发现是将数据存储于redis的。

找啊找
什么问题导致我登录不上呢?既然是数据验证上出现问题,就从数据着手吧,我登陆我们测试环境的redis机器,执行 redis-cli monitor,然后走一遍登录流程,发现输出如下(意思意思):

  • GET sessionId 
  • GET sessionId 
  • SETEX sessionId 3600 csrf=xxxx 
  • SETEX sessionId 3600 captcha=abcd 

我们可以看到:

1、这里存在两次请求,一次是表单加载,一次是生成验证码的。
2、存在“并发”的情况,这两个请求应该是表单加载渲染后才请求验证码的,也就是session顺序应该是get->set->get->set,看起来怎么是并发请求了。
3、后面那个SETEX没有csrf的内容,也就是覆盖掉前面的数据了
整个世界都不好了,不过也稍微明白是什么问题了。什么问题呢,说来话长,要从PHP的session数据的存取说起。

php的session数据的存取
session的数据是经过编码成字符串存储在存储器【file、db、redis、memcache等】的,在我们使用session的时候,是什么时候去储存器取数据的?又是什么时候将数据写入存储器的?

这个问题的答案可能和一些朋友想的不一样,一个请求里面,PHP只会读取一次存储器,在session_start的时候,然后也只会写入一次存储器,在请求结束的时候,或调用session_write_close的时候,将数据刷回存储器,关闭session。

那么问题来了:

1、如果一个会话,同时出现两个读写session请求,没有保证获取1-写入1-获取2-写入2,同时没有cas版本管理机制的情况下,这些并发请求就会彼此读取不到对方的写入,最后写入的会把前面请求写入的session覆盖掉。
2、如果请求是串行的,像登录页面的表单和验证码,也有可能前面的请求已经输出内容了,但是session还没写入,后面的请求就已经发起了。
锁与不锁
解决这种资源的并发一般会通过锁或版本管理来处理。但是版本管理我看不到好的方法。就聊聊锁吧。

其实锁是不大适合,有弊端的。

php的session,默认是用文件存储的,在打开session的时候,会对文件加独占锁,这样,其它请求就无法获取锁了,只能等待直到前面的锁解了。

这样保证了 读取-写入,读取-写入的顺序。

其它存储器,例如mysql,可以借助select for update进行行锁。redis可以通过一个自增键,返回1的获取到锁等来实现。

这个实现的话,对数据流来说很理想,但是,对于目前这种页面大量应用ajax的情况,所有请求排队处理,将大大加大页面展现的耗时,甚至出现请求超时等不可用故障。

没有解决的解决
不建议过多使用session,其一次读取一次写入的机制所引发的问题,会造成坑的存在。
在模版渲染前,或请求输出前调用session_write_close

# 立刻回写session,避免session覆盖
$eventManager = $this->view->getEventsManager();
if (!$eventManager) {
  $eventManager = new Manager();
  $this->view->setEventsManager($eventManager);
}
$eventManager->attach("view:afterRender",function(){
  session_write_close();
});
return $this->view;
if($login) {
  # 立刻回写session,避免session读取不到
  $eventManager = $this->dispatcher->getEventsManager();
  if (!$eventManager) {
    $eventManager = new Manager();
    $this->dispatcher->setEventsManager($eventManager);
  }
  $eventManager->attach('dispatch:afterDispatchLoop',function(){
    session_write_close();
  });
  return $this->response->setHeader('Location', '/');
}

以上就是关于php session的锁和并发,希望对大家的学习有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索并发
, php
, session

php session 并发、session 并发问题、session并发、asp.net session 并发、高并发 session,以便于您获取更多的相关知识。

时间: 2024-07-30 04:16:00

php session的锁和并发_php技巧的相关文章

php使用session二维数组实例_php技巧

本文实例讲述了php使用session二维数组的用法.分享给大家供大家参考.具体如下: 最普通的用法:一个变量名 复制代码 代码如下: $_SESSION['user'] = 0; echo $_SESSION['user']; 使用数组: 复制代码 代码如下: $_SESSION['user']['a'] = 1; $_SESSION['user']['b'] = 2; echo $_SESSION['user']['a']; echo $_SESSION['user']['b']; 这样的好

php验证session无效的解决方法_php技巧

本文实例讲述了php验证session无效的解决方法.分享给大家供大家参考.具体方法如下: 一.问题 今天在配置 apache+php环境时折腾了很久很久,后来成功了但发现验证码图片可以生成,在登录验证时发现session为空,并没有值了. 二.解决方法 环境:apache+php 程序代码如下: 复制代码 代码如下: <input name="username" type="text" class="input" id="use

php中session与cookie的比较_php技巧

本文较为详细的比较了php中session与cookie区别.分享给大家供大家参考.具体分析如下: 1.存放的位置 cookie保存在客户端,session保存在服务器端的文件系统/数据库/memcache等. 2.安全性 session因为保存有服务器端,安全性无疑更高一些. 3.网络传输量 cookie通过网络在客户端与服务器端传输,会占用一些带宽:而session保存在服务器端,不需要传输. 4.保存时间(生命周期),以20分钟为例 cookie的生命周期是累计的,从创建时就开始计算,20

php中实现精确设置session过期时间的方法_php技巧

大多数据情况下我们对于session过期时间使用的是默认设置的时间,而对于一些有特殊要求的情况下我们可以设置一下session过期时间. 对此,可以在PHP中,设置php.ini,找到session.gc_maxlifetime = 1440 #(PHP5默认24分钟)这里你可以随便设置一下过期时间.但是有人说设置以后,好象不起作用! 其实不是不起作用,而是因为系统默认: session.gc_probability = 1 session.gc_divisor = 1000 garbage c

解析PHP的Yii框架中cookie和session功能的相关操作_php技巧

Sessions 和 请求 和 响应类似, 默认可通过为yii\web\Session 实例的session 应用组件 来访问sessions. 开启和关闭 Sessions 可使用以下代码来开启和关闭session. $session = Yii::$app->session; // 检查session是否开启 if ($session->isActive) ... // 开启session $session->open(); // 关闭session $session->clo

php通过session防url攻击方法_php技巧

本文实例讲述了php通过session防url攻击方法.分享给大家供大家参考.具体实现方法如下: 通过session跟踪,可以很方便地避免url攻击的发生,php采用session防url攻击方法代码如下: 复制代码 代码如下: <?php session_start();  $clean = array();  $email_pattern = '/^[^@s<&>]+@([-a-z0-9]+.)+[a-z]{2,}$/i';  if (preg_match($email_pa

新手菜鸟必读:session与cookie的区别_php技巧

session和cookie是网站浏览中较为常见的两个概念,也是比较难以辨析的两个概念,但它们在点击流及基于用户浏览行为的网站分析中却相当关键.基于网上一些文章和资料的参阅,及作者个人的应用体会,对这两个概念做一个简单的阐述和辨析,希望能与大家共同探讨下. session和cookie的最大区别在于session是保存在服务端的内存里面,而cookie保存于浏览器或客户端文件里面:session是基于访问的进程,记录了一个访问的开始到结束,当浏览器或进程关闭之后,session也就"消失&quo

使用PHP会话(Session)实现用户登陆功能_php技巧

对比起 Cookie,Session 是存储在服务器端的会话,相对安全,并且不像 Cookie 那样有存储长度限制,本文简单介绍 Session 的使用. 由于 Session 是以文本文件形式存储在服务器端的,所以不怕客户端修改 Session 内容.实际上在服务器端的 Session 文件,PHP 自动修改 Session 文件的权限,只保留了系统读和写权限,而且不能通过 ftp 修改,所以安全得多. 对于 Cookie 来说,假设我们要验证用户是否登陆,就必须在 Cookie 中保存用户名

PHP中SESSION的注销与清除_php技巧

1.每个页面都必须开启session_start()后才能在每个页面里面使用session. 2.session_start()初始化session,第一次访问会生成一个唯一会话ID保存在客户端(是基于cookie保存的),用户下次访问时,session_start()会检查有没有会话ID,如果有浏览器会带着这个会话ID过来(通过发送头文件传过来的,这个可以用ff浏览器看到)来确定客户端. 3.给于cookie的session会在客户端保存一个会话ID即session_id,这个可以通过打印co