【发布时间】:2014-12-09 21:59:15
【问题描述】:
伙计们,我知道这个话题已经死了,但是在阅读了这里的许多回答问题后,我离解决方案还差得远。
问题:提交表单后,即使使用Post-Redirect-Get,用户仍然可以按返回按钮返回到原始表单,这将与提交时完全相同。然后用户只需按下提交按钮即可再次发送相同的数据。
我意识到尝试禁用后退按钮是一种不好的做法,所以我想要: 1.- 能够清除表单,以便在通过后退按钮返回已发布的表单时用户输入的数据不再存在。 2.- 能够在代码中区分原始表单提交和重复表单提交。
我一直在读到您可以使用随机数完成 #2。在Stop data inserting into a database twice 我读到了
对于重新提交存在问题的表单,我使用 nonces(“使用一次的数字”)。创建一个随机数/字符串,将其存储在会话数据中,并将其作为隐藏字段添加到表单中。提交表单时,检查 POSTed 值是否与会话值匹配,然后立即清除会话值。重新提交将失败。 (詹姆斯·索科尔)
看起来很清楚,但我似乎无法让它发挥作用。这是骨架代码,尽可能简短。我已经单步执行了。当我按下后退按钮时,PHP 代码从头开始执行。 $_SERVER['REQUEST_METHOD'] 返回GET 所以好像表单还没有发布,代码落空并生成一个新的随机数。当表单提交(第二次)时,$_SESSION['rnd'] 等于 $_POST['rnd'],因此重新提交的表单会像第一次一样被处理。
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($_SESSION['rnd'] == $_POST['rnd']) {
$form_data = $_POST; //process form
$_SESSION['rnd'] = 0;
$msg = 'data posted';
}
else {
$msg = 'cannot post twice';
}
}
else {
$msg = 'ready to post';
$rnd = rand(100,999);
$_SESSION['rnd'] = $rnd;
}
?>
<html>
<head>
<title>app page</title>
</head>
<body>
<h1>app page</h1>
<h3><?= $msg ?></h3>
<form method="post">
Field 1: <input type="text" name="field1"
value="<?= (isset($form_data['field1']) ? $form_data['field1'] : '') ?>">
<input type="submit" name="submit" value="Ok">
<input type="hidden" name="rnd" value="<?= (isset($rnd) ? $rnd : $_POST['rnd']) ?>">
</form>
</body>
</html>
感谢您的任何见解。我意识到上面的代码没有实现 PRG,但我认为没关系。问题不是 F5 刷新,而是后退按钮刷新。
【问题讨论】:
-
提交后为什么不直接重定向?
-
重定向可防止用户按 F5 时意外重新提交,但不能防止故意使用后退按钮返回页面并提交新表单而无需填写。也许我应该解释一下应用程序。这适用于教授用来调查学生的调查生成器。他想防止一些恶作剧者填写调查表,然后返回按钮/提交 50 次,从而在调查表中引入大量噪音。但调查是匿名的,因此我们可以针对每个用户进行限制。
-
一个可能的解决方案可能是
js,您只需在提交后重置表单,因此他们无法在返回时检索信息。但我不知道你是否愿意走那条路 -
将“nonce”保存在数据库而不是会话中可能是值得的。会话在几分钟后超时。 'sqlite' 数据库适用于这类事情。
-
@RyanVincent 是的,毫无疑问,但是在数据库或会话中或只是写入文本文件中,问题仍然存在:当 PHP 脚本开始运行时,如何判断它是否正在运行因为它是从浏览器的 URL 栏中执行的,或者因为用户按下了后退按钮。似乎没有办法做到这一点。