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

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


当前回答

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

$everything_fine是表单验证的布尔结果。如果表单没有验证,那么通常会再次显示,并提示需要更正的内容,以便用户可以再次发送。因此,如果需要更正的形式,也会再次创建$_SESSION['uniq']

其他回答

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

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

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

如果您正在做一些类似评论的事情,并且希望用户停留在相同的页面上,您可以使用Ajax来处理表单提交

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

$everything_fine是表单验证的布尔结果。如果表单没有验证,那么通常会再次显示,并提示需要更正的内容,以便用户可以再次发送。因此,如果需要更正的形式,也会再次创建$_SESSION['uniq']

这个form.php示例展示了如何正确地使用PRG(当表单有效或无效时)。

它只在表单有效且执行操作时重定向到相同的页面。 重定向可以防止表单在页面刷新时被重新提交。 当表单有效时,它使用session来避免丢失想要显示的成功消息。 有两个测试按钮:“有效提交”,“无效提交”。两者都试一下,然后刷新页面。

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

我寻找解决方案,以防止在一个巨大的项目之后再次提交。 代码高度工作与$_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的重新提交。但这是我需要的行为。 重新提交的问题不工作的文件上传!

我找到了下一个变通办法。您可以通过操作历史对象在处理POST请求后转义重定向。

你有一个HTML表单

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

当你在你的服务器上处理这个表单时,你不是重定向用户到/the/result/页面,而是像这样设置Location头:

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

处理post数据后,呈现小的<脚本>和result/ the/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>

结果是:

如你所见,表单数据被post到process.php脚本。 这个脚本处理post数据并立即渲染/the/result/page:

没有重定向 当你刷新页面时没有rePOST数据(F5) 当你通过浏览器历史导航到上一页/下一页时,没有rePOST

UPD

作为另一个解决方案,我要求Mozilla FireFox团队允许用户设置NextPage头,它将像Location头一样工作,使post/redirect/get模式过时。

简而言之。当服务器处理表单POST数据成功时:

设置NextPage头而不是位置 呈现POST表单数据处理的结果,就像在POST /redirect/ GET模式中呈现GET请求一样

浏览器依次看到NextPage头:

调整窗口。位置与NextPage值 当用户刷新页面时,浏览器将协商GET请求NextPage而不是rePOST表单数据

我认为这将是极好的,如果实施,不是吗?=)