Du bist nicht angemeldet.

Lieber Besucher, herzlich willkommen bei: WebStyleBoard. Falls dies dein erster Besuch auf dieser Seite ist, lies bitte die Hilfe durch. Dort wird dir die Bedienung dieser Seite näher erläutert. Darüber hinaus solltest du dich registrieren, um alle Funktionen dieser Seite nutzen zu können. Benutze das Registrierungsformular, um dich zu registrieren oder informiere dich ausführlich über den Registrierungsvorgang. Falls du dich bereits zu einem früheren Zeitpunkt registriert hast, kannst du dich hier anmelden.

TNS

alter Sack, aber Chef :D

  • »TNS« ist der Autor dieses Themas

Beiträge: 4 695

Vorname: Andreas

  • Private Nachricht senden

1

Donnerstag, 2. September 2010, 04:47

erneutes Abschicken eines Formulars per Reload verhindern?

Guten Morgen

Ich versuche mal ein Szenario zu skizzieren um das Problem zu verdeutlichen.

Ich habe eine PHP-Datei (nennen wir sie mal upload.php) mit einem Formular um Dateien hoch laden zu können. Per Submit ruft sich diese Datei selber auf und verarbeitet $_POST und $_FILES wie gewünscht. Gebe ich jetzt einfach nur eine Meldung ala "Upload erfolgreich" aus bekomme ich ein Problem wenn der User die Seite per "Aktualisieren" neu lädt. Dann werden die ganzen Daten ja nochmal verarbeitet und die Datei erneut hoch geladen werden. Das umgehe ich derzeit damit das ich folgendes einlege wenn das Formular abgefertigt ist:

PHP-Quelltext

1
2
3
header("Refresh: 2; URL="upload.php"");
echo "Upload erfolgreich";
exit;


Diese Verfahrensweise funktioniert und macht genau das was beabsichtigt ist ABER sie gefällt mir nicht zu 100%. Ich würde sozusagen gern beide Seiten der Medaille haben wollen und mir den Refresh ersparen und trotzdem das erneute Verarbeiten durch "Aktualisieren der Seite" verhindern ;) Hat da jemand ne einfache Lösung auf die ich nicht komme? (Captcha ist hier übrigens keine Option und auf Sessions würde ich gern verzichten)

Andreas
Signatur von »TNS«

TNS

alter Sack, aber Chef :D

  • »TNS« ist der Autor dieses Themas

Beiträge: 4 695

Vorname: Andreas

  • Private Nachricht senden

2

Donnerstag, 2. September 2010, 05:10

so gehts mir mit LapisInfernalis auch immer ... beim erklären des Problems kommt ne Lösung :thumbsup:
Wie sauber wäre folgende Verfahrensweise:

Aufruf des Formulars
- eindeutige ID wird erstellt und in einer DB gespeichert + Feld "fertig = 0"
- ID wird per hidden dem Formular mitgegeben

Formular wird abgeschickt
- Check in der DB ob die ID existiert
- - ja + fertig = 0 -> Formular wird normal verarbeitet und fertig wird auf "1" gesetzt
- - ja + fertig = 1 -> nix da

Wenn ich das um die Zeit schon richtig sehe würde ich damit auch externe Aufrufe verhindern weil man ja vorher immer erst das Formular aufrufen muss um eine ID zu bekommen oder?

Andreas
Signatur von »TNS«

3

Donnerstag, 2. September 2010, 11:30

Ich ergänz mal ein bisschen :)

Das Problem tritt natürlich häufig auf, aber im Sinne eines REST-vollen Designs sind beide Lösungen suboptimal, wirklich sauber wäre es wohl, wenn die Meldung dass alles OK übertragen wurde, unter einem ganz anderen URL erscheinen würde. Dafür gibt es HTTP-Redirects, zum Beispiel folgendes Design:

  • GET-Request nach /admin/products/foo: Bearbeiten-Formular
  • POST-Request nach /admin/products/foo: Aktualisieren; bei Misserfolg erneutes Anzeigen des Formulars mit Fehlermeldungen. Bei Erfolg: Redirect nach /admin/message, wo einem gesagt wird, dass alles OK ist
