J'ai un formulaire simple qui envoie du texte à ma table SQL. Le problème est qu'après que l'utilisateur a soumis le texte, il peut actualiser la page et les données sont soumises à nouveau sans remplir à nouveau le formulaire. Je pourrais rediriger l'utilisateur vers une autre page une fois le texte soumis, mais je souhaite que les utilisateurs restent sur la même page.
Je me souviens avoir lu quelque chose sur le fait de donner à chaque utilisateur un identifiant de session unique et de le comparer avec une autre valeur qui résolvait le problème que j’avais mais j’ai oublié où il se trouve.
Utilisez le modèle Post/Redirect/Get. http://en.wikipedia.org/wiki/Post/Redirect/Get
Avec mon site Web, je vais stocker un message dans un cookie ou une session, rediriger après le message, lire le cookie/la session, puis effacer la valeur de cette variable de session ou de cookie.
Je tiens également à souligner que vous pouvez utiliser une approche javascript, window.history.replaceState
, pour empêcher une nouvelle soumission lors de l'actualisation et du bouton Précédent.
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
</script>
Preuve de concept ici: https://dtbaker.net/files/prevent-post-resubmit.php
Je recommanderais toujours une approche Post/Redirect/Get, mais il s'agit d'une nouvelle solution JS.
Vous devriez vraiment utiliser un motif «Get Redirect Get» pour gérer cela, mais si vous vous retrouvez dans une position où PRG n'est pas viable (par exemple, le formulaire est lui-même dans une inclusion, ce qui empêche les redirections), vous pouvez hacher certains paramètres de requête. créer une chaîne en fonction du contenu, puis vérifiez que vous ne l’avez pas déjà envoyée.
//create digest of the form submission:
$messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']);
//and check it against the stored value:
$sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:'';
if($messageIdent!=$sessionMessageIdent){//if its different:
//save the session var:
$_SESSION['messageIdent'] = $messageIdent;
//and...
do_your_thang();
} else {
//you've sent this already!
}
vous pouvez effectuer une nouvelle soumission de formulaire via une variable de session, comme
vous devez d’abord définir Rand () dans la zone de texte et $ _SESSION ['Rand'] sur la page du formulaire
<form action="" method="post">
<?php
$Rand=rand();
$_SESSION['Rand']=$Rand;
?>
<input type="hidden" value="<?php echo $Rand; ?>" name="randcheck" />
Your Form's Other Field
<input type="submit" name="submitbtn" value="submit" />
</form>
Après vérification, $ _SESSION ['Rand'] avec la zone de texte $ _POST ['randcheck'] valueLike
if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['Rand'])
{
//Your Code here
}
Lorsque le formulaire est traité, vous redirigez vers une autre page:
... process complete....
header('Location: thankyou.php');
vous pouvez également rediriger vers la même page.
si vous faites quelque chose comme des commentaires et que vous voulez que l'utilisateur reste sur la même page, vous pouvez utiliser Ajax pour gérer l'envoi du formulaire
Utilisez l'en-tête et redirigez la page.
header("Location:your_page.php");
Vous pouvez rediriger vers une même page ou une autre page.
Désactivez $ _POST après l'avoir inséré dans la base de données.
unset($_POST);
J'utilise cette ligne javascript pour bloquer la fenêtre contextuelle demandant de soumettre à nouveau le formulaire lors de l'actualisation une fois le formulaire soumis.
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
Il suffit de placer cette ligne au pied de votre fichier et de voir la magie
J'ai trouvé la solution suivante. Vous pouvez échapper à la redirection après avoir traité la demande POST
en manipulant history
object.
Donc vous avez le formulaire HTML:
<form method=POST action='/process.php'>
<input type=submit value=OK>
</form>
Lorsque vous traitez ce formulaire sur votre serveur, au lieu de rediriger l'utilisateur vers /the/result/page
, configurez l'en-tête Location
comme ceci:
$cat process.php
<?php
process POST data here
...
header('Location: /the/result/page');
exit();
?>
Après le traitement des données POST
ed, vous rendez le petit <script>
et le résultat /the/result/page
.
<?php
process POST data here
render the <script> // see below
render `/the/result/page` // OK
?>
Le <script>
à rendre:
<script>
window.onload = function() {
history.replaceState("", "", "/the/result/page");
}
</script>
Le résultat est:
comme vous pouvez le constater, les données du formulaire sont POST
ed to process.php
script.
Ce script processus POST
ed données et rendu /the/result/page
immédiatement avec:
POST
lorsque vous actualisez la page (F5) POST
lorsque vous naviguez vers la page précédente/suivante dans l'historique du navigateurUPD
Comme autre solution, je demande à demande de fonctionnalité l’équipe Mozilla FireFox de permettre aux utilisateurs de configurer l’en-tête NextPage
qui fonctionnera comme l’en-tête Location
et de rendre le modèle post/redirect/get
obsolète.
En bref. Lorsque le serveur traite les données POST
avec succès, il:
NextPage
au lieu de Location
POST
comme il le ferait pour la demande GET
dans le modèle post/redirect/get
Le navigateur, à son tour, voit l’en-tête NextPage
:
window.location
avec la valeur NextPage
GET
en NextPage
au lieu des données de formulaire rePOST
.Je pense que ce serait excellent s'il était mis en œuvre, non? =)
Une méthode assez sûre consiste à implémenter un identifiant unique dans la publication et à
<input type='hidden' name='post_id' value='".createPassword(64)."'>
Ensuite, dans votre code, faites ceci:
if( ($_SESSION['post_id'] != $_POST['post_id']) )
{
$_SESSION['post_id'] = $_POST['post_id'];
//do post stuff
} else {
//normal display
}
function createPassword($length)
{
$chars = "abcdefghijkmnopqrstuvwxyz023456789";
srand((double)microtime()*1000000);
$i = 0;
$pass = '' ;
while ($i <= ($length - 1)) {
$num = Rand() % 33;
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$i++;
}
return $pass;
}
Il vous suffit de le rediriger vers la même page après avoir utilisé les données de formulaire, et cela fonctionne. J'ai essayé.
header('location:yourpage.php');
Une version raffinée du post de Moob. Créez un hachage du POST, enregistrez-le en tant que cookie de session et comparez les hachages à chaque session.
// Optionally Disable browser caching on "Back"
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' );
header( 'Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT' );
$post_hash = md5( json_encode( $_POST ) );
if( session_start() )
{
$post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash;
$_SESSION[ 'post_hash' ] = $post_hash;
session_write_close();
}
else
{
$post_resubmitted = false;
}
if ( $post_resubmitted ) {
// POST was resubmitted
}
else
{
// POST was submitted normally
}
Après l'avoir insérée dans la base de données, appelez la méthode unset () pour effacer les données.
non défini ($ _ POST);
Pour empêcher l’insertion de données actualisées, effectuez une redirection de page vers la même page ou une page différente après l’insertion de l’enregistrement.
en-tête ('Emplacement:'. $ _ SERVER ['PHP_SELF']);
En gros, vous devez rediriger la page en dehors de cette page, mais cela peut toujours poser un problème lorsque votre internet est lent (En-tête de redirection à partir de serveride)
Exemple de scénario de base:
Moyen de résoudre
Côté client
Du côté serveur
Comment empêcher la resoumission de formulaire php sans redirection. Si vous utilisez $ _SESSION (après session_start) et un formulaire $ _POST, vous pouvez faire quelque chose comme ceci:
if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
// do your stuff, save data into database, etc
}
Dans votre formulaire html, mettez ceci:
<input type="hidden" id="act" name="act" value="<?php echo ( empty($_POST['act']) || $_POST['act']==2 )? 1 : 2; ?>">
<?php
if ( $_POST['act'] == $_SESSION['act'] ){
if ( empty( $_SESSION['act'] ) || $_SESSION['act'] == 2 ){
$_SESSION['act'] = 1;
} else {
$_SESSION['act'] = 2;
}
}
?>
Ainsi, chaque fois que le formulaire est soumis, un nouvel acte est généré, stocké en session et comparé au post-acte.
Ps: si vous utilisez un formulaire Get, vous pouvez facilement changer tout POST avec GET et cela fonctionne aussi.
Utiliser la réponse Post/Redirect/Get de Keverw est une bonne idée. Cependant, vous ne pouvez pas rester sur votre page (et je pense que c’est ce que vous demandiez?). En outre, cela peut parfois échouer :
Si un utilisateur Web est actualisé avant la fin de la soumission initiale en raison d'un décalage du serveur, entraînant la duplication d'une demande HTTP POST dans certains agents utilisateurs.
Une autre option serait de stocker dans une session si le texte devait être écrit dans votre base de données SQL comme ceci:
if($_SERVER['REQUEST_METHOD'] != 'POST')
{
$_SESSION['writeSQL'] = true;
}
else
{
if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
{
$_SESSION['writeSQL'] = false;
/* save $_POST values into SQL */
}
}
Comme d'autres l'ont dit, il n'est pas possible de sortir de post/redirect/get. Mais en même temps, il est assez facile de faire ce que vous voulez faire côté serveur.
Dans votre page POST, vous ne faites que valider la saisie de l'utilisateur mais vous n'agissez pas sur celle-ci. Vous la copiez plutôt dans un tableau SESSION. Vous êtes ensuite redirigé vers la page de soumission principale. Votre page de soumission principale commence par vérifier si le tableau SESSION que vous utilisez existe et, le cas échéant, copiez-le dans un tableau local et supprimez-le. À partir de là, vous pouvez agir.
De cette façon, vous ne réaliserez qu'une seule fois tout votre travail principal, en réalisant ce que vous voulez faire.
J'ai cherché une solution pour empêcher la resoumission dans un projet énorme par la suite . Le code fonctionne fortement avec $ _GET et $ _POST et je ne peux pas changer le comportement des éléments de formulaire sans le risque de bugs imprévus. mon code:
<!-- language: lang-php -->
<?php
// Very top of your code:
// Start session:
session_start();
// If Post Form Data send and no File Upload
if ( empty( $_FILES ) && ! empty( $_POST ) ) {
// Store Post Form Data in Session Variable
$_SESSION["POST"] = $_POST;
// Reload Page if there were no outputs
if ( ! headers_sent() ) {
// Build URL to reload with GET Parameters
// Change https to http if your site has no ssl
$location = "https://" . $_SERVER['HTTP_Host'] . $_SERVER['REQUEST_URI'];
// Reload Page
header( "location: " . $location, true, 303 );
// Stop any further progress
die();
}
}
// Rebuilt POST Form Data from Session Variable
if ( isset( $_SESSION["POST"] ) ) {
$_POST = $_SESSION["POST"];
// Tell PHP that POST is sent
$_SERVER['REQUEST_METHOD'] = 'POST';
}
// Your code:
?><html>
<head>
<title>GET/POST Resubmit</title>
</head>
<body>
<h1>Forms:</h1>
<h2>GET Form:</h2>
<form action="index.php" method="get">
<input type="text" id="text_get" value="test text get" name="text_get"/>
<input type="submit" value="submit">
</form>
<h2>POST Form:</h2>
<form action="index.php" method="post">
<input type="text" id="text_post" value="test text post" name="text_post"/>
<input type="submit" value="submit">
</form>
<h2>POST Form with GET action:</h2>
<form action="index.php?text_get2=getwithpost" method="post">
<input type="text" id="text_post2" value="test text get post" name="text_post2"/>
<input type="submit" value="submit">
</form>
<h2>File Upload Form:</h2>
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file">
<input type="submit" value="submit">
</form>
<h1>Results:</h1>
<h2>GET Form Result:</h2>
<p>text_get: <?php echo $_GET["text_get"]; ?></p>
<h2>POST Form Result:</h2>
<p>text_post: <?php echo $_POST["text_post"]; ?></p>
<h2>POST Form with GET Result:</h2>
<p>text_get2: <?php echo $_GET["text_get2"]; ?></p>
<p>text_post2: <?php echo $_POST["text_post2"]; ?></p>
<h2>File Upload:</h2>
<p>file:
<pre><?php if ( ! empty( $_FILES ) ) {
echo print_r( $_FILES, true );
} ?></pre>
</p>
<p></p>
</body>
</html><?php
// Very Bottom of your code:
// Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice
unset( $_SESSION["POST"] );
Cela fonctionne seulement pour éviter la nouvelle soumission de $ _POST, pas de $ _GET. Mais c’est le comportement dont j’ai besoin… .. Le problème de resoumission ne fonctionne pas avec les téléchargements de fichiers!