2010-01-25 45 views
29

Đôi khi người dùng có thể nhấn Enter hai lần và bài đăng được chèn hai lần.Làm cách nào để ngăn chặn nhiều lần chèn khi gửi biểu mẫu bằng PHP?

Có giải pháp nào để ngăn điều này ngoài kiểm tra xem đã có bài đăng có cùng số titlecontent không?

+0

Bạn có thể tắt sự kiện được kích hoạt khi nhấn enter không? –

+12

Smack chúng mỗi khi họ làm. Cuối cùng, họ sẽ tìm hiểu :) – Gordon

+4

Tôi sẽ khuyên bạn nên sử dụng các phím Biểu mẫu. Hãy xem xét điều đó tại đây: http: //net.tutsplus.com/tutorials/php/secure-your-forms-with-form-keys/ –

Trả lời

1

Tắt nút gửi bằng Javascript khi biểu mẫu được gửi (onsubmit).

Lưu ý rằng nếu người dùng đã tắt Javascript, họ vẫn có thể gửi hai lần. Việc điều này có xảy ra thường xuyên đủ để biện minh cho việc kiểm tra mã của bạn (như bạn đã đề xuất trong câu hỏi của bạn) tùy thuộc vào bạn hay không.

0

vô hiệu hóa nút gửi khi người dùng đã gửi biểu mẫu, sử dụng JavaScript. Đó là những gì, ví dụ, StackOverflow sử dụng khi bạn trả lời một câu hỏi.

Ví dụ

<input type="submit" onclick="this.disabled=true" /> 
0

Sử dụng Javascript để vô hiệu hóa các nút ngay sau khi nó được nhấp.

onclick="this.disabled=true;forms[0].submit();" 
+1

Trình xử lý 'onclick' sẽ không chạy nếu biểu mẫu được gửi qua đột quỵ bàn phím ví dụ: người dùng nhấn phím enter trong khi tập trung vào nút gửi. Sử dụng tốt hơn 'onsubmit' giống như một trong những áp phích khác được đề xuất. – Asaph

+1

@Asaph: Tôi thực sự thích ý tưởng mã thông báo @Mats được đề xuất. Nhưng nếu ở bên phía khách hàng, thực sự có lẽ sẽ tốt hơn nếu có phương pháp kết hợp cả nhấp chuột và gửi. 2 lần nhấp chuột có thể đăng ký trong IE trước khi tiện ích thực sự kích hoạt. Ngu ngốc, nhưng tôi đã nhìn thấy nó. –

0

Nhấn nộp hai lần khá hiếm khi dẫn đến chèn nhiều, nhưng nếu bạn muốn có một sollution dead-đơn giản, sử dụng

onsubmit="document.getElementById('submit').disabled = true" 

trong thẻ biểu mẫu, với điều kiện bạn đưa ra nộp mình nút id="submit"

30

Sử dụng mã thông báo duy nhất với bài đăng để mỗi bài đăng/đăng lại chỉ được xử lý một lần.

Vô hiệu hóa nút gửi không phải là giải pháp tốt vì mọi người có thể tắt javascript hoặc thực hiện những điều kỳ lạ khác. Xác nhận phía máy khách là một khởi đầu tốt, nhưng phải luôn luôn được sao lưu với xử lý phía máy chủ.

+2

+1 - đây là phương pháp phổ biến nhất và không có phụ thuộc phía máy khách. Tại sao điều này không được chấp nhận là câu trả lời? – Russell

+0

@Steve Không đúng sự thật. Các POST không được mong đợi là không có giá trị. – kaqqao

46

Có một số giải pháp cho vấn đề này:

  1. Sử dụng Javascript để vô hiệu hóa các hình thức của nút gửi khi nó được đăng tải. Nhược điểm với điều này là điều này là TUYỆT ĐỐI không phải là một cách dễ dàng. Rất dễ dàng để gửi biểu mẫu mà không thực sự nhấp vào nút và điều này cũng sẽ không hoạt động đối với người dùng đã tắt JavaScript. Tôi chắc chắn sẽ không đề xuất phương pháp này.

    Ví dụ:

    <script language="javascript"> 
    <!-- 
        function disableSubmitButton() { 
         // you may fill in the blanks :) 
        } 
    --> 
    </script> 
    <form action="foo.php" method="post"> 
        <input type="text" name="bar" /> 
        <input type="submit" value="Save" onclick="disableSubmitButton();"> 
    </form> 
    
  2. Sử dụng PHP sessions để thiết lập một biến phiên (ví dụ: $ _SESSION [ 'posttimer']) để dấu thời gian hiện hành về đường bưu điện. Trước khi thực sự xử lý biểu mẫu trong PHP, hãy kiểm tra xem biến $ _SESSION ['posttimer'] tồn tại chưa và kiểm tra một dấu thời gian nhất định (IE: 2 giây). Bằng cách này, bạn có thể dễ dàng lọc ra các lần gửi đôi.

    Ví dụ:

    // form.html 
    <form action="foo.php" method="post"> 
        <input type="text" name="bar" /> 
        <input type="submit" value="Save"> 
    </form> 
    
    // foo.php 
    if (isset($_POST) && !empty($_POST)) 
    { 
        if (isset($_SESSION['posttimer'])) 
        { 
         if ((time() - $_SESSION['posttimer']) <= 2) 
         { 
          // less then 2 seconds since last post 
         } 
         else 
         { 
          // more than 2 seconds since last post 
         } 
        } 
        $_SESSION['posttimer'] = time(); 
    } 
    
  3. Bao gồm một thẻ duy nhất trên mỗi POST. Trong trường hợp này, bạn cũng sẽ đặt biến phiên cho mã thông báo bạn muốn bao gồm và sau đó hiển thị mã thông báo trong biểu mẫu. Khi biểu mẫu được gửi, bạn tạo lại mã thông báo. Khi mã thông báo đã gửi không khớp với mã thông báo trong phiên của bạn, biểu mẫu đã được gửi lại và phải được khai báo là không hợp lệ.

    Ví dụ:

    // form.php 
    <?php 
        // obviously this can be anything you want, as long as it is unique 
        $_SESSION['token'] = md5(session_id() . time()); 
    ?> 
    <form action="foo.php" method="post"> 
        <input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>" /> 
        <input type="text" name="bar" /> 
        <input type="submit" value="Save" /> 
    </form> 
    
    // foo.php 
    if (isset($_SESSION['token'])) 
    { 
        if (isset($_POST['token'])) 
        { 
         if ($_POST['token'] != $_SESSION['token']) 
         { 
          // double submit 
         } 
        } 
    } 
    