Welche Nachricht da jetzt genau angezeigt wird, wird per Session gespeichert, dafür haben viele moderne Web-Frameworks eine oft so genannte "flash"-Methode. Durch die Umleitung gibt es kein Problem mit erneuter Absendung gültiger Daten per Reload-Knopp, man ist ja bei 'nem ganz anderen URL. OK, möglicherweise ist dann die Meldung weg, aber die Daten gehen nicht kaputt.

Gegen eine Lösung mit verzögertem Refresh spricht, dass während dieser Verzögerung per Reload trotzdem Mist gemacht werden kann. Außerdem hat das W3C noch ein paar gute Argumente gegen Refreshs.

Das mit der vergebenen ID ist natürlich trickreich, aber man hat immer noch keine schönen getrennten URLs fürs Absenden und die Meldung.

Ich habe mal ein kleines Beispielskript vorbereitet, was den Mechanismus ganz anschaulich macht:
Hier aber mal das wesentliche (die Routes sind im Gist ab Zeile 9): ein GET-Request auf /edit zeigt einfach das Ändern-Formular an, im Template wird noch der eventuell bekannte Name aus der Session geholt (siehe unten im Skript). Ein Post-Request auf /edit ändert den Namen in der Session auf den per Formular übermittelten. Anschließend wird eine Nachricht in die Session eingetragen und zur Nachricht-Anzeige-Seite weitergeleitet. Was da rauskommt, ist ein handelsüblicher 302-Redirect, also ein "temporärer", das ist genau das richtige für unsere Zwecke. Die einzige "komplexe" Aktion da ist das update auf POST /edit, die anderen Actions zeigen nur Daten an, deshalb findet da alles nur in den Templates unten im Skript statt.

HTH und viele Grüße
Mirko

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »memowe« (2. September 2010, 12:16) aus folgendem Grund: Abo hinzugefügt - hier ist ja nix los, dann muss ich nicht jeden Tag gucken :)


TNS

alter Sack, aber Chef :D

  • »TNS« ist der Autor dieses Themas

Beiträge: 4 695

Vorname: Andreas

  • Private Nachricht senden

4

Donnerstag, 2. September 2010, 12:40

Mirko, das mag vielleicht schön aussehen ist aber größtenteils kontraproduktiv bzw. geht zu Lasten der Bedienerfreundlichkeit. Durch den Redirect auf eine weitere Datei muss der User dann mind. noch einen Klick machen um wieder auf die Uploadseite zu kommen. Dies ist zb. bei einem Galeriescript die Hölle wenn man mal 10 oder 15 Bilder hochladen will (ich weiss das es da andere Möglichkeiten gibt, aber das soll hier nicht das Thema sein). Daher benutze ich bisher die Refresh-Lösung, denn da kann ich die Leute mit einer Erfolgsmeldung direkt wieder auf die Uploadseite schicken.
Signatur von »TNS«

5

Donnerstag, 2. September 2010, 13:00

Hey Andreas,

ich bin froh dass Du gefragt hast! Tatsächlich hatte ich das vergessen, aber schon vorbereitet. Wie Du sehen kannst, übergebe ich dem Flash schon einen redirect_url zusammen mit der Message. Das Testskript macht dann nach Anzeige der Nachricht einen ganz entspannten META-Refresh (ja, hier passt er) und es ist genau so komfortabel wie Du haben wolltest :)

Wenn Refresh tatsächlich ein HTTP-Header gewesen wäre, hätte man das natürlich auch in der HTTP-Response schicken müssen, was auch schöner gewesen wäre, aber Refresh ist kein Bestandteil von RFC 2616 (HTTP 1.1).

Hier nochmal das Skript in Aktion und der aktualisierte Gist.

Schöne Grüße und danke für die Erinnerung!
Mirko

Ähnliche Themen