当用户通过Post方法发送表单数据时,我想阻止F5重新提交。
所以,首先,我有一个页面,其中有一个提交信息/数据的表单,当正确提交时,我想要闪回一条带有正面反馈的消息,并清理$ _POST ['vars']中的所有数据。
PHP代码:
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$error= '';
if (!$_POST['name']) {
$error.= '- Introduza o seu Nome.<br>';
}
if (!$_POST['email']) {
$error.= '- Introduza o seu Email.<br>';
}
if (!$_POST['message']) {
$error.= '- Introduza a sua mensagem.<br>';
}
if (empty($_POST['check'])) {
$error.= '- Por favor, confirme que é um humano.<br>';
}
if ($error) {
$result="Temos erros no formulário. Por favor corriga os seguinte(s):<br> $error";
} else {
mail("email@email", "Mensagem de Contato", "Nome: ".$_POST['name']. "Email: ". $_POST['email'] . "Mensagem: " . $_POST['message'] );
$result='A sua mensagem foi enviada. Obrigado<br>';
}
}
?>
HTML:
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>Formulário de Contato</h1>
<p>Envie mensagem pelo formulário em baixo</p>
<?php if (isset($_POST['submit'])) {
echo $result;
}
?>
<br>
<form method="post" action="" role="form">
<div class="form-group">
<input type="text" name="name" class="form-control" placeholder="Coloque aqui o seu nome" value="<?php
if (isset($_POST['name'])) {
echo $_POST['name'];
}
?>">
</div>
<div class="form-group">
<input type="email" name="email" class="form-control" placeholder="O seu email" value="<?php
if (isset($_POST['email'])) {
echo $_POST['email'];
}
?>">
</div>
<div class="form-group">
<textarea name="message" name="message" class="form-control" cols="30" rows="10" placeholder="Escreva a sua mensagem"><?php
if (isset($_POST['message'])) {
echo $_POST['message'];
}
?></textarea>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="check" >Confirma que é humano.
</label>
</div>
<div align="center">
<input type="submit" name="submit" class="btn btn-secondary" value="Enviar Mensagem">
</div>
</div>
</form>
</div>
</div>
</div>
答案 0 :(得分:4)
让我们看看要求:
因此,当浏览器 收到FORM时,它只能将其提交给PHP。不允许使用Javascript / AJAX恶作剧。所以按F5 将是不可避免的。
&#34;清算$ _POST&#34;意味着没有 - 您无法从服务器修改浏览器可能(重新)发布的数据,除非浏览器已经信任您并已下载相应的Javascript。
一旦交易完成,能够远程更改_POST
将是一个可怕的安全漏洞(想想电子支付)。
但你要做的就是不重复操作。您无需清除$_POST
即可执行此操作。我们唯一可以做的就是识别重新提交并以不同方式对待它(在这种情况下,不再次发送邮件);这就是我们需要做的一切。
我们通过在FORM中添加唯一的,不可重复使用的ID来实现此目的,例如,当页面是用PHP制作的时候uniqueid()
:
<input type="hidden" name="nonce" value="0cf8059606c73ab872cd8e0064" />
浏览器接收表单,用户提交表单。各个字段填充_POST。
服务器接收POST,并将nonce保存在$_SESSION
数组中......并检查这是第一次在_POST中看到该nonce。
if (!in_array($_POST['nonce'], $_SESSION['posts'])) {
// It is the first time. We add it to the list of "seen" nonces.
$_SESSION['posts'][] = $_POST['nonce'];
do_something_with($_POST);
} else {
print '<div class="errormessage">Please do not resubmit.</div>';
}
或者,如果不成功,我们可以简单地运行测试并死掉:
if (in_array($_POST['nonce'], $_SESSION['posts'])) {
die('Não atualize a pagina. Click <a href="/">aqui</a> para voltar para a home.');
}
当然,如果在回复提交时生成的页面再次具有FORM(例如,可以一个接一个地插入多个记录),则需要重新生成 uniqueid隐藏字段
所以F5将提交一个独特的&#34;已经看过&#34;并且完全忽略_POST字段,而使用收到的新数据的新诚实提交将提供一个新的,但尚未看到的值,因此允许发布。
更确定的是,您可以在提交之前(即首次打开表单时)生成uniqueid并将存储在会话中。然后,在提交时,您将只接受为该会话生成的ID:
if (array_key_exists('nonce', $_POST)) {
$nonce = $_POST['nonce'];
unset($_POST['nonce']); // for transparency with extant code
if (array_key_exists($nonce, $_SESSION['securePosts'])) {
if ($_SESSION['securePosts'][$nonce]) {
$error = false;
// Punch the ticket so it can't be reused
$_SESSION['securePosts'][$nonce] = false;
} else {
$error = 'FORM resubmitted';
}
} else {
$error = 'Someone sent a fake FORM or a FORM from an expired session';
}
}
if (!$error) {
// We can treat $_POST as legit.
// Here the code that "does something".
}
$uniqueid = secureUniqueId();
$_SESSION['securePosts'][$uniqueid] = true; // Ready to be triggered
print "<input type=\"hidden\" name=\"nonce\" value=\"{$uniqueid}\" />";
// If no error, empty DIV
print "<div id=\"error\">{$error}</div>";
上述方法不支持支持书签成功&#34;成功&#34;页。
能够&#34;书签&#34; &#34;结果&#34;对于初学者,您需要在网址中添加唯一ID:
<form method="POST" action="?nonce={$nonce}">
这样,当您单击SUBMIT时,同一页面会在$_GET['nonce']
参数中收到nonce。缺少nonce意味着我们需要生成一个空表单。
然后,在提交时,您需要将nonce存储在数据库中或以某种方式将nonce与结果一起保存:
nonce results (in separate columns)
eb72ab1736a32... invoice=1234,amount=32,...
此时,当你收到一个随机数时,
1. it is not in the database, and there is POST.
- do whatever needs to be done and update the database accordingly.
2. is in the database, and there is a POST.
- it is a resubmission. Ignore it, or display an error
3. is not in the database, and there is no POST.
- it's a prankster, or a database error.
4. is in the database, and there is no POST.
- is a bookmark. Display the success page as in (1).
如果用户按下F5,他就是(2)。如果他将页面保存为书签,则URL中的nonce来自最近完成的提交,因此用户在case(1)中,并根据case(4)设置为继续。