如何防止页面刷新时的表单重新提交(F5 / CTRL + R)

我有一个简单的表单提交文本到我的SQL表。 问题是,用户提交文本后,他们可以刷新页面,数据被重新提交,而无需再次填写表单。 提交文本后,我可以将用户redirect到另一个页面,但我希望用户保持在同一页面上。

我记得阅读一些关于给每个用户一个独特的会话ID,并与另一个值解决了我遇到的问题,但我忘了它在哪里。

使用Post / Redirect / Get模式。 http://en.wikipedia.org/wiki/Post/Redirect/Get

通过我的网站,我将在cookie或session中存储消息,在post后redirect,读取cookie / session,然后清除会话或cookievariables的值。

  1. 使用标题并redirect页面。

    header("Location:your_page.php"); 您可以redirect到相同的页面或不同的页面。

  2. 插入到数据库后,请取消$ _POST的设置。

    unset($_POST);

你应该使用一个Post Redirect Get模式来处理这个,但是如果你不知何故结束了一个PRG不可行的位置(例如表单本身在一个包含中,阻止redirect),你可以散列一些请求参数根据内容创build一个string,然后检查是否已经发送。

 //create digest of the form submission: $messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']); //and check it against the stored value: $sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:''; if($messageIdent!=$sessionMessageIdent){//if its different: //save the session var: $_SESSION['messageIdent'] = $messageIdent; //and... do_your_thang(); } else { //you've sent this already! } 

表单处理完成后,您将redirect到另一个页面:

 ... process complete.... header('Location: thankyou.php'); 

你也可以redirect到同一页面。

如果您正在做类似于注释的事情,并希望用户留在同一页面上,则可以使用Ajax来处理表单提交

一个非常可靠的方法是在post中实现一个唯一的ID并caching它

 <input type='hidden' name='post_id' value='".createPassword(64)."'> 

