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

Php 如何在刷新页面时防止表单重新提交(F5/CTRL+;R),php,html,forms,post,form-submit,Php,Html,Forms,Post,Form Submit,我有一个简单的表单将文本提交到我的SQL表。问题是,在用户提交文本后,他们可以刷新页面并再次提交数据,而无需再次填写表单。提交文本后,我可以将用户重定向到另一个页面,但我希望用户保持在同一页面上 我记得读过一些关于给每个用户一个唯一的会话id并将其与另一个值进行比较的文章,该值解决了我遇到的问题,但我忘记了它在哪里。处理表单时,您会重定向到另一个页面: ... process complete.... header('Location: thankyou.php'); 您还可以重定向到同一页面

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


我记得读过一些关于给每个用户一个唯一的会话id并将其与另一个值进行比较的文章,该值解决了我遇到的问题,但我忘记了它在哪里。

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

... process complete....
header('Location: thankyou.php');
您还可以重定向到同一页面


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

使用Post/Redirect/Get模式


使用我的网站,我将在cookie或会话中存储消息,在发布后重定向,读取cookie/会话,然后清除该会话或cookie变量的值。

为什么不将
$\u post['submit']
变量用作逻辑语句来保存表单中的内容呢。您始终可以重定向到同一页面(以防它们刷新,并且当它们在浏览器中点击
返回
时,将不再设置submit post变量。只需确保您的submit按钮具有
名称
id
提交

  • 使用页眉并重定向页面

    标题(“Location:your_page.php”);
    您可以重定向到同一页面或不同页面

  • 将$\u POST插入数据库后取消设置

    unset($\u POST);


  • 您确实应该使用Post Redirect Get模式来处理此问题,但如果您最终遇到PRG不可行的情况(例如,表单本身在包含中,阻止重定向),您可以散列一些请求参数,以根据内容生成字符串,然后检查您是否已经发送了该字符串

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

    在使用表单数据后,只需将其重定向到同一页面,它就可以工作了。我已经尝试过了

    header('location:yourpage.php');
    

    一个非常可靠的方法是在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;
    }
    
    if($\u会话['post\u id']!=$\u post['post\u id']))
    {
    $\u会话['post\u id']=$\u post['post\u id'];
    //发邮件
    }否则{
    //正常显示
    }
    函数createPassword($length)
    {
    $chars=“abcdefghijkmnopqrstuvxyzo23456789”;
    srand((双)微时间()*1000000);
    $i=0;
    $pass='';
    
    而($i是Moob帖子的精练版本。创建帖子的散列,将其保存为会话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()方法清除数据

    unset($\u POST);

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


    标题('Location:'.$\u SERVER['PHP\u SELF']);

    基本上,您需要重定向出该页面,但当您的internet速度较慢时,仍然会出现问题(从服务器端重定向标题)

    基本场景示例:

    点击提交按钮两次 解决方法

    • 客户端

      • 客户端单击“提交”按钮后禁用该按钮
      • 如果您使用Jquery:
    • 服务器端

      • 发送请求时使用基于区分的哈希时间戳/时间戳
      • Userequest令牌。当主服务器加载时,将临时请求分配给令牌,如果重复,则忽略该请求

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

    如果web用户在首次提交完成之前刷新 由于服务器延迟,导致中出现重复的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 */
      }
    }
    
    if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
    {
        // Your code here
    }
    
    if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
      // do your stuff, save data into database, etc
    }
    
    $cat process.php
    <?php 
         process POST data here
         ... 
         header('Location: /the/result/page');
         exit();
    ?>
    

    您可以通过会话变量阻止表单重新提交

    首先,您必须在文本框中设置
    rand()
    ,并在表单页面上设置
    $\u会话['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\u start()

    我还想指出,您可以使用javascript方法
    window.history.replaceState
    来防止刷新时重新提交和返回按钮

    <script>
        if ( window.history.replaceState ) {
            window.history.replaceState( null, null, window.location.href );
        }
    </script>
    
    
    如果(window.history.replaceState){
    window.history.replaceState(null,null,window.location.href);
    }
    
    此处的概念证明:


    我仍然建议使用Post/Redirect/Get方法,但这是一种新颖的JS解决方案。

    如何防止php表单在没有重定向的情况下重新提交。如果您使用$\u会话(会话启动后)和$\u Post表单,您可以执行以下操作:

    if($_SERVER['REQUEST_METHOD'] != 'POST')
    {
      $_SESSION['writeSQL'] = true;
    }
    else
    {
      if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
      {
        $_SESSION['writeSQL'] = false;
    
        /* save $_POST values into SQL */
      }
    }
    
    if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
    {
        // Your code here
    }
    
    if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
      // do your stuff, save data into database, etc
    }
    
    $cat process.php
    <?php 
         process POST data here
         ... 
         header('Location: /the/result/page');
         exit();
    ?>
    
    在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;
        }
    }
    ?>
    

    我找到了下一个解决方法。在处理
    POST
    请求后,您可以通过操纵对象来逃避重定向

    因此,您有了HTML表单:

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

    处理
    POST
    ed数据后,您将呈现较小的
    和结果
    /result/page

    <?php 
         process POST data here
         render the <script>         // see below
         render `/the/result/page`   // OK
    ?>
    
    
    
    您应该呈现的

    <script>
        window.onload = function() {
            history.replaceState("", "", "/the/result/page");
        }
    </script>
    
    
    window.onload=函数(){
    replaceState(“,”,“/the/result/page”);
    }
    
    结果是:

    如您所见,表单数据是
    POST
    ed到
    process.php
    script。
    此脚本处理
    POST
    ed数据并立即呈现
    /result/page
    ,包括:

  • 无重定向
  • 刷新页面(F5)时无re
    POST
    数据
  • 在浏览器历史记录中导航到上一页/下一页时,无re
    POST
  • UPD

    if ( !refreshed()) { //Your Submit Here if (isset( $_GET['refresh'])) { setcookie("refresh",$_GET['refresh'], time() + (86400 * 5), "/"); } } } function refreshed() { if (isset($_GET['refresh'])) { $token = $_GET['refresh']; if (isset($_COOKIE['refresh'])) { if ($_COOKIE['refresh'] != $token) { return false; } else { return true; } } else { return false; } } else { return false; } } function createToken($length) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } return $randomString; } ?>
     <form  action="?refresh=<?php echo createToken(3)?>">
    
    
    
     </form>
    
    <?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>