PHP Erneutes Formular-Absenden durch reload

te one

Lt. Commander
Registriert
Apr. 2009
Beiträge
1.255
Hallo,

auf meiner Seite sendet ein User durch klick auf ein Bild ein Formular ab.
Wenn er nun allerdings F5 drückt bzw. irgendwie die Seite neu läd, wird dieses Formular natürlich erneut abgesendet und alles nochmals ausgeführt.

Gibt es eine einfache Möglichkeit das zu unterbinden? (Der Benutzer bekommt sowieso einen Reload-Button von mir generiert, der er benutzen kann)

Zwei Möglichkeiten sind mir schon eingefallen, aber die sind alle nicht so wirklich schön:
1. In der Datenbank zu jedem User eine Transaktions-ID hinterlegen die immer um 1 hochgezählt wird. Stimmt die ID des Formulars nicht mehr mit dieser überein, wird einfach nichts mit den Fomulardaten gemacht
--> Overhead in der Datenbank, möchte ich wenn möglich vermeiden
2. Nach dem ausführen der verschiedenen Funktionen mit den Formulardaten lade ich die Seite einfach neu (per Meta-Header-Angabe o.Ä.). Der User befindet sich immer auf der gleichen Seite, weshalb ich einfach ein festes Ziel hinterlegen kann
--> Auch wieder total viel Overhead bzw. verschwendete Bandbreite weil die Seite doppelt geladen wird.


Gibts da bessere Lösungen?
 
lad die Seite mit header() neu, bevor irgendetwas an HTML gesendet wird ;)
 
Dann hab ich halt nach jedem Absenden eines Formulars wieder nen reload drin...
Das Problem ist, dass alles auf der Seite aus Formularen besteht und später mal mehrere Hundert User im Sekundentakt sich dort durchklicken sollen...
 
Einfach per session - ist das Formular abgesendet $_SESSION['gesendet'] = TRUE setzen und vor dem eigentlich formular diese Variable abfragen. Falls diese wahr ist, wurde das Formular gesendet und Du kannst einen Text ausgeben, oder das Formular normal anzeigen lassen.
 
unset($_POST);

nach erstmaligem Absenden ausführen ... würde ich vorschlagen.
 
Wie wäre es denn statt eiem reload einfach eine weiterleitung auf sich selber? Beim reload wird da der letze Request nochmal ausgeführt, was bei dir das Formular senden wäre. Wenn du jetzt aber einfach statt neu laden auf sich selber weiter leiten lässt, muss er die seite neu aufrufen und die POST Daten sind weg.

Zumindest in der Theorie ^^

sonst vlt. mit js...
 
Zuletzt bearbeitet:
Ich denke das über Session zu machen, oder anderwertig Cachen (über IP etc.) sollte die beste Lösung sein.
Achte drauf, dass das Merkmal nur gesetzt wird, wenn alle Daten positiv validiert sind (und bei einer Fehleingabe man nochmal das Formular abschicken kann).

Das mit der Weiterleitung hatte ich schon einige Mal, hatte nichts am Problem geändert (womöglich aber auch etwas anders umgesetzt wie du es meinst).
 
Zuletzt bearbeitet:
ansonsten kann ich dir wirklich nur JS ans herz legen wenn das kein kriterium ist es nicht zu verwenden. Denn dann könntest du das Formular senden von JS erledigen lassen und für den Fall das es schon gesendet wurde lädt es nur die Seite neu ohne die POST daten zu verschicken.
 
syntec schrieb:
Einfach per session - ist das Formular abgesendet $_SESSION['gesendet'] = TRUE setzen und vor dem eigentlich formular diese Variable abfragen. Falls diese wahr ist, wurde das Formular gesendet und Du kannst einen Text ausgeben, oder das Formular normal anzeigen lassen.

Nein bloß nicht über die Session. Die ist nicht threadsafe! D.h. wenn der Reload nur schnell genug kommt gibt es hier ne Race condition und es gibt trotzdem einen Doppelsubmit!

