【问题标题】:Prevent Form resubmission upon hitting back button点击返回按钮时防止重新提交表单
【发布时间】:2013-02-20 00:40:02
【问题描述】:

我在这里和其他地方搜索了很多帖子,但似乎找不到解决我的问题的方法。 我有一个显示数据库条目的页面:database.php。可以使用表单过滤这些条目。当我过滤它们并仅显示我感兴趣的那些时,我可以单击一个条目(作为链接),将我带到该条目页面(通过 php GET)。当我在该条目页面(即“view.php?id=1”)并点击后退按钮(返回 database.php)时,过滤器表单需要确认表单重新提交。有什么办法可以预防吗?

这里有一些(简化的)代码示例:

数据库.php:

<form>
    <select>
        <option>1</option>
        <option>2
        <option>
    </select>
    <input type="submit" name="apply_filter" />
</form>
<?php
if ( isset( $_POST[ "apply_filter" ] ) ) { // display filtered entries
    $filter = $_POST[ "filter" ];
    $q = "Select * from table where col = '" . $filter . "'";
    $r = mysql_query( $q );
} else { // display all entries
    $q = "Select * from table";
    $r = mysql_query( $q );
}
while ( $rec = mysql_fetch_assoc( $r ) ) {
    echo "<a href='view.php?id=" . $rec[ "id" ] . "'>" . $rec[ "name" ] . "</a><br />"; // this is where the link to the view.php page is...
}
?>

现在如前所述,如果我点击链接,它会将我带到“view.php?id=whatever”。在该页面上,我只是从 url 中获取 ID 以显示该单个条目:

view.php:

<?php
$id = $_GET[ "id" ];
$q = "Select * from table where id = '" . $id . "'";
$r = mysql_query( $q );
while (  ) {
    // display entry
}

?>

如果我现在点击返回按钮,database.php 上的表单(用于过滤数据库结果的表单)需要确认重新提交。这不仅很烦人,对我来说也没用。

我该如何解决这个问题?我希望我的问题的代码示例和解释是足够的。如果不让我知道,我会尝试指定。

【问题讨论】:

标签: php forms get refresh back


【解决方案1】:

我知道这个问题很老,但我自己也有这个问题,我发现有两行有效:

header("Cache-Control: no cache");
session_cache_limiter("private_no_expire");

【讨论】:

  • 我们必须在哪里添加这些行?
  • @user3663 我在所有页面上都使用了它,但可能只适用于界面页面,例如view.php 关于 OP 的问题。
  • 我在使用 session_cach_limiter 时出错。我也在使用 session_start 。当我不使用 session_cache_limiter("private_no_expire"); 时它似乎有效并使用 session_start 和 header("Cache-Control: no cache");在包含提交按钮的页面上使用它。
【解决方案2】:

我知道有两种方法可以做到这一点。简单的方法和困难的方法。

无论如何,当您处理基于状态的页面(使用$_SESSION)时,您应该这样做以保持您的页面“活动”并在您的控制之下,防止缓存所有页面,例如这个:

<?php
//Set no caching
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
header("Cache-Control: no-store, no-cache, must-revalidate"); 
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
?>

困难的方法是生成一个 id 并将其作为隐藏输入或 &amp;_SESSION cookie 存储在页面上的某个位置。然后在服务器上存储与$_SESSION 相同的ID。如果它们不匹配,则一系列预编程的 if else 类型语句会导致页面重新提交时不会发生任何事情(当您单击返回时,它会尝试执行此操作)。

如果表单提交成功,简单的方法是简单地将用户重定向回表单提交页面,如下所示:

header('Location: http://www.mydomain.com/redirect.php');

我希望这会有所帮助!

【讨论】:

  • 我不理解“简单的方法”。如果用户在“查看”页面上,则无法重定向他,因为我不知道他想看多长时间该页面上的信息。我包含了一个重定向按钮,它将用户带回表单页面;这不是问题。只有当用户按下返回以返回整个数据库时,问题才会出现。
  • 您将从表单提交到 Database.php,然后收集所有信息并在该脚本末尾使用 $_GET 样式 URL 重定向用户 header('Location: http://www.mydomain.com/view.php?databse=this&amp;somethingelse=that');
【解决方案3】:

可能有帮助的一件事是让您的过滤器表单使用GET 方法而不是POST

浏览器通常会阻止POST 输入自动重新提交,这是在使用GET 输入时它们不会做的事情。此外,这将允许用户使用过滤器链接到您的页面。

【讨论】:

  • 此解决方案最适合搜索/过滤表单。对于创建/更新表单重定向是最好的。
【解决方案4】:
header("Cache-Control: no cache");

session_cache_limiter("private_no_expire");

注意:在使用你从表单提交的post数据之后,这两行应该在function的末尾使用。所以,当我们回到重定向页面时,它不会要求你重新提交页。这会起作用。

【讨论】:

    【解决方案5】:

    我使用How do I detect if a user has got to a page using the back button? 的答案来检测访问是否是由浏览器的后退按钮单击触发的,如果是这种情况,我使用 JavaScript 重新加载页面。当页面重新加载时,我的代码已经处理了相应的验证,以确保表单永远不会提交两次。在我的案例中,重要的部分是在单击浏览器的后退按钮后重新访问表单时强制页面重新加载。这是我要应用此验证的 URL 中的代码:

    <script type="text/javascript">
        if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
            location.reload();
        }
    </script>
    

    【讨论】:

      【解决方案6】:

      如果/当页面重新加载时,另一种解决方案也可以使用 $_SESSION 检查帖子的原创性。简而言之,检查一个唯一的或随机的字符串。

      在表单中,添加一个使用 rand() 或 microtime() 设置值的输入元素:

      <input type="hidden" name="formToken" value="<?php echo microtime();?>"/>
      

      然后将 PHP 函数包装在 if 块中,对表单数据进行验证和解析:

      if(!isset($_SESSION['formToken']) || $_POST['formToken'] !== $_SESSION['formToken'])){
             $_SESSION['formToken'] = $_POST['formToken'];
            /*continue form processing */
      }
      

      【讨论】:

        【解决方案7】:

        对我有用的解决方案是

        $(document).ready( function() {
        //prevent form submit on refresh or resubmit with back button
        if ( window.history.replaceState ) window.history.replaceState( null, null, window.location.href );
        }
        

        【讨论】:

          【解决方案8】:

          您需要从浏览器历史记录中删除包含POST 数据的请求

          history.replaceState("", "", "/the/result/page")
          

          this回答

          您也可以遵循Post/Redirect/Get 模式。

          【讨论】:

            猜你喜欢
            • 2011-12-06
            • 2018-02-21
            • 2019-06-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-12-13
            • 2014-08-15
            相关资源
            最近更新 更多