+3

+1 Câu trả lời hay, nhưng tôi muốn chỉnh sửa để đề xuất của bạn xuất hiện trước và sau đó bạn làm theo các phương pháp mà bạn không đề xuất - sẽ giúp bạn đọc dễ dàng hơn. Điều đó nói rằng, nó phải là câu trả lời được chấp nhận. –

+0

Đối với giải pháp javascript, bạn có thể tạo chức năng đó cho sự kiện gửi biểu mẫu, không gửi nút bấm. Chức năng đó sẽ được gọi và sẽ vô hiệu hóa nút gửi. – machineaddict

+1

Nó thấy rằng phương pháp Ba là hoàn hảo – yip

1

Ngoài ra, sử dụng các phím hình thức một lần.

5

Tạo khóa sử dụng một lần duy nhất để gửi cùng với biểu mẫu.

Dựa trên Javascript là một ý tưởng tồi vì nó có thể đã bị vô hiệu hóa trong ứng dụng của khách hàng bởi người dùng. Với lược đồ phím, khi máy chủ nhận được trình gửi, việc gửi cho khóa đó có thể bị khóa. Tuy nhiên, bạn có thể phản hồi các lần gửi trùng lặp theo ý muốn.

Để phương pháp này hoạt động, các khóa phải là duy nhất và rất khó dự đoán. Nếu không, một số biểu mẫu có thể bị khóa do xung đột chính. Vì vậy, bạn không phải theo dõi các khóa cho mỗi lần gửi biểu mẫu và tránh va chạm, các khóa sẽ hết hạn với phiên của người dùng đó. Một điều khác cần lưu ý là nếu người dùng độc hại có thể dự đoán được khóa, mã của bạn có thể dễ bị tấn công bởi một số loại tấn công hoặc khai thác DOS.

+1

Đây là phương pháp tôi sử dụng. Tạo ra một GUID bất cứ khi nào trang được trả lại, và bao gồm điều này trong cơ sở dữ liệu của bạn bất cứ khi nào bạn lưu một biểu mẫu. Trong mã xử lý gửi của bạn, hãy đảm bảo rằng GUID không tồn tại trong db trước khi chèn. –

+1

Loại thuật toán tạo GUID nào bạn thường sử dụng? –

1

tôi sử dụng này:

$form_token = $_SESSION['form_token'] = md5(uniqid()); 

gửi $ form_token với các hình thức, sau đó ...

tôi kiểm tra form_token:

if($_SESSION['form_token'] != $_POST['form_token']) { 
    echo 'Error'; 
} 
-1

Aron Rotteveel của Bao gồm một thẻ duy nhất trên mỗi POST đã làm việc cho tôi. Tuy nhiên, biểu mẫu của tôi vẫn gửi khi người dùng làm mới trang (F5). Tôi quản lý để giải quyết việc này bằng cách thêm một thiết lập lại:

  // reset session token 
      $_SESSION['token'] = md5($_POST['token'] . time()); 

kịch bản cuối cùng của tôi đi như thế:

if (isset($_SESSION['token'])) { 
    if (isset($_POST['token'])) { 
     if ($_POST['token'] != $_SESSION['token']) { 
      echo '<h3>Oops! You already submitted this request.</h3>'; 
     } else { 
      // process form 
      // reset session token 
      $_SESSION['token'] = md5($_POST['token'] . time()); 
     } 
    } else { 
     echo 'post token not set'; 
     $_SESSION['token'] = md5($somevariable . time()); 
    } 
} 

oh! đừng quên thêm session_start(); trước <!DOCTYPE>

Tôi là người mới sử dụng PHP, vì vậy hãy sửa tôi nếu bạn tìm thấy sự bất thường.

+0

đây là mã vô dụng. Chỉ cần thực hiện chuyển hướng HTTP sau khi gửi biểu mẫu. –

+0

tôi muốn làm điều đó nhưng biểu mẫu của tôi hoạt động trong một trang duy nhất. tôi ban đầu muốn sử dụng jquery unload() nhưng tôi thấy điều này hữu ích vào những dịp người dùng vô tình nhấn f5 (tải lại trang). bạn có liên kết trong chuyển hướng đó không? tôi rất muốn xem xét lại – Pabile

+0

lý do của bạn không có ý nghĩa. bạn cũng có thể thực hiện chuyển hướng HTTP trên trang đơn. –

-1

Sử dụng JavaScript để ngăn không cho gửi

+1

Ví dụ/mã trình diễn sẽ làm cho câu trả lời này trở thành một câu trả lời có giá trị. – nickhar

0

Một cách khác để tạo trang xác nhận nơi người dùng cuối cùng có thể nhấn nút gửi. Nó có thể làm giảm khả năng của loại này.

Các vấn đề liên quan