Ich habe nach einigen Experimenten als sinnvollste Lösung eine Submission über die Datenbank gefunden. D.h. du erstellst per Zufallsgenerator für jedes Formular ein Hiddenfeld mit einem Submission-ID (z.B. ein MD5-Code von irgendwas zufälligem (bitte nicht date())) und wenn das Formular abgeschickt wird machst du mit der SubmissionID als primary key einen insert in die Datenbank. Wenns duplicate key Fehler gibt wurde das Formular schonmal abgeschickt und du kannst den Request ignorieren!
 
@syntec:
Der User kann aber auf der Seite die sich öffnet nachdem er das erste formular gesendet hat, nochmal eines absenden. Und das sieht wieder genau so aus (also hat die gleichen Felder, und kann sogar genau die gleichen Inhalte haben)

@maxpayne:
Ein löschen von $_POST bringt nichts, nach nem refresh sendet ers nochmal

@Mercsen:
Genau mit so einer Weiterleitung funktioniert es. Aber dann muss ich die Seite jedesmal neu laden was nicht gerade schön ist.
Das Problem ist, dass jeder User im Sekundentakt dieses Formular absenden wird. Ewiges hin-und-her-Geruckel wäre sehr unschön. Außerdem sollte möglichst wenig Bandbreite etc. (Datenbank usw. wird auch alles belastet) gebraucht werden.

@Mercsen, 2ter Post:
Wobei ich dann auch erst wieder erkennen muss ob das wirklich ein neues Absenden des Formulars ist. Dann könnte ich das mit der Transaktions-ID auch machen.
Bei jedem Seitenaufruf generiere ich eine eindeutige ID und schreibe es in die SESSION des Users. Außerdem wird diese ID im Formular übergeben.
Passen die Nummern zusammen, nutze ich die Daten, passen diese nicht zusammen, mache ich einfach nichts mit den Daten.
Dann wird das Formular zwar mehrfach abgesendet beim reload, aber das ist dann wurst, wenn nichts passiert.

@IceMatrix:
Man sollte erst alle Antworten lesen, hab ich eben gemerkt^^
Naja meine Lösung ist ja ähnlich und wird wahrscheinlich die einzig gute Lösung sein :) Eigenlob stinkt...

Denke so werde ich das umsetzen
 
rein informativ:
das date() nicht so toll ist kann ich verstehen, doch wie sieht es mit microtime() aus? Oder ist selbst da die gefahr zu groß das 2 userden selben hash bekommen?

und zu JS:

Ich meinte das so, das beim klicken das formular abgeschickt wird und der server antwortet dann mit:war ok, oder war nicht ok. Und diesen Zustand kann man sich ja merken und dann ist gar kein reload mehr nötig, da man einfach per JS die alten Daten nachladen oder gleich speichern und wieder eintragen kann. Doch selbst das reine nachladen der daten erzeugt weniger traffic als das gesamte formular zu laden ;)
 
Zuletzt bearbeitet:
ich stehe grade vor dem selben problem. bei uns werden formuladaten (supportanfragen etc.) abgeschickt und per mail verschickt. manchmal kommt dann bei uns so eine anfrage 2-4 mal an.

wäre es nicht am einfachsten ein CAPTCHA zu verwenden? ein CAPTCHA würde außerdem gleich noch spam eindämmen.

oder hab ich da grad nen denkfehler? der user müsste ja, wenn er das formular noch einmal abschicken möchte, den neuen CAPTCHA-Code eingeben. das problem wird dann nur, wenn er trotzdem 2 mal auf den senden button klickt, schickt er die erste anfrage ab und bei der zweiten, wird ein fehler ausgegeben und der user würde nur unnötig irritiert und schickt dann ein drittes mal die anfrage ab. :S
 
