在 PHP 中防止竞争条件的最可靠和安全的方法

2023-12-21

我需要在 PHP 中使用互斥体或信号量,这让我感到害怕。澄清一下,我并不害怕编写正确同步的无死锁代码,也不害怕并发编程的危险,而是害怕 PHP 处理边缘情况的能力。

快速背景知识:编写位于用户和第 3 方信用卡网关之间的信用卡处理程序接口。需要防止重复请求,并且已经有一个可以工作的系统,但是如果用户在几毫秒内点击提交(未启用 JS,因此我无法禁用它们的按钮),则会在我的 PHP 脚本中出现竞争条件没有意识到已经提出了重复的请求。需要一个信号量/互斥体,这样我就可以确保每个唯一事务只有一个成功的请求通过。

我通过 PHP-FPM 在 nginx 后面运行 PHP,并在多核 Linux 机器上使用多个进程。我想确定的是

  1. 信号量在所有 php-fpm 进程和所有内核(i686 内核)之间共享。
  2. php-fpm 处理 PHP 进程崩溃,同时持有互斥体/信号量并相应地释放它。
  3. php-fpm 在持有互斥体/信号量的同时处理会话中止并相应地释放它。

是的,我知道。非常基本的问题,认为任何其他软件都不存在适当的解决方案是愚蠢的。但这是 PHP,而且它在构建时肯定没有考虑到并发性,它经常崩溃(取决于您加载的扩展),并且处于不稳定的环境中(PHP-FPM 和 Web)。

关于 (1),我假设如果 PHP 使用 POSIX 函数,那么这两个条件在 SMP i686 机器上都成立。至于(2),我通过简要浏览文档发现有一个参数决定了这种行为(尽管我不明白为什么有人希望 PHP 不释放互斥锁,因为会话被杀死了)。但是(3)是我主要关心的问题,我不知道是否可以安全地假设 php-fpm 为我正确处理所有边缘情况。我(显然)不想出现死锁,但我不确定我是否可以相信 PHP 永远不会让我的代码处于无法获取互斥体的状态,因为获取互斥体的会话要么被优雅地终止,要么不优雅地终止。

我考虑过使用MySQLLOCK TABLES方法,但还有更多的疑问,因为虽然我比 PHP 锁更信任 MySQL 锁,但我担心如果 PHP 在持有 MySQL 会话锁的同时中止请求(*out* 崩溃),MySQL 可能会保持表锁定(特别是.因为我可以很容易地想象出会导致这种情况发生的代码)。

老实说,我对一个非常基本的 C 扩展感到最满意,在其中我可以准确地看到正在进行哪些 POSIX 调用以及使用哪些参数来确保我想要的确切行为。但我不期待编写该代码。

有人想分享有关 PHP 的并发相关最佳实践吗?


事实上,我认为无论什么解决方案都不需要复杂的互斥体/信号量。

存储在 PHP 中的表单密钥$_SESSION就是你所需要的。作为一个很好的副作用,此方法还可以保护您的表单免受 CSRF 攻击。

在 PHP 中,会话通过获取 POSIX 来锁定flock()和 PHP 的session_start()等待直到用户会话被释放。你只需要unset()第一个有效请求的表单密钥。第二个请求必须等待第一个请求释放会话。

然而,当在涉及多个主机的(不是基于会话或源 IP 的)负载平衡场景中运行时,事情会变得更加复杂。对于这种情况,我相信您会在这篇精彩的论文中找到有价值的解决方案:http://thwartedefforts.org/2006/11/11/race-conditions-with-ajax-and-php-sessions/ http://thwartedefforts.org/2006/11/11/race-conditions-with-ajax-and-php-sessions/

我通过以下演示重现了您的用例。只需将此文件扔到您的网络服务器上并测试它:

