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

| 我有一个简单的表单,可将​​文本提交到SQL表。问题在于,用户提交文本后,他们可以刷新页面,并且无需再次填写表单即可再次提交数据。提交文本后,我可以将用户重定向到另一个页面,但是我希望用户停留在同一页面上。 我记得读过一些有关为每个用户提供唯一的会话ID,并将其与另一个值进行比较的信息,这些值解决了我遇到的问题,但我忘记了它在哪里。     
已邀请:
        使用发布/重定向/获取模式。 http://en.wikipedia.org/wiki/Post/Redirect/Get 在我的网站上,我将在cookie或会话中存储一条消息,在帖子后重定向,读取cookie /会话,然后清除该会话或cookie变量的值。     
        我还要指出,您可以使用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解决方案。     
        您确实应该使用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!
    }
    
        表单提交后,我使用此javascript行来阻止弹出窗口,要求刷新时重新提交表单。
if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}
只需将这一行放在文件的页脚处即可看到魔术     
        您可以通过会话变量阻止表单重新提交。 首先,您必须在文本框中设置
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>
之后,用文本框“ 8”的值检查“ 5” 像这样:
if(isset($_POST[\'submitbtn\']) && $_POST[\'randcheck\']==$_SESSION[\'rand\'])
{
    // Your code here
}
    
        处理表单后,您将重定向到另一个页面:
... process complete....
header(\'Location: thankyou.php\');
您还可以重定向到同一页面。 如果您正在执行诸如注释之类的操作并且希望用户停留在同一页面上,则可以使用Ajax来处理表单提交     
         使用标题并重定向页面。
header(\"Location:your_page.php\");
您可以重定向到相同页面或不同页面。 将$ _POST插入数据库后,取消设置。
unset($_POST);
    
        我找到了下一个解决方法。您可以通过处理
history
对象来处理
POST
请求后逃避重定向。 因此,您具有HTML表单:
<form method=POST action=\'/process.php\'>
 <input type=submit value=OK>
</form>
在服务器上处理此表单时,您不必像这样通过设置
Location
头将用户重定向到
/the/result/page
$cat process.php
<?php 
     process POST data here
     ... 
     header(\'Location: /the/result/page\');
     exit();
?>
处理ѭ13的数据后,您将渲染小
<script>
,结果
/the/result/page
<?php 
     process POST data here
     render the <script>         // see below
     render `/the/result/page`   // OK
?>
render20ѭ应该呈现:
<script>
    window.onload = function() {
        history.replaceState(\"\", \"\", \"/the/result/page\");
    }
</script>
结果是: 如您所见,表单数据被“ 13”修改为“ 26”脚本。 该脚本使用以下命令一次处理“ 13”个数据并立即渲染“ 16”: 没有重定向 刷新页面(F5)时没有re
POST
数据 在浏览器历史记录中导航到上一页/下一页时没有re
POST
UPD 作为另一个解决方案,我要求功能要求Mozilla FireFox团队允许用户设置
NextPage
标头,该标头的工作方式类似于
Location
标头,并使
post/redirect/get
模式过时。 简而言之。当服务器处理表格
POST
成功数据时: 设置
NextPage
报头而不是
Location
渲染处理
POST
表单数据的结果,因为它将以
post/redirect/get
模式呈现给
GET
请求 浏览器依次看到
NextPage
标头: 用
NextPage
值调整
window.location
当用户刷新页面时,浏览器将向
NextPage
协商
GET
请求,而不是re
POST
表单数据 我认为,如果实施,效果会很好,不是吗?
=)
    
        一种非常肯定的方法是在帖子中实现唯一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;
}
    
        使用表单数据后,只需将其重定向到同一页面即可。我试过了
header(\'location:yourpage.php\');
    
        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
}
    
        将其插入数据库后,调用unset()方法清除数据。 未设置($ _POST); 为防止插入刷新数据,请在插入记录后将页面重定向到相同页面或不同页面。 header(\'Location:\'。$ _ SERVER [\'PHP_SELF \']);     
基本上,您需要重定向到该页面之外,但是当您的Internet速度较慢时,它仍然可能会引起问题(从服务器端重定向标题) 基本方案示例: 单击提交按钮两次 解决方式 客户端 客户端单击后禁用提交按钮 如果您使用Jquery:Jquery.one PRG模式 服务器端 发送请求时使用基于区别的哈希时间戳/时间戳。 用户请求令牌。当主负载加载时,分配一个临时请求令牌,如果重复请求将被忽略。     
        如何防止未经重定向的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;
    }
}
?>
因此,每次提交表单时,都会生成一个新动作,将其存储在会话中并与后动作进行比较。 附:如果您使用的是Get表单,则可以轻松地使用GET更改所有POST,它也可以使用。     
        Java脚本 此方法非常简单,一旦提交表单,就会阻止弹出窗口在刷新时要求重新提交表单。只需将这行javascript代码放在文件的页脚处,然后看一下魔术。
<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>
    
        使用Keverw回答中的Post / Redirect / Get模式是一个好主意。但是,您无法停留在页面上(我想这就是您要的内容吗?)此外,有时可能会失败:   如果网络用户在初始提交完成之前刷新   由于服务器延迟,导致重复的HTTP POST请求   某些用户代理。 另一个选择是将文本存储到会话中,如下所示:
if($_SERVER[\'REQUEST_METHOD\'] != \'POST\')
{
  $_SESSION[\'writeSQL\'] = true;
}
else
{
  if(isset($_SESSION[\'writeSQL\']) && $_SESSION[\'writeSQL\'])
  {
    $_SESSION[\'writeSQL\'] = false;

    /* save $_POST values into SQL */
  }
}
    
        正如其他人所说,不可能不使用post / redirect / get。但是同时,在服务器端执行您想做的事情非常容易。 在POST页面中,您只需验证用户输入但不对其进行操作,而是将其复制到SESSION数组中。然后,您再次重定向回主提交页面。您的主要提交页面首先检查您正在使用的SESSION数组是否存在,如果存在,则将其复制到本地数组中并取消设置。从那里可以采取行动。 这样,您只需要一次完成所有主要工作即可实现您想要的工作。     
        之后,我在大型项目中寻找解决方案以防止重新提交。 该代码可与$ _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。但这是我需要的行为。 重新提交问题不适用于文件上传!     
        这种方法对我来说效果很好,我认为这是完成这项工作的最简单方法。 总体思路是在提交表单后将用户重定向到其他页面,这将在页面刷新时停止重新提交表单。不过,如果您需要在提交表单后将用户保留在同一页面上,则可以通过多种方式进行操作,但是这里我将描述javascript方法。 JavaScript方法 此方法非常简单,一旦提交表单,就会阻止弹出窗口在刷新时要求重新提交表单。只需将这行javascript代码放在文件的页脚处,然后看一下魔术。
<script>
if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}
</script>
        
if (($_SERVER[\'REQUEST_METHOD\'] == \'POST\') and (isset($_SESSION[\'uniq\']))){
    if($everything_fine){
        unset($_SESSION[\'uniq\']);
    }
}
else{
    $_SESSION[\'uniq\'] = uniqid();
}
    
        为什么不只是使用
$_POST[\'submit\']
变量作为逻辑语句来保存表格中的内容。您始终可以重定向到同一页面(如果它们刷新,并且在浏览器中单击
go back
时,将不再设置Submit post变量。只需确保您的Submit按钮的
name
id
submit
。     

要回复问题请先登录注册