te one schrieb:
@IceMatrix:
Man sollte erst alle Antworten lesen, hab ich eben gemerkt^^
Naja meine Lösung ist ja ähnlich und wird wahrscheinlich die einzig gute Lösung sein :) Eigenlob stinkt...

Denke so werde ich das umsetzen

Pass aber drauf auf dass du nicht mit deiner Technik wiederrum ne Race Condition auslöst. Also entweder Transactions verwenden oder atomare Queries (wie der bereits erwähnte INSERT mit duplicate key).
 
Also zur Info wie ich das jetzt gelöst habe:

Code:
Wenn (Formulardaten vorhanden AND $_SESSION['action_id']==$_POST['action_id']) {
verarbeite_Formulardaten();
}
$_SESSION['action_id']++;
erzeuge_Formulare(); //Jedes Formular sendet ein Feld mit der action_id mit

Wenn jetzt einer F5 drückt, passt die SESSION nixmehr zur übergebenen ID von $_POST und mit den Formulardaten passiert nichts.

Einziger Nachteil: Beim Aktualisieren fragt der Browser ob der die Formulardaten nochmal senden soll. Aber wie gesagt macht das dem Skript dann ja nichts.

@IceMatrix:
Läuft das Skript nicht aufm Webserver entweder ganz durch oder eben nicht?
Weiß nicht ob das wirklich ein User zustande bringt...
 
Zuletzt bearbeitet:
te one schrieb:
@IceMatrix:
Läuft das Skript nicht aufm Webserver entweder ganz durch oder eben nicht?
Weiß nicht ob das wirklich ein User zustande bringt...

Er kann das zustande bringen. Wir haben da sehr einschlägige Erfahrungen mit Zahlungsabwicklungssystemen gemacht.
Die Session wird zu Beginn des Scripts aus einer Datei oder der Datenbank ausgelesen und erst zu Ende des Scripts wieder dorthin gespeichert. Wenn während der Ausführung des Scripts die Seite neu geladen wird gibts da zwangsläufig eine Race Condition. Das wird insbesondere dann kritisch wenn die Scriptausführung mal bisschen länger dauert, weil dann das Zeitfenster für die Race Condition größer wird.
 
Warum nicht einfach das Formular ausblenden wenn es abgeschickt wurde? Wenn es doch eh einen Reload-Button gibt?
 
@IceMatrix:
Vertrauen ist gut, Kontrolle ist besser. Das stimmt schon...
Werde mir das nochmal durch den Kopf gehen lassen.

@chriz0101:
Nicht jedes Formular sieht aus wie ein Formular.
Bei mir kann ein User mit einem Klick auf verschiedene Buttons laufen.
Die gleichen Buttons braucht er dann aber auch wieder auf der Seite die sich dann öffnet (am Anfang wird immer nen Eventhandler aufgerufen und dann der Rest der Seite aufgebaut). Und dieser Rest der Seite baut sich halt dynamisch auf.
Kann durchaus möglich sein, dass der User das Formular 100 mal hintereinander abschickt und ich muss unterscheiden ob das nen reload war oder eben tatsächlich ein neues Formular ist.
 
Ich denke auch mit javascript lässt sich da viel machen, aber wenn das eben vermeiden möchte...

Du könntest deine Methode auch noch erweitern in dem du alle Formulare an ein Skript schickst, dass nur entscheidet, ob der Request angenommen wird oder nicht, wenn ja schreibst du die Daten in die Session und leitest wieder auf die richtige Seite um, wenn nein dann leitest du so einfach um. Dadurch wird das Zeitfenster nochmal etwas kleiner und wenn man jetzt auf reload drückt sollte doch eigentlich keine abfrage mehr kommen. Außerdem wird die richtige Seite dann immer nur einmal geladen.
 
Du meinst du hast sowas wie

<form action="?page=bla" method="post">
<button>Bla</button>
</form>

?

FALLS du sowas benutzt, dann mach es lieber über GET, da sollte das Problem nicht auftauchen.
 

Ähnliche Themen

Zurück
Oben