搜尋
首頁php教程php手册php session的锁和并发,phpsession

php session的锁和并发,phpsession

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

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

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

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

<input type="hidden" 
  name="{{ security.getTokenKey() }}"
  value="{{ security.getToken() }}"/>
<img  src="/static/imghwm/default1.png"  data-src="/login/getCaptcha"  class="lazy" id="img-captcha"/ alt="php session的锁和并发,phpsession" > 

我首先对这两个组件进行查阅,发现他们都是将数据存于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死锁的方法
  • PHP中session变量的销毁
  • PHP错误WARNING: SESSION_START() [FUNCTION.SESSION-START]解决方法
  • ThinkPHP的模版中调用session数据的方法
  • php中实现精确设置session过期时间的方法
  • ThinkPHP中Session用法详解
  • PHP session文件独占锁引起阻塞问题解决方法
  • PHP中Session可能会引起并发问题
  • 浅析PHP中Session可能会引起并发问题
陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
php怎么把负数转为正整数php怎么把负数转为正整数Apr 19, 2022 pm 08:59 PM

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

php怎么实现几秒后执行一个函数php怎么实现几秒后执行一个函数Apr 24, 2022 pm 01:12 PM

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php怎么除以100保留两位小数php怎么除以100保留两位小数Apr 22, 2022 pm 06:23 PM

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

php怎么根据年月日判断是一年的第几天php怎么根据年月日判断是一年的第几天Apr 22, 2022 pm 05:02 PM

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php怎么替换nbsp空格符php怎么替换nbsp空格符Apr 24, 2022 pm 02:55 PM

方法:1、用“str_replace("&nbsp;","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\&nbsp\;||\xc2\xa0)/","其他字符",$str)”语句。

php怎么判断有没有小数点php怎么判断有没有小数点Apr 20, 2022 pm 08:12 PM

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

php字符串有没有下标php字符串有没有下标Apr 24, 2022 am 11:49 AM

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

php怎么设置implode没有分隔符php怎么设置implode没有分隔符Apr 18, 2022 pm 05:39 PM

在PHP中,可以利用implode()函数的第一个参数来设置没有分隔符,该函数的第一个参数用于规定数组元素之间放置的内容,默认是空字符串,也可将第一个参数设置为空,语法为“implode(数组)”或者“implode("",数组)”。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具