<?php
session_start();
if (isset($_REQUEST['do_stuff'])) {
  // do stuff
  if ($_REQUEST['uniquehash'] == $_SESSION['uniquehash']) {
    echo "valid, doing stuff now ... "; flush();
    // delete formkey from session
    unset($_SESSION['uniquehash']);
    // release session early - after committing the session data is read-only
    session_write_close();
    sleep(20);  
    echo "stuff done!";
  }
  else {
    echo "nope, {$_REQUEST['uniquehash']} is invalid.";
  }     
}
else {
  // show form with formkey
  $_SESSION['uniquehash'] = md5("foo".microtime().rand(1,999999));
?>
<html>
<head><title>session race condition example</title></head>
<body>
  <form method="POST">
    <input type="hidden" name="PHPSESSID" value="<?=session_id()?>">
    <input type="text" name="uniquehash" 
      value="<?= $_SESSION['uniquehash'] ?>">
    <input type="submit" name="do_stuff" value="Do stuff!">
  </form>
</body>
</html>
<?php } ?>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 PHP 中防止竞争条件的最可靠和安全的方法 的相关文章

  • 在php中获取二进制数据大小的正确方法是什么?

    我已阅读文件的一部分 现在想确保该部分的大小正确 我怎样才能在 php 中做到这一点 part fread file 1024 return some function part 1024 我已经阅读了这些示例 但我怀疑是否要使用 strl
  • 计算两个数字之间的差异

    我想计算两个给定数字之间的差异 例如 1 5 或 24 35 我必须将数组中的数字分开并写出它们之间的差异 如下所示 1 2 3 4 5 或 24 25 26 27 28 29 30 31 32 33 34 35 是否有任何 php 函数可
  • 如何通过键查找最大和最小日期

    我有一个数组 a array 2010 05 03 gt 100 2010 05 04 gt 400 2008 05 01 gt 800 2011 01 01 gt 800 我如何找到最大值和最小值key date 例如 max gt 20
  • 如何在 标签中用 %20 替换空格

    我想替换 html 文本的图像标签中的所有空格 Example img src to img src photo 201 jpg 我没有找到 preg replace 的解决方案 但它可能是一个简单的正则表达式行 谢谢 Edit 抱歉各位
  • 基于 PHP 的 CSV 编辑器? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有谁知道用 PHP 编写的在线 CSV 编辑器允许用户打开 编辑和保存给定的 CSV 文件 我能找到的只
  • 为什么我应该使用 $_GET 和 $_POST 而不是 $_REQUEST? [复制]

    这个问题在这里已经有答案了 除此之外 REQUEST从 cookie 读取 有什么理由我应该使用 GET and POST代替 REQUEST 这样做的理论和实践理由是什么 当我只想让用户的某些数据返回某些数据时 我使用 REQUEST 当
  • 如何在 PHP 中正确分割路径

    执行以下操作的最佳方法是什么 我通过 AJAX 请求获取路径 e g dir1 dir2 dir3 dir4 我需要在我的网页上这样展示它 dir1 gt gt dir2 gt gt dir3 gt gt dir4 它们每个都是 html
  • FPDF - 内嵌粗体文本

    我正在尝试从 PHP 创建 PDF 出于法律原因 我们需要将免责声明的一部分设为粗体 并且需要概述免责声明 我当前的代码使用 if isset POST optout POST optout yes pdf gt Ln 5 pdf gt S
  • 适用于 Windows 的 PHP 支持的 GUI 应用程序

    我知道 PHP 是一种解释性语言 对于基于 Web 的事物来说 不是为在实际操作系统上运行 GUI 应用程序而设计的 但是有没有办法呢 基本上 是否有一个框架 系统允许我创建 本机 基本上是二进制文件 exe 看起来像带有本机控件和所有内容
  • Propel Query 中的动态表名称

    我想知道您是否可以使 propel 查询的表名称动态化 有点像变量 一个例子类似于 DynamicVar Query create 我让它在 ifs 中工作 就像下面的例子一样 但如果更动态地制作 可以删除相当多的行 这些表的设置都是相同的
  • 使用 DOM 获取 div 的内容(包括子标签)

    我正在使用 DOM 来获取 div 标签的内容 但内部 html 部分未显示 功能是 dom new DOMDocument libxml use internal errors true dom gt loadHTMLFile url l
  • 将秒转换为天、小时、分钟和秒

    我想转换一个变量 uptime这是秒 分为天 小时 分钟和秒 Example uptime 1640467 结果应该是 18 days 23 hours 41 minutes 这可以通过以下方式实现DateTime http php net
  • 在 MySQL 中搜索多个单词

    我使用 HTML 表单来允许用户查找数据库表中的条目
  • 解析 PHP 响应:未捕获的语法错误:意外的标记 <

    我正在使用 AJAX 来调用 PHP 脚本 我唯一需要从响应中解析的是脚本生成的随机 ID 问题是 PHP 脚本会引发许多错误 这些错误实际上很好 不会妨碍程序功能 唯一的问题是当我跑步时 parseJSON response I get
  • 读写器的信号量解决方案:更新读取器计数和等待或发出读/写二进制信号量信号之间的顺序?

    从操作系统概念来看 在解决第一个读者 作者问题时 读者 进程共享以下数据结构 semaphore rw mutex 1 semaphore mutex 1 int read count 0 do wait rw mutex writing
  • 无需下载整个文件即可读取 ID3 标签

    是否可以读取 MP3 文件的 ID3 标签 持续时间 艺术家 标题 而无需下载整个文件 我做了一些测试 只需下载 MP3 文件的几个字节就可以获得艺术家和标题标签 但我不确定持续时间和其他标签是否可能 Thanks 我刚刚发现 ffmpeg
  • WordPress 事件按元生效日期排序

    我在获取参数数组以按 Wordpress 中的日期对事件列表进行排序时遇到一些问题 我在 Stack Overflow 和其他地方找到了几个建议的解决方案 但经过大量的试验和错误后 这些解决方案似乎都不起作用 这没什么花哨的 而且应该比这容
  • sqlsrv_num_rows 不返回任何值

    我正在尝试获取查询中返回的行数 while 循环遍历结果有效 但由于某种原因 sqlsrv num rows 不返回任何值 result SELECT from dtable WHERE id2 apple query sqlsrv que
  • PHP 中的嵌套 JSON 输出

    我正在为 iOS 应用程序构建 API 并尝试将 mySQL 数据转换为 JSON 字符串进行处理 所需的输出将需要顶级订单详细信息 例如客户名称和地址 然后是订购的产品子数组 我需要的两个表中有相当多的字段 我希望拥有所有字段 我已经构建
  • NodeJS 和 PHP (Laravel) 集成用于 Socket.IO 实时聊天

    目前我有一个我写过的网站PHP通过Laravel 框架 我已经使用写了一个实时聊天nodeJS with 套接字IO and Express现在我想做的是将它集成到我已经编写的 Laravel 网站中 问题是聊天必须在主页中 当前由 Lar

