2010-01-25 8 views
29

Parfois, l'utilisateur peut appuyer deux fois sur Enter et le message est inséré deux fois.Comment éviter plusieurs insertions lors de la soumission d'un formulaire en PHP?

Existe-t-il une solution pour empêcher cela, sinon de vérifier s'il y a déjà un poste avec le même title et content?

+0

Pouvez-vous désactiver l'événement qui est déclenché en appuyant sur Entrée? –

+12

Smack les chaque fois qu'ils le font. Finalement, ils vont apprendre :) – Gordon

+4

Je recommanderais d'utiliser des clés de formulaire. Jetez un oeil à cela ici: http: //net.tutsplus.com/tutorials/php/secure-vos-forms-with-form-keys/ –

Répondre

1

Désactiver le bouton d'envoi en utilisant Javascript une fois le formulaire soumis (onsubmit).

Notez que si l'utilisateur a désactivé Javascript, il peut toujours soumettre deux fois. Que cela arrive ou non assez souvent pour justifier la vérification de votre code (comme vous l'avez suggéré dans votre question) est à vous.

0

Désactiver le bouton Envoyer une fois que l'utilisateur a envoyé le formulaire, en utilisant JavaScript. C'est ce que, par exemple, StackOverflow utilise lorsque vous répondez à une question.

Par exemple

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

Utilisez un JavaScript pour désactiver le bouton dès qu'il est cliqué.

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

Le gestionnaire 'onclick' ne fonctionnera pas si le formulaire est soumis via un coup de clavier, par exemple. l'utilisateur appuie sur la touche Entrée tout en se concentrant sur le bouton Envoyer. Il vaut mieux utiliser 'onsubmit' comme l'une des autres affiches suggérées. – Asaph

+1

@Asaph: J'aime vraiment l'idée symbolique suggérée par @Mats. Mais si rester côté client, il serait probablement préférable d'avoir une méthode qui intègre à la fois cliquez et soumettre. 2 clics de souris peuvent s'inscrire dans IE avant que l'onsubmit ne se déclenche réellement. Stupide, mais je l'ai vu. –

0

Une pression soumettre deux fois des résultats assez rarement dans de multiples inserts, mais si vous voulez un sollution mort simple, utiliser

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

dans la balise form, à condition que vous donnez à votre bouton Envoyer id="submit"

30

Utilisez un jeton unique avec la publication, de sorte que chaque publication/publication ne soit traitée qu'une seule fois.

Désactiver le bouton d'envoi n'est pas une très bonne solution, car les utilisateurs peuvent désactiver javascript ou faire d'autres choses bizarres. La validation côté client est un bon début, mais devrait toujours être sauvegardé avec la gestion côté serveur.

+2

+1 - c'est la méthode la plus courante et n'a aucune dépendance côté client. Pourquoi cela n'est-il pas accepté comme réponse? – Russell

+0

@Steve Non true. Les POST ne sont pas censés être idempotents. – kaqqao

46

Il existe plusieurs solutions à ce problème:

  1. Utilisez le Javascript pour désactiver le bouton de soumettre le formulaire lorsqu'il est affiché. Inconvénient à cela est que ce n'est ABSOLUMENT pas un moyen infaillible. Il est très facile de soumettre des formulaires sans cliquer sur le bouton, et cela ne fonctionnerait pas non plus pour les utilisateurs avec JavaScript désactivé. Je ne recommanderais certainement pas cette méthode.

    Exemple:

    <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. Utilisez PHP sessions pour définir une variable de session (par exemple $ _SESSION [ 'de posttimer']) à l'horodatage en cours sur le poteau. Avant de traiter le formulaire en PHP, vérifiez si la variable $ _SESSION ['posttimer'] existe et vérifiez la différence d'horodatage (IE: 2 secondes). De cette façon, vous pouvez facilement filtrer les doubles soumissions.

    Exemple:

    // 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. Inclure un jeton unique sur chaque poste. Dans ce cas, vous devez également définir une variable de session sur le jeton que vous souhaitez inclure, puis restituer le jeton dans le formulaire. Une fois le formulaire soumis, vous générez à nouveau le jeton. Lorsque le jeton soumis ne correspond pas au jeton de votre session, le formulaire a été soumis à nouveau et doit être déclaré non valide.

    Exemple:

    // 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 Bonne réponse, mais je modifierais donc votre recommandation vient en premier, et puis vous suivez les méthodes que vous ne recommandez pas - rendrait plus facile à lire. Cela dit, ce devrait être la réponse acceptée. –

+0

Pour la solution javascript, vous pouvez créer cette fonction pour un événement de soumission de formulaire, sans cliquer sur le bouton Soumettre. Cette fonction serait appelée et désactiverait le bouton de soumission. – machineaddict

+1

Il a vu que la méthode trois est parfaite – yip

1

En variante, utiliser les touches forment une seule fois.

5

Générez une clé unique à usage unique à envoyer avec le formulaire.

Compter sur Javascript est une mauvaise idée car il peut avoir été désactivé dans le client par l'utilisateur. Avec le schéma de clé, lorsque l'envoi est reçu par le serveur, la soumission pour cette clé peut être verrouillée. Vous pouvez répondre aux soumissions en double comme vous le souhaitez. Pour que cette approche fonctionne, les clés doivent être uniques et très difficiles à prédire. Sinon, certains formulaires pourraient être verrouillés en raison de collisions de clés. Vous n'avez donc pas besoin de suivre les clés pour chaque soumission de formulaire et d'éviter les collisions, les clés doivent expirer avec la session de cet utilisateur. L'autre chose à surveiller est que si les utilisateurs malveillants sont capables de prédire la clé, votre code peut être vulnérable à une sorte de piratage ou d'exploit DOS.

+1

C'est l'approche que j'utilise. Générez un GUID chaque fois que la page est rendue et incluez-le dans votre base de données chaque fois que vous enregistrez un formulaire. Dans votre code de traitement de soumission, assurez-vous que le GUID n'existe pas déjà dans la base de données avant l'insertion. –

+1

Quel type d'algorithme de génération de GUID utilisez-vous normalement? –

1

J'utilise ceci:

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

envoyer form_token $ avec le formulaire, puis ...

Je vérifie la form_token:

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

de Aron Rotteveel Inclure un jeton unique sur chaque POST a travaillé pour moi. Cependant, mon formulaire est toujours envoyé lorsqu'un utilisateur actualise la page (F5). J'ai réussi à résoudre ce problème en ajoutant une remise à zéro:

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

mes scripts finaux va comme:

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! ne pas oublier d'ajouter session_start(); avant <!DOCTYPE>

Je suis un débutant PHP alors s'il vous plaît corrigez-moi si vous trouvez des irrégularités.

+0

c'est un code inutile. Faites simplement une redirection HTTP après l'envoi du formulaire. –

+0

Je souhaite faire cela mais mon formulaire fonctionne sur une seule page. je souhaite d'abord utiliser jquery unload() mais je trouve cela utile dans certains cas, l'utilisateur appuie accidentellement sur f5 (rechargement de page). avez-vous un lien dans cette redirection? J'aimerais reconsidérer – Pabile

+0

votre raison n'a aucun sens. vous pouvez également effectuer une redirection HTTP sur la même page. –

-1

utiliser JavaScript pour l'arrêter d'envoyer

+1

Exemple/code de démo faites-en une réponse potentiellement précieuse. – nickhar

0

Une autre façon de créer une page de confirmation où l'utilisateur peut enfin appuyer sur le bouton d'envoi. Cela pourrait réduire les possibilités de ce genre.