然后在你的代码中这样做:

 if( ($_SESSION['post_id'] != $_POST['post_id']) ) { $_SESSION['post_id'] = $_POST['post_id']; //do post stuff } else { //normal display } function createPassword($length) { $chars = "abcdefghijkmnopqrstuvwxyz023456789"; srand((double)microtime()*1000000); $i = 0; $pass = '' ; while ($i <= ($length - 1)) { $num = rand() % 33; $tmp = substr($chars, $num, 1); $pass = $pass . $tmp; $i++; } return $pass; } 

你可以通过会话variablesLike来完成表单重新提交

首先你必须在表单页面上设置文本框中的rand()和$ _SESSION ['rand']

 <form action="" method="post"> <?php $rand=rand(); $_SESSION['rand']=$rand; ?> <input type="hidden" value="<?php echo $rand; ?>" name="randcheck" /> Your Form's Other Field <input type="submit" name="submitbtn" value="submit" /> </form> 

在检查$ _SESSION ['rand']与文本框$ _POST ['randcheck']值之后

  if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand']) { //Your Code here } 

使用表单数据后,只需将其redirect到同一页面即可。 我已经尝试过了。

 header('location:yourpage.php'); 

Moob的post的精炼版本。 创buildPOST的散列,将其保存为会话cookie,并对每个会话进行散列比较。

 // Optionally Disable browser caching on "Back" header( 'Cache-Control: no-store, no-cache, must-revalidate' ); header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' ); header( 'Last-Modified: ' . gmdate('D, d MYH:i:s') . 'GMT' ); $post_hash = md5( json_encode( $_POST ) ); if( session_start() ) { $post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash; $_SESSION[ 'post_hash' ] = $post_hash; session_write_close(); } else { $post_resubmitted = false; } if ( $post_resubmitted ) { // POST was resubmitted } else { // POST was submitted normally } 

将其插入数据库后,调用unset()方法清除数据。

未设置($ _ POST);

要防止刷新数据插入,请在插入logging后对相同页面或不同页面执行页面redirect。

标题( '位置:'。$ _ SERVER [ 'PHP_SELF']);

基本上,你需要redirect的页面,但它仍然可以成为一个问题,而你的networking慢(redirect头从服务器端)

基本情景示例:

点击提交button两次

解决的办法

  • 客户端

    • 一旦客户端点击它,禁用提交button
    • 如果你使用Jquery: Jquery.one
    • PRG模式
  • 服务器端

    • 发送请求时使用基于区分的哈希时间戳/时间戳。
    • 使用请求令牌。 当主要负载分配临时请求时,如果重复被忽略。

使用Keverw的Post / Redirect / Get模式回答是一个好主意。 但是,你不能留在你的网页上(我想这是你要求的?)另外,它有时可能会失败 :

如果Web用户在首次提交完成之前由于服务器滞后而刷新,导致某些用户代理中出现重复的HTTP POST请求。

另一个select是将文本存储到会话中,如下所示,将文本写入SQL数据库:

 if($_SERVER['REQUEST_METHOD'] != 'POST') { $_SESSION['writeSQL'] = true; } else { if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL']) { $_SESSION['writeSQL'] = false; /* save $_POST values into SQL */ } } 

我也想指出,你可以使用JavaScript方法, window.history.replaceState来防止重新提交刷新和返回button。

 <script> if ( window.history.replaceState ) { window.history.replaceState( null, null, window.location.href ); } </script> 

这里的概念certificate: https : //dtbaker.net/files/prevent-post-resubmit.php

我仍然会推荐一个Post / Redirect / Get方法,但这是一个新颖的JS解决scheme。

如何防止没有redirect的PHP表单重新提交。 如果你正在使用$ _SESSION(在session_start之后)和一个$ _POST表单,你可以这样做:

 if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) { // do your stuff, save data into database, etc } 

在你的html表单中放置这个:

 <input type="hidden" id="act" name="act" value="<?php echo ( empty($_POST['act']) || $_POST['act']==2 )? 1 : 2; ?>"> <?php if ( $_POST['act'] == $_SESSION['act'] ){ if ( empty( $_SESSION['act'] ) || $_SESSION['act'] == 2 ){ $_SESSION['act'] = 1; } else { $_SESSION['act'] = 2; } } ?> 

因此,每次提交表格时,都会生成一个新的行为,并存储在会话中,并与发布行为进行比较。

Ps:如果您使用Get表单,则可以使用GET轻松更改所有POST,也可以使用。

我发现下一个解决方法。 处理POST请求后,您可以通过操作history对象来转义redirect。

所以你有HTML表单:

 <form method=POST action='/process.php'> <input type=submit value=OK> </form> 

当你在你的服务器上处理这个表单时,你不用像下面这样设置Location标头来将用户redirect到/the/result/page

 <?php process POST data here ... header('Location: /the/result/page'); exit(); ?> 

在这里输入图像描述

在处理POST编辑的数据之后,您将渲染小<script>和result /the/result/page

 <?php process POST data here render the <script> // see below render `/the/result/page` // OK ?> 

<script>你应该渲染:

 <script> window.onload = function() { history.replaceState("", "", "/the/result/page"); } </script> 

结果是:

在这里输入图像描述

正如你所看到的,表单数据是POSTprocess.php脚本的。
此脚本一次处理POST编辑数据和渲染/the/result/page

  1. 没有redirect
  2. 刷新页面(F5)时无法重新POST数据
  3. 当您通过浏览器历史logging导航到上一页/下一页时,不会重新POST

UPD

作为另一种解决scheme,我要求function请求 Mozilla FireFox团队允许用户设置NextPage标题,这将像Location标题,并使post/redirect/get模式过时。

简而言之。 当服务器进程成功发布POST数据时:

  1. 设置NextPage标题而不是Location
  2. 呈现处理POST表单数据的结果,因为它将在post/redirect/get模式中呈现GET请求

浏览器依次查看NextPage标题时:

  1. 使用NextPage值调整window.location
  2. 当用户刷新页面时,浏览器将向NextPage协商GET请求,而不是重新发布POST表单数据

我认为这将是优秀的,如果执行,不会? =)

为什么不使用$_POST['submit']variables作为逻辑语句来保存表单中的内容。 你总是可以redirect到同一个页面(如果它们刷新了,当它们go back到浏览器时,submit postvariables就不会被设置了,只要确保你的提交button有一个namesubmit id