2011-04-17 95 views
17

我認爲這個問題通常發生在Web應用程序上。但我會詳細解釋我的煩惱。避免因刷新頁面而提交的最佳方式

我想知道如何擺脫這種行爲,例如當我有這樣的代碼:

<? 
    if (isset($_POST['name'])) { 
     ... operation on database, like to insert $_POST['name'] in a table ... 
     echo "Operation Done"; 
     die(); 
    } 

?> 

<form action='page.php' method='post' name="myForm"> 
    <input type="text" maxlength="50" name="name" class="input400" /> 
    <input type="submit" name="Submit" /> 
</form> 

當我提交表單,我插入數據庫的數據,我收到消息Operation Done。如果我刷新頁面,數據將再次被分離。

我該如何避免這種情況?任何建議都會很好:)

回答

29

創建操作後不顯示響應;改爲在動作完成後重定向到另一個頁面。如果有人刷新,他們刷新您重定向到的GET請求頁面。

// submit 
// set success flash message (you are using a framework, right?) 
header('Location: /path/to/record'); 
exit; 
+7

這就是你應該始終做的。這個模式甚至有一個維基頁面:http://en.wikipedia.org/wiki/Post/Redirect/Get – 2011-04-17 00:13:16

+0

這是一個很好的解決方案,它通過使用一些框架(如Struts2或JSF,我已經很容易實現在過去做過)。事實上,我不知道在php上最好的戰略:) :) – markzzz 2011-04-17 00:14:03

+0

簡單,明顯,優雅等=) – Rudie 2011-04-17 00:15:31

22

在窗體顯示時在會話中設置一個隨機數,並且將該數字放在隱藏字段中。如果發佈的號碼和會話號碼匹配,則刪除會話,運行查詢;如果他們不這樣做,重新顯示錶格,並生成一個新的會話編號。這是XSRF令牌的基本理念,你可以閱讀更多關於他們,他們的安全在這裏用途:http://en.wikipedia.org/wiki/Cross-site_request_forgery

下面是一個例子:

<?php 
session_start(); 

if (isset($_POST['formid']) && isset($_SESSION['formid']) && $_POST["formid"] == $_SESSION["formid"]) 
{ 
    $_SESSION["formid"] = ''; 
    echo 'Process form'; 
} 
else 
{ 
    $_SESSION["formid"] = md5(rand(0,10000000)); 
?> 
    <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post"> 
    <input type="hidden" name="formid" value="<?php echo htmlspecialchars($_SESSION["formid"]); ?>" /> 
    <input type="submit" name="submit" /> 
</form> 
<?php } ?> 
+0

是的,這是另一個好主意! :) – markzzz 2011-04-17 00:22:30

+2

如果會話過期: if(!empty($ _ SESSION [「formid」])&& $ _POST [「formid」] == $ _SESSION [「formid」]) – Joefay 2016-07-30 03:55:41

+0

感謝Joefay,你是對的我應該在使用它之前,必須檢查會話中是否存在'formid'。我已經更新了我的回答 – Ben 2016-08-24 14:31:19

2

像這樣:

<?php 
if(isset($_POST['uniqid']) AND $_POST['uniqid'] == $_SESSION['uniqid']){ 
    // can't submit again 
} 
else{ 
    // submit! 
    $_SESSION['uniqid'] = $_POST['uniqid']; 
} 
?> 

<form action="page.php" method="post" name="myForm"> 
    <input type="hidden" name="uniqid" value="<?php echo uniqid();?>" /> 
    <!-- the rest of the fields here --> 
</form> 
+0

是否將所有發佈的數據添加到會話中? – 2014-04-14 22:41:14

0

我認爲它更簡單,

page.php

<?php 
    session_start(); 
    if (isset($_POST['name'])) { 
     ... operation on database, like to insert $_POST['name'] in a table ... 
     $_SESSION["message"]="Operation Done"; 
     header("Location:page.php"); 
     exit; 
    } 
?> 

<html> 
<body> 
<div style='some styles'> 
<?php 
//message here 
echo $_SESSION["message"]; 
?> 
</div> 
<form action='page.php' method='post'> 
<!--elements--> 
</form> 
</body> 
</html> 
0

