0

我有一个数据库和一个表(innoDB):表。

此表中的行是:m1 和 m2。

我在一页上有 2 个提交按钮。

提交 1 执行此操作:

Database::q('UPDATE table SET m1 = ?s, m2 = ?i WHERE id = ?i', $n, 0, $ID);

提交 2 这样做:

Database::q('UPDATE table SET m2 = ?s WHERE id = ?i', $n2, $ID);

问题:如果用户同时提交两个表单。假设提交 1 为 100 000 ($n),提交 2 为 50 ($n2)。结果将在更新后:m1 为 99 950,m2 为 100 000。

我怎样才能防止这种情况?我尝试使用事务,但它仍然无法正常工作。

这个语法正确吗?我不明白什么时候使用哪个:执行,查询,执行?

try {
   Database::beginTransaction();
   Database::q('..');
   Database::commit();
} catch (Exception $e) {
   Database::rollBack();
   echo 'ERROR!';
}

这是我正在使用的数据库类:http: //pastebin.com/PfsiYysX

4

2 回答 2

0

正如 Martin 建议的那样,一些 javascript 将防止意外按下两个按钮。但是,它并非在所有情况下都有效,并且当然不能防止故意提交两种形式。但是,它会阻止大多数用户到达您对操作应用真实、有效控制的位置。

更安全的解决方案是合并一个单次使用的 CSRF 令牌(两种形式的相同令牌的副本) - 在第一次请求时检查并过期令牌。这样做的问题是,如果用户拆分会话(打开新窗口),他们可能会认为存在错误。有一些方法可以缓解这种情况——但这取决于应用程序如何实现的具体细节。

更好的解决方案是将 建模为有限状态机,允许在数据处于初始状态时进行两次更新,但不允许后续更新。我会提供一个示例,但从您提供的数据来看这是不可能的。因此,请考虑一下:用户已经装满了购物篮并去结账。此时他们有 2 个选择 - 购买或丢弃篮子。如果他们单击“进行购买”,如果是,那么您将状态设置为“购买”,其中购物篮状态为“结帐时”,如果成功,则继续进行购买处理。如果他们单击“丢弃”,则您将购物篮状态更改为“丢弃”,状态为“结帐时”,如果成功,则继续进行清理。如果任一操作不成功,然后你报错。请注意,每个操作都应该自动提交 - 这不使用锁。

于 2013-01-14T14:42:02.120 回答
0

如果用户同时提交两个表单

意味着您对 1 个文件或 2 个单独的 php 文件有 2 个 http 请求 - 并不重要。无论如何,没有办法(也没有交易)来避免这个问题。

事务用于保护需要一个接一个地执行的一堆查询。在执行之前,它们必须为 sql 引擎所知。对于 2 个请求,发送不同的单语句查询,这是不可能的。

一种出路是通过javascript停用按钮2,按下1,反之亦然。但这仅适用于启用 js 的行为良好的客户端(无安全措施!)。

于 2013-01-14T14:29:42.517 回答