Ich habe ein einfaches Formular, das Text an meine SQL-Tabelle übermittelt. Das Problem ist, dass der Benutzer, nachdem er den Text übermittelt hat, die Seite aktualisieren kann und die Daten erneut übermittelt werden, ohne das Formular erneut ausfüllen zu müssen. Ich könnte den Benutzer auf eine andere Seite umleiten, nachdem der Text gesendet wurde, aber ich möchte, dass Benutzer auf derselben Seite bleiben.
Ich erinnere mich an etwas gelesen zu haben, in dem ich jedem Benutzer eine eindeutige Sitzungs-ID gab und mit einem anderen Wert vergleicht, der das Problem löste, das ich habe, aber ich habe vergessen, wo es ist.
Verwenden Sie das Post/Redirect/Get-Muster. http://en.wikipedia.org/wiki/Post/Redirect/Get
Mit meiner Website werde ich eine Nachricht in einem Cookie oder einer Sitzung speichern, nach dem Beitrag umleiten, das Cookie/die Sitzung lesen und dann den Wert dieser Sitzung oder Cookie-Variablen löschen.
Ich möchte auch darauf hinweisen, dass Sie eine Javascript-Methode verwenden können, window.history.replaceState
, um das erneute Senden einer Schaltfläche zum Aktualisieren und Zurück zu verhindern.
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
</script>
Konzeptnachweis hier: https://dtbaker.net/files/prevent-post-resubmit.php
Ich würde immer noch einen Post/Redirect/Get-Ansatz empfehlen, aber dies ist eine neuartige JS-Lösung.
Sie sollten ein Post-Redirect-Get-Muster verwenden, um dieses Problem zu lösen. Wenn Sie jedoch in einer Position gelandet sind, in der PRG nicht möglich ist (z. B. das Formular selbst ist in einem Include enthalten, um Weiterleitungen zu verhindern), können Sie einige der Anforderungsparameter anhängen Erstellen Sie eine Zeichenfolge basierend auf dem Inhalt und prüfen Sie, ob Sie die Zeichenfolge noch nicht gesendet haben.
//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!
}
sie können pervent Form Wiedervorlage über Sitzungsvariable Like
zuerst müssen Sie Rand () in der Textbox und $ _SESSION ['Rand'] auf der Formularseite setzen
<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>
Nach dem Überprüfen von $ _SESSION ['Rand'] mit dem Textfeld $ _POST ['randcheck'] valueLike
if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['Rand'])
{
//Your Code here
}
Wenn das Formular verarbeitet wird, leiten Sie auf eine andere Seite um:
... process complete....
header('Location: thankyou.php');
sie können auch auf dieselbe Seite umleiten.
wenn Sie so etwas wie Kommentare machen und möchten, dass der Benutzer auf derselben Seite bleibt, können Sie Ajax verwenden, um die Formularübergabe zu bearbeiten
Verwenden Sie die Kopfzeile und leiten Sie die Seite um.
header("Location:your_page.php");
Sie können auf dieselbe Seite oder auf eine andere Seite umleiten.
Deaktivieren Sie $ _POST, nachdem Sie es in die Datenbank eingefügt haben.
unset($_POST);
Ich verwende diese Javascript-Zeile, um das Popup zu blockieren, das die erneute Vorlage des Formulars beim Aktualisieren fordert, sobald das Formular gesendet wurde.
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
Platzieren Sie diese Zeile einfach in der Fußzeile Ihrer Datei und sehen Sie die Magie
Ich fand die nächste Problemumgehung. Sie können die Weiterleitung nach der Verarbeitung der POST
-Anforderung umgehen, indem Sie history
object bearbeiten.
Sie haben also das HTML-Formular:
<form method=POST action='/process.php'>
<input type=submit value=OK>
</form>
Wenn Sie dieses Formular auf Ihrem Server verarbeiten, müssen Sie den Benutzer nicht zu /the/result/page
umleiten, indem Sie den Header Location
folgendermaßen einrichten:
$cat process.php
<?php
process POST data here
...
header('Location: /the/result/page');
exit();
?>
Nachdem Sie POST
ed-Daten verarbeitet haben, machen Sie einen kleinen <script>
und das Ergebnis /the/result/page
.
<?php
process POST data here
render the <script> // see below
render `/the/result/page` // OK
?>
Der <script>
, den Sie rendern sollten:
<script>
window.onload = function() {
history.replaceState("", "", "/the/result/page");
}
</script>
Das Ergebnis ist:
wie Sie sehen können, sind die Formulardaten zu process.php
-Skript POST
ed.
Dieses Skript verarbeitet POST
ed Daten und macht /the/result/page
gleichzeitig mit:
POST
-Daten beim Aktualisieren der Seite (F5) POST
, wenn Sie durch den Browserverlauf zur vorherigen/nächsten Seite navigierenUPD
Als eine andere Lösung frage ich feature request das Mozilla FireFox -Team, das Benutzern die Einrichtung eines NextPage
-Headers ermöglicht, der wie Location
-Header funktioniert und post/redirect/get
-Muster veraltet macht.
Zusamenfassend. Wenn der Server die POST
-Daten erfolgreich verarbeitet, geschieht Folgendes:
NextPage
-Header statt Location
POST
-Formulardaten wie für GET
-Anforderungen in post/redirect/get
-MusterDer Browser wiederum zeigt den Header NextPage
:
window.location
mit dem Wert NextPage
anGET
-Anforderung an NextPage
aus, anstatt rePOST
-FormulardatenIch denke, das wäre ausgezeichnet, wenn es umgesetzt würde, nicht? =)
Ein ziemlich sicherer Weg ist, eine eindeutige ID in den Post zu implementieren und diese im Cache zu speichern
<input type='hidden' name='post_id' value='".createPassword(64)."'>
Dann tun Sie dies in Ihrem Code:
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;
}
Leiten Sie es einfach auf dieselbe Seite um, nachdem Sie die Formulardaten verwendet haben. Ich habe es ausprobiert.
header('location:yourpage.php');
Eine verfeinerte Version von Moobs Post. Erstellen Sie einen Hash des POST, speichern Sie ihn als Sitzungscookie und vergleichen Sie bei jeder Sitzung Hashes.
// 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
}
Rufen Sie nach dem Einfügen in die Datenbank die Methode unset () auf, um die Daten zu löschen.
unset ($ _ POST);
Um das Einfügen von Aktualisierungsdaten zu verhindern, führen Sie nach dem Einfügen des Datensatzes eine Seitenumleitung auf dieselbe oder eine andere Seite durch.
header ('Location:'. $ _ SERVER ['PHP_SELF']);
Grundsätzlich müssen Sie die Seite aus dieser Seite umleiten, aber es kann immer noch ein Problem sein, wenn Ihr Internet langsam ist.
Beispiel für ein Basisszenario:
Weg zu lösen
Client-Seite
Serverseite
So verhindern Sie die Wiedervorlage von PHP-Formularen ohne Umleitung. Wenn Sie $ _SESSION (nach session_start) und ein $ _POST-Formular verwenden, können Sie Folgendes tun:
if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
// do your stuff, save data into database, etc
}
In Ihrem HTML-Formular fügen Sie Folgendes ein:
<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;
}
}
?>
Jedes Mal, wenn das Formular übermittelt wird, wird ein neuer Vorgang generiert, in einer Sitzung gespeichert und mit dem Nachakt verglichen.
Ps: Wenn Sie ein Get-Formular verwenden, können Sie einfach alle POST mit GET ändern.
Die Verwendung des Post/Redirect/Get-Musters von Keverw ist eine gute Idee. Sie sind jedoch nicht in der Lage, auf Ihrer Seite zu bleiben (und ich denke, das war es, wonach Sie gefragt haben?) Außerdem kann es manchmal fail :
Wenn ein Webbenutzer aktualisiert wird, bevor die erste Übermittlung abgeschlossen ist wegen Server-Verzögerung, was zu einer doppelten Anforderung von HTTP POST in .__ führt. bestimmte Benutzeragenten.
Eine andere Option wäre das Speichern in einer Sitzung, wenn der Text wie folgt in Ihre SQL-Datenbank geschrieben werden soll:
if($_SERVER['REQUEST_METHOD'] != 'POST')
{
$_SESSION['writeSQL'] = true;
}
else
{
if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
{
$_SESSION['writeSQL'] = false;
/* save $_POST values into SQL */
}
}
Wie bereits erwähnt, ist es nicht möglich, Post/Redirect/Get nicht zu verwenden. Gleichzeitig ist es jedoch recht einfach, das zu tun, was Sie serverseitig tun möchten.
Auf Ihrer POST - Seite überprüfen Sie einfach die Benutzereingabe, bearbeiten diese jedoch nicht, sondern kopieren sie in ein SESSION-Array. Sie kehren dann wieder zur Haupt-Einreichungsseite zurück. Auf der Hauptseite Ihrer Übermittlungsseite wird geprüft, ob das von Ihnen verwendete SESSION-Array vorhanden ist. Falls ja, kopieren Sie es in ein lokales Array und löschen Sie es. Von dort aus können Sie darauf reagieren.
Auf diese Weise erledigen Sie Ihre gesamte Hauptarbeit nur einmal und erreichen, was Sie wollen.
Ich suchte nach einer Lösung, um die Wiedervorlage später in einem großen Projekt zu verhindern. Der Code funktioniert sehr gut mit $ _GET und $ _POST, und ich kann das Verhalten der Formularelemente nicht ändern, ohne das Risiko unvorhergesehener Fehler. __ Hier ist mein 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"] );
Es funktioniert nur, um die erneute Übermittlung von $ _POST und nicht von $ _GET zu vermeiden. Dies ist jedoch das Verhalten, das ich brauche .. Das Problem mit der erneuten Übermittlung funktioniert nicht mit Datei-Uploads!