2011-04-17 21 views
17

Tôi nghĩ rằng vấn đề này thường xảy ra trên một ứng dụng web. Nhưng tôi sẽ giải thích chi tiết những rắc rối của tôi.Cách tốt nhất để tránh việc gửi do làm mới trang

Tôi muốn biết làm thế nào để thoát khỏi hành vi này, ví dụ như khi tôi đã là một mã như thế này:

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

Khi tôi gửi biểu mẫu, tôi chèn các dữ liệu trên cơ sở dữ liệu, và Tôi nhận được thông báo Thao tác Hoàn tất. Hơn nữa, nếu tôi làm mới trang, dữ liệu sẽ được in lại.

Làm cách nào để tránh tình huống này? Mọi đề xuất sẽ tốt :)

Trả lời

29

Không hiển thị phản hồi sau khi tạo hành động của bạn; chuyển hướng đến một trang khác sau khi tác vụ hoàn tất. Nếu ai đó làm mới, họ đang làm mới trang được yêu cầu GET mà bạn đã chuyển hướng đến.

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

Đây là những gì bạn nên làm. Thậm chí còn có một trang wiki cho mẫu này: http://en.wikipedia.org/wiki/Post/Redirect/Get –

+0

Đây là một giải pháp tốt và dễ thực hiện bằng cách sử dụng một số Khung (như Struts2 hoặc JSF, tôi đã thực hiện nó trong quá khứ). Trong thực tế, tôi không biết sstrategy tốt nhất trên php :) – markzzz

+0

Đơn giản, rõ ràng, thanh lịch vv =) – Rudie

22

Đặt số ngẫu nhiên trong phiên khi biểu mẫu được hiển thị và cũng đặt số đó vào trường bị ẩn. Nếu số đã đăng và số phiên khớp nhau, hãy xóa phiên, chạy truy vấn; nếu không, hãy hiển thị lại biểu mẫu và tạo số phiên mới. Đây là ý tưởng cơ bản của thẻ XSRF, bạn có thể đọc thêm về họ, và sử dụng của họ đối với an ninh ở đây: http://en.wikipedia.org/wiki/Cross-site_request_forgery

Dưới đây là một ví dụ:

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

Vâng, một ý tưởng hay nữa! :) – markzzz

+2

Điều kiện nếu phiên hết hạn: nếu (! Empty ($ _ SESSION ["formid"]) && $ _POST ["formid"] == $ _SESSION ["formid"]) – Joefay

+0

Cảm ơn Joefay, bạn nói đúng Tôi nên chắc chắn kiểm tra rằng 'formid' vẫn tồn tại trong phiên trước khi sử dụng nó. Tôi đã cập nhật câu trả lời của mình – Ben

2

Như thế này:

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

Có phải tất cả dữ liệu bài đăng đã được thêm vào phiên không? –

0

Tôi nghĩ đơn giản hơn,

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

Tôi đã xem xét sử dụng các biến phiên như những người khác đã đề xuất ở đây, nhưng nó có thể là một nỗi đau khi biến phiên bị xóa vì hết thời gian chờ. Sau đó, nó xảy ra với tôi trong ứng dụng của tôi cho mục đích của tôi có một giải pháp đơn giản hơn nhiều. Loại bỏ vấn đề thay vì kiểm tra nó. Các giải pháp dưới đây thường làm việc cho tôi bởi vì tôi thường xử lý tất cả các php của tôi trước khi bán nó vào của tôi <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> 

Điều này chỉ hoạt động vì tôi thường làm cho nó tách biệt php của tôi khỏi càng nhiều càng tốt. Rõ ràng, nó không thể tách rời hoàn toàn, nhưng "tách" làm cho giải pháp của tôi trở thành một khả năng và làm cho cả php dễ đọc hơn bởi vì tất cả đều ở một nơi, và nó làm cho HTML dễ đọc hơn vì nó gần như không như chia nhỏ với mã. Tôi đoán bạn có thể trong lý thuyết chỉ cần đặt sau ở cuối trang của bạn là tốt.

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

Vì vậy, đối với những gì tôi cần đây là những gì hiệu quả.

Dựa trên tất cả các giải pháp trên, điều này cho phép tôi chuyển từ biểu mẫu này sang biểu mẫu khác và sang dạng n ^, đồng thời ngăn không cho cùng một lần "lưu" cùng một dữ liệu chính xác khi trang làm mới (và dữ liệu bài từ trước khi lingers vào trang mới).

Nhờ những người đã đăng giải pháp của họ, điều này đã nhanh chóng dẫn tôi đến giải pháp của riêng tôi.

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

Chúng tôi làm việc trên các ứng dụng web nơi chúng tôi thiết kế số biểu mẫu php. Đó là heck để viết một trang khác để có được dữ liệu và gửi nó cho mỗi và mọi hình thức. Để tránh gửi lại, trong mỗi bảng, chúng tôi đã tạo trường 'random_check' được đánh dấu là 'Duy nhất'.

Khi tải trang tạo ra một giá trị ngẫu nhiên và lưu trữ nó trong trường văn bản (rõ ràng là bị ẩn).

TRÊN SUBMIT lưu giá trị văn bản ngẫu nhiên này trong trường 'random_check' trong bảng của bạn. Trong trường hợp truy vấn gửi lại sẽ thông qua lỗi vì nó không thể chèn giá trị trùng lặp.

Sau đó bạn có thể hiển thị các lỗi như

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

Không cần phải chuyển hướng ...

thay die(); với

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

, thiết lập isset để isset không bằng $ _POST ['name'], do đó, khi bạn làm mới nó, nó sẽ không thêm nữa vào cơ sở dữ liệu của bạn, trừ khi bạn bấm vào nút gửi một lần nữa.

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

Cảm ơn bạn đã chia sẻ. Hãy chắc chắn trong tương lai để định dạng đúng câu trả lời của bạn để giúp người đọc khác!(http://stackoverflow.com/editing-help) – lbusett

0

Điều này xảy ra vì chỉ đơn giản là làm mới nó sẽ gửi yêu cầu của bạn một lần nữa.

Vì vậy, ý tưởng để giải quyết vấn đề này bằng cách chữa gốc rễ của nguyên nhân.

Tôi có nghĩa là chúng tôi có thể thiết lập một biến phiên trong biểu mẫu và kiểm tra nó khi cập nhật.

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"]);"> 
Các vấn đề liên quan