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

时间:2011-06-12 04:24:44

标签: php html forms post form-submit

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

我记得读过一些关于给每个用户一个唯一会话ID并将其与另一个值进行比较的信息,这个值解决了我遇到的问题,但我忘记了它的位置。

24 个答案:

答案 0 :(得分:76)

使用发布/重定向/获取模式。 http://en.wikipedia.org/wiki/Post/Redirect/Get

通过我的网站,我会在cookie或会话中存储消息,在帖子后重定向,读取cookie /会话,然后清除该会话或cookie变量的值。

答案 1 :(得分:52)

我还想指出,您可以使用javascript方法window.history.replaceState来阻止重新提交刷新和后退按钮。

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

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

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

答案 2 :(得分:16)

你应该真正使用Post Redirect Get模式来处理这个问题,但是如果你以某种方式最终处于PRG不可行的位置(例如表单本身在include中,防止重定向)你可以哈希一些请求参数根据内容创建一个字符串,然后检查您是否已经发送过它。

//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!
    }

答案 3 :(得分:12)

处理表单后,您将重定向到另一个页面:

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

您也可以重定向到同一页面。

如果您正在执行类似评论的操作并且希望用户保持在同一页面上,则可以使用Ajax处理表单提交

答案 4 :(得分:12)

您可以通过会话变量Like

来完成表单重新提交

首先你必须在文本框中设置rand()并在表单页面上设置$ _SESSION [&#39; rand&#39;]

<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>

使用文本框$ _POST [&#39; randcheck&#39;]值检查$ _SESSION [&#39; rand&#39;]后 像

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

答案 5 :(得分:11)

  1. 使用标题并重定向页面。

    header("Location:your_page.php");您可以重定向到同一页面或不同页面。

  2. 将$ _POST插入数据库后取消设置。

    unset($_POST);

答案 6 :(得分:9)

我使用此javascript行来阻止弹出式窗口,要求其在提交表单后刷新时重新提交表单。

if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}

只需将这一行放在文件的页脚并查看魔术

答案 7 :(得分:7)

一种非常可靠的方法是在帖子中实现一个唯一的ID并将其缓存在

<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;
}

答案 8 :(得分:7)

我找到了下一个解决方法。通过操作history对象处理POST请求后,您可以转义重定向。

所以你有HTML表格:

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

当您在服务器上处理此表单时,您可以设置/the/result/page标题,而不是将用户重定向到Location

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

enter image description here

处理POST个数据后,您渲染小<script>,结果为/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>

结果是:

enter image description here

