我有一个POST
表单,它确实将数据发送到同一个文件,如果使用点击浏览器中的后退按钮,他可以轻松地重新发送数据,它将是还在读。
有没有办法避免这种行为?
答案 0 :(得分:4)
有两种一般方法。
首先是post-redirect-get
模式,其中用户填写signup.php
上的表单POST
submit.php
REDIRECT
成功完成后发送回thanks.php
到thanks.php
。浏览器会看到重定向响应,并为submit.php
发出GET。这样做是因为没有重定向,点击刷新会重新加载POST
,导致重新发布表单数据警告并且signup.php
-----------
...
<input type="text" name="email">
...
submit.php
----------
...
if ($_POST) {
// process data
header('Location: thanks.php');
}
...
thanks.php
----------
...
Thanks
...
请求被双重发布。重定向解决了这个问题。
nonce
第二种方法是在表单中嵌入<input type="nonce" value="<?= uniqid(); ?>">
键。这种方法还具有防止CSRF攻击的额外好处。这里的方法是在你的表单中注入一个隐藏的guid:
{{1}}
服务器需要跟踪所有nonce密钥问题(在数据库或其他东西中),当它收到表单时,它将处理表单并从数据库中删除nonce密钥。如果用户第二次重新提交表单,则nonce密钥将不存在,服务器可以通过忽略或发出警告来处理。
答案 1 :(得分:3)
Levi发送的链接将为您回答。但是如果你想要一个替代方案,我就是这样做的......
用户发布课程,与您的一样。同一个文件。在课程开始时我做后期处理。对于这个例子,我会很简单......
<?php
session_start();
//set form vars ahead of time so you can pre-populate the value attr on post
$form = array(
'name' => '',
'email' => ''
);
if(!empty($_POST))
{
//do some kind of validation...
$errors = array();
if(trim($_POST['name']) == '')
$errors[] = 'Please enter your name';
if(empty($errors))
{
$_SESSION['message'] = 'Thank you for participating';
header('location: /form.php'); // same file
exit;
}
else
{
// set the form vars to the post vars so you don't lose the user's input
$form['name'] = $_POST['name'];
$form['email'] = $_POST['email'];
$message = '<span style="color:red">';
foreach($errors AS $error)
{
$message .= $error."<br />";
}
$message .= '</span>';
$_SESSION['message'] = $message;
}
}
if(isset($_SESSION['message']))
{
echo $_SESSION['message'];
unset($_SESSION['message']);
}
?>
<form id="some_form" action="" method="post">
<fieldset>
<label for="name">Name</label> <input type="text" name="name" value="<?php echo $form['name']; ?>" />
<br /><br />
<label for="email">Email</label> <input type="text" name="email" value="<?php echo $form['email']; ?>" />
<br /><br />
<input type="submit" name="submit" value="Submit" />
</fieldset>
</form>
现在您可以反复刷新,而不是两次提交表单。
编辑以显示更多示例。显然,您的验证和错误处理应该比这更复杂,但这应该会让您在正确的方向。
答案 2 :(得分:2)
如果用户想要这样做,你不能100%阻止这种情况,但为了避免这种情况发生,请查看Post/Redirect/Get。
答案 3 :(得分:1)
发送表单时,将随机数推送到$_SESSION['stopdupe']
值,然后输入隐藏字段。
收到处理表格时:
$_SESSION['stopdupe']
是否存在,并匹配隐藏字段的值。 (如果没有,请忽略帖子)$_SESSION['stopdupe']
这样,如果用户按下提交按钮两次,则不会处理第二个请求。
另一个有用的技巧是使用表单上的onSubmit
javascript事件来禁用该按钮,因此用户无法轻松提交多次。
答案 4 :(得分:1)
这对我有用。我使用smarty,但它也可以毫不聪明地完成。这只是一个想法。根据需要修改它。
HTML表单:
<form action="submit_file.php" method="POST">
<input type="hidden" name="submit_edit" value="1">
<input type="text" name="data"/>
</form>
globals.php中的php
if (count($_POST) > 0) {
if (isset($_POST['submit_edit']) && $_POST['submit_edit'] == '1'
&& time() - $_SESSION['last_request_time'] < 100
&& count($_SESSION['last_request']) > 0
&& serialize($_SESSION['last_request']) == serialize($_POST)) {
$oSmarty->assign('display_time_alert', '1');
unset($_POST['submit_edit']);
unset($_REQUEST['submit_edit']);
} else {
$_SESSION['last_request_time'] = time();
$_SESSION['last_request'] = $_POST;
}
}
这是在head.tpl
{literal}
<script>
function showTimeAlert(){
alert('{/literal}{tr var="Cannot send the same request twice"}{literal}');
}
{/literal}
{if isset($display_time_alert) AND $display_time_alert eq '1'}
showTimeAlert();
{/if}
{literal}
</script>
{/literal}
最后是submit_file.php
require_once("globals.php");
if(isset($_POST['submit_edit']) && $_POST['submit_edit'] == '1')){
//record data
}
$oSmarty->dysplay(some.tpl);//in some.tpl is included head.tpl
答案 5 :(得分:0)
在First Page中使用一个会话变量并将值赋值为1.示例:
<form name="frm1" method="post">
<?php $_SESSION['resend_chk']=1; ?>
<input type="text" name="a" />
<input type="submit" name="submit">
</form>
在第二页:
if(isset($_REQUEST['submit'])
{
if($_SESSION['resend_chk']==1)
{
insert to db OR and any transaction
$_SESSION['resend_chk']=0;
}
}
它将插入一次或者事务将在db中发生一次并且会话变量的值将改变,下次当我们尝试重新发送数据时它不会执行任何事务,因为会话变量的值已经更改。 / p>