当页面被刷新或后退按钮被点击时,如何防止表单重新提交

4
在我的表单中,我允许用户上传文件到数据库,并将它们发送到另一个页面submission_successful.php,显示"感谢您的提交"。但是我发现当我在提交成功的php文件上点击返回按钮时,它回到了表单,相同的信息仍在并可以重新提交。我想做的是,在点击返回按钮时终止代码或清除用户输入的所有内容。我找到了一些答案,比如使用缓存控制,但有些含糊不清,有些对我没有用。而且我不希望用户在成功页面时返回上传页面。所以我会创建两个按钮,一个是"注销",一个是"返回上传页面",如果他们点击返回按钮,它将崩溃。我想显示确认表单重新提交页面。在其他帖子中,他们实际上试图防止"确认表单重新提交",但出于安全考虑,我想要它。这是我的代码。

developerUpload.php

<?php

session_start();

if(array_key_exists("invalid", $_GET)){

    echo '<br><h3 style="color:red;">File(s) were already submitted! Please re-name file or select a different file...</h3>';
}

if(isset($_COOKIE['username'])){

    if($_SERVER['REQUEST_METHOD'] =="POST"){

        $price = addslashes(trim($_POST['price']));
        $description = addslashes(trim($_POST['description']));

        if(!empty($price) && !empty($description)){

            $userid = $_SESSION['id'];
            $username = $_SESSION['username'];
            echo '<br>'.$userid;
            $pack_id = rand();

            //Check file 1
            if($_FILES['file1']['error'] !== UPLOAD_ERR_OK){

                    $file1 = null;
            }else{

                $target1 = "devFiles/";
                $target_file1 = addslashes(trim($target1 . basename($_FILES["file1"]["name"])));
                $file1 = addslashes(trim($_FILES['file1']['tmp_name']));

            }

            //Check file 2
            if($_FILES['file2']['error'] !== UPLOAD_ERR_OK){

                    $file2 = null;
            }else{

                $target2 = "devFiles/";
                $target_file2 = addslashes(trim($target2 . basename($_FILES["file2"]["name"])));
                $file2 = addslashes(trim($_FILES['file2']['tmp_name']));

            }

            //Check file 3
            if($_FILES['file3']['error'] !== UPLOAD_ERR_OK){

                    $file3 = null;
            }else{

                $target3 = "devFiles/";
                $target_file3 = addslashes(trim($target3 . basename($_FILES["file3"]["name"])));
                $file3 = addslashes(trim($_FILES['file3']['tmp_name']));

            }

            //Check file 4
            if($_FILES['file4']['error'] !== UPLOAD_ERR_OK){

                    $file4 = null;
            }else{

                $target4 = "devFiles/";
                $target_file4 = addslashes(trim($target4 . basename($_FILES["file4"]["name"])));
                $file4 = addslashes(trim($_FILES['file4']['tmp_name']));

            }

            //Check file 5
            if($_FILES['file5']['error'] !== UPLOAD_ERR_OK){

                    $file5 = null;
            }else{

                $target5 = "devFiles/";
                $target_file5 = addslashes(trim($target5 . basename($_FILES["file5"]["name"])));
                $file5 = addslashes(trim($_FILES['file5']['tmp_name']));

            }

            //Check video
            if($_FILES['video']['error'] !== UPLOAD_ERR_OK){

                $video = null;
                $videoName = null;
            }else{

                $target = "devFiles/";
                $target_file = addslashes(trim($target . basename($_FILES["video"]["name"])));
                $video = addslashes(trim($_FILES['video']['tmp_name']));
                $videoName = addslashes(trim($_FILES['video']['name']));

            }

            if(file_exists($target_file1) 
               or file_exists($target_file2) 
               or file_exists($target_file3)
               or file_exists($target_file4) 
               or file_exists($target_file5) 
               or file_exists($target_file)){

                header("Location: developerUpload.php?invalid");
                exit;

            }

            if(move_uploaded_file($_FILES["file1"]["tmp_name"], $target_file1) 
               && move_uploaded_file($_FILES["file2"]["tmp_name"], $target_file2)
               && move_uploaded_file($_FILES["file3"]["tmp_name"], $target_file3)
               && move_uploaded_file($_FILES["file4"]["tmp_name"], $target_file4)
               && move_uploaded_file($_FILES["file5"]["tmp_name"], $target_file5)
               && move_uploaded_file($_FILES["video"]["tmp_name"], $target_file)){

                try{

                    // new php data object 
                    $handler = new PDO('mysql:host=127.0.0.1;dbname=magicsever', 'root', '');
                    //ATTR_ERRMODE set to exception
                    $handler->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

                }catch(PDOException $e){
                    die("There was an error connecting to the database");   

                }

                header("Location: submission_successful.php?");
                die();
            }



        }else{

            echo '<br><h1 style="color:red;">VALUES MISSING!</h1>';

        }
    }
}else {

    header("Location: developerLogin.php");
}



