web-dev-qa-db-fra.com

Meilleur moyen d'éviter l'envoi en raison d'une actualisation de la page

Je pense que ce problème se produit souvent lors du développement d'une application Web. Mais je vais essayer d'expliquer en détail mon problème. 

J'aimerais savoir comment corriger ce problème, par exemple, lorsque j'ai un bloc de code comme celui-ci:

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

Lorsque le formulaire est soumis, les données sont insérées dans la base de données et le message Operation Done est généré. Ensuite, si je rafraîchis la page, les données seraient à nouveau insérées dans la base de données.

Comment ce problème peut être évité? N'hésitez pas à nous faire part de vos suggestions :)

21
markzzz

Ne pas afficher la réponse après votre action de création; rediriger vers une autre page une fois l'action terminée. Si quelqu'un actualise, il actualise la page demandée GET vers laquelle vous avez été redirigé.

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

Définissez un nombre aléatoire dans une session lorsque le formulaire est affiché et mettez également ce nombre dans un champ masqué. Si le numéro posté et le numéro de session correspondent, supprimez la session, exécutez la requête; Si ce n'est pas le cas, réaffichez le formulaire et générez un nouveau numéro de session. C’est l’idée de base des jetons XSRF; vous pouvez en savoir plus sur eux et leurs utilisations pour la sécurité ici: http://en.wikipedia.org/wiki/Cross-site_request_forgery

Voici un exemple:

<?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 } ?>
25
Ben

Comme ça:

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

Je pense que c'est plus simple,

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>
1
Sherin Jose

Pas besoin de rediriger ...

remplacer die(); par 

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

, en définissant isset sur isset différent de $ _POST ['nom'], ainsi, lorsque vous l'actualiserez, il ne sera plus ajouté à votre base de données, à moins que vous ne cliquiez à nouveau sur le bouton d'envoi.

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

J'ai rencontré un problème similaire. Je dois montrer à l'utilisateur le résultat du POST. Je ne veux pas utiliser de sessions et je ne veux pas rediriger le résultat dans l'URL (c'est un peu sécurisé, je ne le veux pas accidentellement) J'ai trouvé une solution assez simple qui devrait fonctionner pour les cas mentionnés dans d'autres réponses.

En soumettant le formulaire avec succès, incluez ce bit de Javascript sur la page:

<script>history.pushState({}, "", "")</script>

Il pousse l'URL actuelle sur la pile d'historique. Comme il s'agit d'un nouvel élément de l'historique, l'actualisation ne sera pas postée à nouveau.

0
Cully

Donc, pour ce dont j'avais besoin c'est ce qui fonctionne.

Sur la base de toutes les solutions ci-dessus, cela me permet de passer d'un formulaire à un autre et au n ^ formulaire, tout en empêchant que les mêmes données exactes soient "sauvegardées" à plusieurs reprises lorsqu'une page est actualisée publier les données d’avant s’étend sur la nouvelle page).

Merci à ceux qui ont posté leur solution qui m'a rapidement conduit à la mienne.

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

Nous travaillons sur des applications Web où nous concevons nombre de formulaires php. Il est diable d'écrire une autre page pour obtenir les données et les soumettre pour chaque formulaire. Pour éviter une nouvelle soumission, nous avons créé dans chaque table un champ 'random_check' qui est marqué comme 'Unique'.

Lors du chargement de page, générez une valeur aléatoire et stockez-la dans un champ de texte (qui est évidemment masqué).

Sur SUBMIT, enregistrez cette valeur de texte aléatoire dans le champ 'random_check' de votre table. En cas de nouvelle soumission, la requête passera par erreur car elle ne peut pas insérer la valeur en double.

Après cela, vous pouvez afficher l'erreur comme

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

Cela se produit simplement parce que lors de l'actualisation, votre demande sera à nouveau soumise.

Donc, l'idée de résoudre ce problème en guérissant sa cause.

Je veux dire que nous pouvons configurer une variable de session dans le formulaire et la vérifier lors de la mise à jour.

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"]);"> 
0
Amul