您可以看到表单数据POSTprocess.php脚本 此脚本处理POST ed数据并立即呈现/the/result/page ,其中包含:

  1. 无重定向
  2. 刷新页面(F5)时
  3. 没有重新POST数据
  4. 当您通过浏览器历史记录导航到上一页/下一页时,
  5. 无需POST
  6. <强> UPD

    作为另一种解决方案,我要求feature request Mozilla FireFox 小组允许用户设置NextPage标头,该标头将像Location标头一样工作并生成{{1模式过时。

    简而言之。当服务器处理成功post/redirect/get数据时:

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

      1. 使用NextPage
      2. 调整window.location
      3. 当用户刷新页面时,浏览器会将NextPage请求与GET进行协商,而不是重新NextPage表单数据
      4. 我认为如果实施这将是非常好的,不会吗? POST

答案 9 :(得分:3)

在使用表单数据后,只需将其重定向到同一页面即可。我试过了。

header('location:yourpage.php');

答案 10 :(得分:3)

Moob帖子的精致版本。创建POST的哈希值,将其保存为会话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 M Y H: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
}

答案 11 :(得分:2)

如何防止没有重定向的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,它也可以正常运行。

答案 12 :(得分:2)

基本上,您需要重定向到该页面,但在互联网速度较慢时仍然会出现问题(从服务器端重定向标头)

基本情景示例:

点击提交按钮两次

解决方法

  • 客户端

  • 服务器端

    • 在发送请求时使用基于差异的哈希时间戳/时间戳。
    • 使用请求令牌。当主要加载时,分配一个临时请求tocken,如果重复,则忽略它。

答案 13 :(得分:2)

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

<强>未设置($ _ POST);

要防止刷新数据插入,请在插入记录后执行页面重定向到同一页面或不同页面。

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

答案 14 :(得分:1)

$_POST['submit'] 变量在页面初始加载时不存在,并且只有在以下条件为真时才能运行 curl。

if($_POST['submit'] == "submit"){

// This is where you run the Curl code and display the output
  $curl = curl_init();



//clear $post variables after posting
$_POST = array();

}

答案 15 :(得分:0)

使用Keverw答案中的Post / Redirect / Get模式是一个好主意。但是,你无法留在你的页面上(我认为这是你要求的?)此外,它有时可能会fail

  

如果网络用户在初始提交完成之前刷新   由于服务器滞后,导致重复的HTTP POST请求   某些用户代理。

另一个选择是存储在会话中,如果文本应该像这样写入SQL数据库:

if($_SERVER['REQUEST_METHOD'] != 'POST')
{
  $_SESSION['writeSQL'] = true;
}
else
{
  if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
  {
    $_SESSION['writeSQL'] = false;

    /* save $_POST values into SQL */
  }
}

答案 16 :(得分:0)

正如其他人所说,不可能不使用post / redirect / get。但与此同时,你可以很容易地做你想做的服务器端。

在您的POST页面中,您只需验证用户输入,但不对其进行操作,而是将其复制到SESSION数组中。然后,您再次重定向回主提交页面。您的主提交页面首先检查您正在使用的SESSION数组是否存在,如果存在,则将其复制到本地数组并取消设置。从那里你可以采取行动。

通过这种方式,您只需完成所有主要工作,即可实现您想要的目标。

答案 17 :(得分:0)

此后,我在大型项目中寻找解决方案以防止重新提交。 该代码可与$ _GET和$ _POST高度配合,并且我不能更改表单元素的行为,否则会出现无法预料的错误。 所以,这是我的代码:

<!-- language: lang-php -->
<?php

// Very top of your code:

// Start session:
session_start();

// If Post Form Data send and no File Upload
if ( empty( $_FILES ) && ! empty( $_POST ) ) {
    // Store Post Form Data in Session Variable
    $_SESSION["POST"] = $_POST;
    // Reload Page if there were no outputs
    if ( ! headers_sent() ) {
        // Build URL to reload with GET Parameters
        // Change https to http if your site has no ssl
        $location = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        // Reload Page
        header( "location: " . $location, true, 303 );
        // Stop any further progress
        die();
    }
}

// Rebuilt POST Form Data from Session Variable
if ( isset( $_SESSION["POST"] ) ) {
    $_POST = $_SESSION["POST"];
    // Tell PHP that POST is sent
    $_SERVER['REQUEST_METHOD'] = 'POST';
}

// Your code:
?><html>
    <head>
        <title>GET/POST Resubmit</title>
    </head>
    <body>

    <h1>Forms:</h1>
    <h2>GET Form:</h2>
    <form action="index.php" method="get">
        <input type="text" id="text_get" value="test text get" name="text_get"/>
        <input type="submit" value="submit">
    </form>
    <h2>POST Form:</h2>
    <form action="index.php" method="post">
        <input type="text" id="text_post" value="test text post" name="text_post"/>
        <input type="submit" value="submit">
    </form>
    <h2>POST Form with GET action:</h2>
    <form action="index.php?text_get2=getwithpost" method="post">
        <input type="text" id="text_post2" value="test text get post" name="text_post2"/>
        <input type="submit" value="submit">
    </form>
    <h2>File Upload Form:</h2>
    <form action="index.php" method="post" enctype="multipart/form-data">
        <input type="file" id="file" name="file">
        <input type="submit" value="submit">
    </form>

    <h1>Results:</h1>
    <h2>GET Form Result:</h2>
    <p>text_get: <?php echo $_GET["text_get"]; ?></p>
    <h2>POST Form Result:</h2>
    <p>text_post: <?php echo $_POST["text_post"]; ?></p>
    <h2>POST Form with GET Result:</h2>
    <p>text_get2: <?php echo $_GET["text_get2"]; ?></p>
    <p>text_post2: <?php echo $_POST["text_post2"]; ?></p>
    <h2>File Upload:</h2>
    <p>file:
    <pre><?php if ( ! empty( $_FILES ) ) {
            echo print_r( $_FILES, true );
        } ?></pre>
    </p>
    <p></p>
    </body>
    </html><?php
// Very Bottom of your code:
// Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice
unset( $_SESSION["POST"] );

它只能避免重新提交$ _POST,而不是$ _GET。但这是我需要的行为。 重新提交问题不适用于文件上传!

答案 18 :(得分:0)

JavaScript

此方法非常简单,一旦提交表单,就会阻止弹出窗口在刷新时要求重新提交表单。只需将这行javascript代码放在文件的页脚处,然后看一下魔术。

Select replace(new_variable,',','','')
From dual;

答案 19 :(得分:0)

这种方法对我来说效果很好,我认为这是完成这项工作的最简单方法。

一般的想法是在提交表单后将用户重定向到其他页面,这将在页面刷新时停止重新提交表单。不过,如果您需要在提交表单后将用户保留在同一页面上,则可以通过多种方式进行操作,但是这里我将描述javascript方法。

JavaScript方法

此方法非常简单,一旦提交表单,就会阻止弹出窗口在刷新时要求重新提交表单。只需将这行javascript代码放在文件的页脚处,然后看一下魔术。

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

答案 20 :(得分:0)

对我有用的是:

 <form  action="?refresh=<?php echo createToken(3)?>">



 </form>

在您的表单中

{{1}}

答案 21 :(得分:0)

form.php示例展示了如何正确使用PRG(无论表单是否有效)。

  • 仅当表单有效且已执行操作时,它才会重定向到同一页面。
  • 重定向可防止表单刷新时重新提交表单。
  • 它使用会话不会丢失您希望在表单有效时显示的成功消息。
  • 有两个测试按钮:“有效提交”,“无效提交”。尝试两者并刷新页面。
<?php
session_start();

function doSelfRedirect()
{
  header('Location:'.$_SERVER['PHP_SELF']);
  exit;
}

function setFlashMessage($msg)
{
  $_SESSION['message'] = $msg;
}

function getFlashMessage()
{
  if (!empty($_SESSION['message'])) {
    $msg = $_SESSION['message'];
    unset($_SESSION['message']);
  } else {
    $msg = null;
  }

  return $msg;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  // Validation primitive example.
  if (empty($_POST['valid'])) {
    $formIsValid = false;
    setFlashMessage('Invalid form submit');
  } else {
    $formIsValid = true;
  }

  if ($formIsValid) {
    // Perform any actions here.
    // ...

    // Cool!
    setFlashMessage('Form is valid. Action performed.');

    // Prevent form resubmission.
    doSelfRedirect();
  }
}
?>
<h1>Hello form</h1>

<?php if ($msg = getFlashMessage()): ?>
  <div><?= $msg ?></div>
<?php endif; ?>

<form method="post">
  <input type="text" name="foo" value="bar"><br><br>
  <button type="submit" name="invalid" value="0">Invalid submit</button>
  <button type="submit" name="valid" value="1">Valid submit</button>
</form>

答案 22 :(得分:-1)

if (($_SERVER['REQUEST_METHOD'] == 'POST') and (isset($_SESSION['uniq']))){
    if($everything_fine){
        unset($_SESSION['uniq']);
    }
}
else{
    $_SESSION['uniq'] = uniqid();
}

答案 23 :(得分:-2)

为什么不直接使用$_POST['submit']变量作为逻辑语句来保存表单中的内容。您始终可以重定向到同一页面(如果他们刷新,当他们在浏览器中点击go back时,将不再设置提交帖子变量。只需确保您的提交按钮有{{1}和name的{​​{1}}。