我已經考慮過使用會話變量,正如其他人在這裏所建議的那樣,但當會話變量因爲超時而被清除時,可能會很痛苦。然後在我的應用程序中發現,爲我的目的有一個更簡單的解決方案。擺脫問題而不是檢查它。下面的解決方案通常適用於我,因爲我通常處理所有的PHP,然後將其轉儲到我的<html> ... </html >。

<?php 
    // PROCESS STUFF FOR YOUR PAGE HOWEVER YOU LIKE 

    // SAVE BACKUP COPIES OF _REQEUST _POST & _GET VARS IF NECESSARY FOR SOME REASON 
    $SAVED_REQUEST = $_REQEUST; 
    $SAVED_POST = $_POST; 
    $SAVED_GET = $_GET; 

    // FINALLY, IN YOUR LAST LINE ERASE THE PROBLEM VARIABLES... 
    $_REQUEST = $_POST = $_GET = NULL; 
?> 
<html> 
    <!-- PUT YOUR HTML HERE, ECHOING VARIABLES THAT WERE PROCESSES ABOVE --> 
</html> 

這隻會工作,因爲我通常使它儘可能分開我的PHP從我的HTML。顯然,它不能完全分開,但「分離」使得我的解決方案成爲可能,並且使得這兩個php更易於閱讀,因爲它全部在一個地方,並且它使得HTML更易於閱讀,因爲它不是很接近與代碼分離。 我想你理論上可以在頁面末尾添加以下內容。

<?php $_REQUEST = $_POST = $_GET = NULL; ?> 
0

因此,對於我所需要的,這是有效的。

基於上述所有解決方案,這允許我從一個表單轉到另一個表單,並轉換到n ^表單,同時防止當頁面是一個頁面時反覆地「保存」相同的確切數據刷新(以及之前發佈的數據到新頁面上)。

感謝那些發佈他們的解決方案,迅速讓我自己的解決方案。

<?php 
//Check if there was a post 
if ($_POST) { 
//Assuming there was a post, was it identical as the last time? 
    if (isset($_SESSION['pastData']) AND $_SESSION['pastData'] != $_POST) { 
//No, Save 
    } else { 
//Yes, Don't save 
    } 
} else { 
//Save 
} 
//Set the session to the most current post. 
$_session['pastData'] = $_POST; 
?> 
0

我們的web應用程序,我們設計的PHP的形式數工作。很難寫另一個頁面來獲取數據並提交給每一個表單。爲了避免重新提交,在每個表格中,我們創建了一個'random_check'字段,標記爲'Unique'。

在頁面加載時生成一個隨機值並將其存儲在文本字段中(顯然是隱藏的)。

在提交時,將此隨機文本值保存在表中的'random_check'字段中。如果重新提交查詢將通過錯誤,因爲它不能插入重複值。

在此之後可以顯示像

if (!$result) { 
     die('<script>alertify.alert("Error while saving data OR you are resubmitting the form.");</script>'); 
} 
0

無需重定向錯誤...

isset(! $_POST['name']); 

更換die();,設置isset到isset不等於$ _POST ['name'],所以當你刷新它時,它不會再添加到你的數據庫中,除非你再次點擊提交按鈕。

<? 
    if (isset($_POST['name'])) { 
     ... operation on database, like to insert $_POST['name'] in a table ... 
     echo "Operation Done"; 
     isset(! $_POST['name']); 
    } 

?> 

<form action='page.php' method='post' name="myForm"> 
    <input type="text" maxlength="50" name="name" class="input400" /> 
    <input type="submit" name="Submit" /> 
</form> 
+1

感謝分享。請務必在將來妥善設置答案格式,以幫助其他讀者!(http://stackoverflow.com/editing-help) – lbusett 2017-02-19 10:18:22

0

發生這種情況只是因爲刷新它會再次提交您的請求。

所以解決這個問題的想法,通過治癒它的根源。

我的意思是我們可以在窗體內設置一個會話變量並在更新時檢查它。

if($_SESSION["csrf_token"] == $_POST['csrf_token']) 
{ 
// submit data 
} 

//inside from 

$_SESSION["csrf_token"] = md5(rand(0,10000000)).time(); 

<input type="hidden" name="csrf_token" value=" 
htmlspecialchars($_SESSION["csrf_token"]);">