?>

submission_successful.php

<?php
session_start();

    if(array_key_exists("invalid", $_GET)){

        header("Location: developerUpload.php?invalid");

    }
    if(isset($_COOKIE['username'])){
        echo '<br><h1 style="color:red; text_align:center;">Thank You for Submitting!</h1>';

    }else{

        header("Location: developerLogin.php");
    }

?>

1
你最好使用AJAX。这样,你就不需要使用PHP的header函数了。你只需通过动态div显示成功或错误消息。 - Rotimi
AJAX是您用来获取“确认表单重新提交”页面的工具吗? - Jagr
可能是防止表单重新提交的重复问题。 - Louys Patrice Bessette
你甚至可以在不进行重定向的情况下防止这种情况。请看这里 - Eugen Konkov
可能是重复的问题,参考如何在页面刷新(F5 / CTRL+R)时防止表单重新提交 - Eugen Konkov
4个回答

3
我花了几天时间搜索,最终找到了一些有用的信息。如果您使用HTML命令,则在用户返回时将删除用户输入的任何内容。因为我的问题是当用户被重定向后返回时,他们的信息仍然存在,但如果您使用

命令,则可以解决这个问题。
<form method="post" enctype="multipart/form-data" autocomplete="off">

它会移除所有内容,因此在某种程度上有所帮助。用户仍然可以返回到之前的页面,但至少现在他们无法重新提交数据。


2

不确定您是否可以检查数据库中的值是否存在两次(从而防止多次提交),但您可以阻止用户过于频繁地提交表单。创建一个时间戳,保存在第一次提交后,如果第二次重新提交的时间戳与第一次提交的时间戳相差不远,您可以尝试类似于(您正在过于频繁地提交)的东西,或者您可以使用Ajax,或者这个https://es.m.wikipedia.org/wiki/Post/Redirect/Get


我喜欢你的想法,但主要问题是当我将它们发送到成功页面时,我不希望它们返回到上传页面。我将创建两个按钮,一个用于注销,另一个用于转到上传页面。但是,如果没有会话,我无法实现这一点,这就是我卡住的地方。 - Jagr
好的,你无法禁用返回功能。你可以添加一个警告消息。https://dev59.com/q2ct5IYBdhLWcg3wD5WU - Klajdi
但是我看到很多网站在提交表单或申请后返回时会出现“确认表单重新提交”的提示。 - Jagr
请清空表单中的所有字段,当用户使用浏览器后退按钮时。您所说的只是针对重新加载,我想,否则请查看我的先前回复,在那里您可以在用户单击后退按钮时添加消息。 - Klajdi
你的回答帮助我想到了一些东西,以帮助回答这个问题:D。非常感谢。 - Jagr

0

使用会话变量就像这样

$_SESSION["post_id"] = "";
if($_POST) {
    if($_POST["post_id"] != $_SESSION["post_id"]) {
        $_SESSION["post_id"] = $_POST["post_id"];
        // do database submission here
    }
}

这将设置一个会话变量,如果他们重新提交表单,它不会重复发布数据。


你从哪里得到了 "$_POST['post_id']"? - Jagr
创建一个名为 post_id 的隐藏字段,并在其中生成一个随机数或每次刷新表单时更改的10-20个字符的字符串。这是您确定是否已提交的检查。我没有在答案中包含它,因为我不确定表单结构等内容。 - Kaboom
这段代码是放在我的程序开头还是在他们提交之后? - Jagr
会话(session)位于代码的开头,其他部分是他们在发布(posting)数据的地方,而HTML字段则放在您的表单(form)所在的位置。 - Kaboom
我已经尝试过了,但是没有起作用。您能否直接在我的代码中更新一下,这样我就可以看到您所说的内容了吗?非常感谢。 - Jagr
你在吗?我正在尝试,但是不知道出了什么问题 D: - Jagr

0
如果还有人需要,以下答案对我有效: 我还想指出,您可以使用JavaScript方法window.history.replaceState来防止在刷新和返回按钮上重新提交。
<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>

原始答案在此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接