web-dev-qa-db-fra.com

Comment éviter les insertions multiples lors de la soumission d'un formulaire en PHP?

Parfois, l'utilisateur peut appuyer sur Enter deux fois et la publication est insérée deux fois.

Y a-t-il une solution pour empêcher cela autre que de vérifier s'il existe déjà une publication avec les mêmes title et content?

29
user198729

Il y a plusieurs solutions à ce problème:

  1. Utilisez Javascript pour désactiver le bouton de soumission du formulaire lorsqu'il est publié. Inconvénient, c’est que c’est ABSOLUMENT un moyen infaillible. Il est très facile de soumettre des formulaires sans cliquer sur le bouton. 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 ['posttimer']) sur l'horodatage actuel de la publication. Avant de traiter le formulaire en PHP, vérifiez si la variable $ _SESSION ['posttimer'] existe et vérifiez une certaine 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. Inclut un jeton unique sur chaque POST. Dans ce cas, vous devez également définir une variable de session sur le jeton que vous souhaitez inclure, puis afficher 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é invalide.

    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
            }
        }
    }
    
48
Aron Rotteveel

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

Désactiver le bouton d'envoi n'est pas une très bonne solution car javascript pourrait être désactivé ou faire d'autres choses étranges. La validation côté client est un bon début, mais elle doit toujours être sauvegardée avec la gestion côté serveur.

30
Mats Fredriksson

Générez une clé unique et à usage unique à soumettre 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, l'envoi de cette clé peut être verrouillé. Vous pouvez répondre aux envois en double comme bon vous semble.

Pour que cette approche fonctionne, les clés doivent être uniques et très difficiles à prévoir. Sinon, certains formulaires pourraient être verrouillés en raison de collisions clés. Ainsi, vous n'avez pas à suivre les clés pour chaque soumission de formulaire et à éviter les collisions, les clés doivent expirer avec la session de cet utilisateur. L'autre chose à surveiller est que si des utilisateurs malveillants sont en mesure de prédire la clé, votre code peut être vulnérable à une sorte de piratage ou à un exploit de type DOS. 

5
Dana the Sane

Empêcher la soumission de formulaires en double montre une façon de le faire sans javascript.

2
Javi

J'utilise ceci:

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

envoyez $ form_token avec le formulaire, puis ...

Je vérifie le formulaire_token:

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

Désactivez le bouton d'envoi à l'aide de Javascript une fois le formulaire soumis (onsubmit).

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

1
Aistina

Vous pouvez également utiliser des clés de formulaire uniques.

1
mst

Une autre façon de créer une page de confirmation sur laquelle l’utilisateur peut enfin appuyer sur le bouton Envoyer. Cela pourrait réduire les possibilités de ce genre. 

0
Diwakar Kumar Singh

Je fais ce qui suit sur le action.php 

if($_SESSION && isset($_SESSION['already_submitted'])) {

  # If already submitted just redirect to thank you page

} else {

    # If first submit then assign session value and process the form
    $_SESSION['already_submitted'] = true;

    # Process form

}

Remarque: commencez toujours vos sessions dans l'en-tête à l'aide de session_start ();

0
Robert Sinclair

désactivez le bouton d'envoi une fois que l'utilisateur a soumis le formulaire à l'aide de JavaScript. C’est ce que StackOverflow utilise par exemple pour répondre à une question. 

Par exemple

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

Utilisez un JavaScript pour désactiver le bouton dès que vous cliquez dessus.

onclick="this.disabled=true;forms[0].submit();"
0
Joel Etherton

En appuyant deux fois sur submit, vous obtiendrez rarement plusieurs insertions, mais si vous voulez une solution simple, utilisez

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

dans la balise de formulaire, à condition que vous donniez votre bouton d'envoi id="submit"

0
raveren