随机推荐

  • ExtJS - 动态格式化 GridPanel 行?

    我有带有布尔值的记录 并且根据布尔值 我希望 GridPanel 的行呈现为粗体 我确信有一个很好的 GridView 风格的方法可以做到这一点 但我似乎找不到它 Thanks 您的答案是正确的 但我想指出 无需提供实例化的 GridVie
  • 将用户输入从 NodeJS 发送到 shell 脚本

    我有这个 NodeJS 脚本 var util require util process require child process ls process exec test sh ls stdout on data function da
  • Mapbox GL JS:如果单击标记,则忽略地图单击事件

    我在地图上有一个标记 我想在单击它时更改其状态 并在单击地图上的其他位置时将其更改回来 问题是map on click console log 单击标记时也会触发 我只想查看标记单击事件 因为地图单击会调用状态回滚
  • 使用 Jersey 上传文件:FormDataContentDisposition 为 null

    我正在尝试使用 Jersey 实现文件上传 所以我遵循了这个示例 http www mkyong com webservices jax rs file upload example in jersey http www mkyong co
  • Moment js 将毫秒转换为日期和时间

    我的当前时间以毫秒为单位 1454521239279 如何将其转换为 03 FEB 2016 和时间 11 10 PM 矩解析器 moment 1454521239279 format DD MMM YYYY hh mm a parse i
  • 致命:无法获取凭证存储锁:文件存在

    我正在使用 git scm 并尝试推送到存储库 这样做后 我收到了以下消息 fatal unable to get credential storage lock File exists 虽然推送最终确实推送成功 但我想知道为什么会出现这个
  • 如何将 FlowDocument 中的表格放在一起?

    我想如果我将表格放在段落中 我可以使用 KeepTogether 属性将表格保持在一起 该表格用于报告的总计 客户不希望它们分成两页 想象一下 表中有 5 行 我快要疯了 不知道下一步该尝试什么 最后一行代码 myFlowDocument
  • (Laravel) 基于用户输入的接口动态依赖注入

    我目前在架构和实现方面面临着一个非常有趣的困境 我有一个名为ServiceInterface其中有一个方法称为execute 然后我对该接口有两种不同的实现 Service1 and Service2 它正确地实现了execute方法 我有
  • 是否有任何设计模式可以避免嵌套开关盒?

    我见过类似的线程 但是 不确定如何准确地将解决方案应用到我的案例中 我的问题是我有一组用例 可以说 A B C 当输入传递 2个用例是输入 是列出的用例中的任何2个时 我需要执行某些命令 例如 switch input1 case A br
  • AWS 步骤和批量动态命令

    我有一个带有单个作业定义的批处理作业 该作业定义根据环境命令选项上的参数执行 原值为 param2 XXX 但我需要根据 Step Functions 的输入参数使其保持动态 param2 param2 YYY 我无法将 Step Func
  • facet_grid 中的自由色阶

    假设我有以下数据框 Set seed for RNG set seed 33550336 Create toy data frame loc x lt c a 1 b 2 c 3 loc y lt c a 3 b 2 c 1 scaling
  • Imagemagick - 更改 Heroku 上的 policy.xml

    我正在尝试使用 Imagemagick 在 Heroku 上通过 https 访问图像 如何更改 Heroku 上的策略 在 policy xml 中 Heroku 于 2016 年 5 月进行了 ImageMagick 安全更新 http
  • WordPress 禁用 /admin 重定向到 /wp-admin

    我的网站是用wordpress 4 5 2 对于wordpress控制面板 可以正常登录myweb com wp admin目录 但我有另一个控制面板 目录中有其他应用程序myweb com admin 问题是每当我尝试登录myweb co
  • 通过输入框和 jquery 过滤选择列表

    我想知道是否可以获得一些帮助 通过 jquery 使用输入框过滤选择列表 这是我的 js 的样子 但它似乎不起作用 我猜这是因为选择列表中的选项不可隐藏
  • 我可以直接在表示层中使用域对象吗

    我最初有以下设置 表示层使用 gt 通过 WCF 生成的服务代理 gt 实际服务组件 代理生成于其中 通过 IIS 托管 gt 域层 业务逻辑 gt DAL 最初就是这样 但发现服务和 DAL 也应该访问域层 现在我有一个场景 在表示层中
  • 因为我无法在顶层运行等待,所以我必须将其放入异步函数中 - 为什么我可以直接调用该异步函数?

    我有一个简短的 Node js 脚本 我需要另一个包并从中调用异步函数 然后想要打印返回值 如果我简单地await来自顶层的返回值 然后我会得到一个错误 说我只能使用await在异步函数本身内部 所以显然要走的路是这样的 async fun
  • 在 boost::signals2 中混合使用 boost 智能指针和 C++11 智能指针

    我有一个使用的应用程序boost signals2组件之间进行通信 我试图通过使用它的自动连接管理功能slot type track weak ptr 问题 在我的整个计划中 std shared ptr用来 track期望一个boost
  • Android编程-屏幕分辨率

    我是 Android 编程新手 我见过运行 Android 的不同屏幕分辨率的手机 如何创建一个适用于所有 Android 设备的应用程序 而应用程序视图不会出现任何失真 简短的答案是调整所有布局项目的大小dip dip是缩写Density
  • iOS 增强现实,带有指南针和位置

    我正在尝试开发一个迷你 Around Me 例如使用相机 指南针和位置 我想在屏幕上显示地点的图像 目前我已经有了指南针的位置和方向 我想知道如何确定我要显示的位置的位置 感谢您的帮助 一旦有了相对距离和方位 您就可以使用以下算法从同一坐标
  • 在 PHP 中防止竞争条件的最可靠和安全的方法

    我需要在 PHP 中使用互斥体或信号量 这让我感到害怕 澄清一下 我并不害怕编写正确同步的无死锁代码 也不害怕并发编程的危险 而是害怕 PHP 处理边缘情况的能力 快速背景知识 编写位于用户和第 3 方信用卡网关之间的信用卡处理程序接口 需