Backbutton und Reload einschränken
stephan
- php
0 Ldi910 Jörg Peschke0 Stephan
0 Sven Rautenberg
Ich arbeite momentan an einem kleinen Shopsystem. Es ist eine PHP MySQL Anwendung, die Variablen werden per POST übergeben. Um ein versehentlichen Eintrag in den Warenkorb durch den Back- oder Reloadbutton zu verhindern, gebe ich einen Counter an jede Seite und an die Datenbank weiter. Der aktuelle Counter-Wert wird anschließend bei jedem Aufruf einer Seite mit dem Wert in der Datenbank verglichen und dann um eins erhöht. Ist der Aktuelle Wert kleiner oder gleich werden alle Shop relaventen Funktionen ignoriert.
Das Problem: der Backbutton ruft die vorherige Seite auch mit den alten Datenbankwerten auf. Kann man was dagegen tun?
Gibt es eine andere Lösung Reloads und HistoryBacks abzufangen?
Danke,
Stephan
[QUOTE]JavaScript erlaubt zum Schutz der Seitenbesucher nur einen begrenzten Zugriff auf das history-Objekt. Das bedeutet, Sie erhalten keinen Zugriff auf die URIs der besuchten Seitenadressen, und Sie können die History auch nicht löschen. Neben der Bewegung in der History ist es lediglich erlaubt, mit der Methode Seite location.replace() den history-Eintrag der zuletzt besuchten Seite zu überschreiben.[/QUOTE] Aus selfhtml
Der aktuelle Counter-Wert wird anschließend bei jedem Aufruf einer Seite mit dem Wert in der Datenbank verglichen und dann um eins erhöht. Ist der Aktuelle Wert kleiner oder gleich werden alle Shop relaventen Funktionen ignoriert.
Wo erhöhst Du Deinen Counter? Wenn Du es in der Datenbank tust, müsste es eigentlich schon gehen:
PHP-Seite sendet ihre zuletzt bekannte cnt- werte als "act_cntr" an die Datenbank.
Pseudo-Code:
var cntr = SELECT cntr FROM session
if (act_cnt != cntr) {
/* Ignore */
}
else {
UPDATE session SET cnt = cntr+1
/* Go ahead */
}
Hier mal der code:
function BackCheck()
{
#ob $site ^ counter gesetzt
if(!$_POST['site'])
{
#wenn nicht, dann auf 1 setzen
$site = '1';
}else{
#sonst Post holen
$site = $_POST['site'];
}
# counter/site wert aus der DB holen
$data = array();
$data = $this->callSQL("SELECT site FROM client WHERE id=".$_POST['c_id']);
#wenn aktueller wert kleiner gleich db wert
if($_POST['site']<=$data[0][0])
{
#echo "back!</br>";
$_POST['quantity']=NULL;
$site=$data[0][0];
}
#aktuellen counter/site wert in db schreiben
$this->callSQL("UPDATE client set site =".$site." WHERE id=".$_POST['c_id']);
#counter/site erhöhen
return $site++;
}
Moin!
Um ein versehentlichen Eintrag in den Warenkorb durch den Back- oder Reloadbutton zu verhindern, gebe ich einen Counter an jede Seite und an die Datenbank weiter. Der aktuelle Counter-Wert wird anschließend bei jedem Aufruf einer Seite mit dem Wert in der Datenbank verglichen und dann um eins erhöht. Ist der Aktuelle Wert kleiner oder gleich werden alle Shop relaventen Funktionen ignoriert.
Dabei verhinderst du möglicherweise, dass der Besucher parallel in mehreren Browserfenstern in deinem Shop surft und einkauft - nicht unbedingt die beste Lösung, denn es gibt bessere.
Gibt es eine andere Lösung Reloads und HistoryBacks abzufangen?
Die Sache ist recht simpel, ich möchte aber etwas ausholen:
Die erste Feststellung: Ob POST oder GET ist vollkommen egal. Beide Arten senden (teilweise individuell vom Benutzer eingegebene) Formular- oder Linkparameterdaten an den Server, und dieser arbeitet dann ein Skript ab, welches Dinge tut, und erstellt eine Seite als Antwort.
Logische Konsequenz: Werden dieselben Daten nochmal an den Server gesendet, wird natürlich dasselbe Skript mit denselben Aktionen nochmal ausgeführt.
Wenn also ein Shop eine Grafik mit "1x kaufen" verlinkt hat (GET-Request), und die Ergebnisseite die URL mit dem Parameter "?kaufe=produkt01" hat und ein "Danke für ihren Kauf" ausgibt, und diese Seite vom Besucher neu geladen wird, dann kauft er das Produkt mehrfach. Dabei ist aber nicht unterscheidbar, ob er
a) absichtlich oder unabsichtlich die Reloadtaste gedrückt hat, oder
b) die Back-Taste gedrückt und den Kaufen-Link erneut geklickt hat, oder
c) über die normale Shop-Navigation zum Kaufen-Link weitergegangen und ihn erneut geklickt hat (wenn man voraussetzt, dass alle dabei besuchten Seiten schon im Browsercache sind, und nicht neu vom Server angefordert werden, merkt der Server davon nichts.
Um zu verhindern, dass sich die Kaufen-Aktion neuladbar im Browser hinterläßt, ist meine schon seit langer Zeit geäußerte Empfehlung: Der Skriptaufruf, der den Kauf veranlaßt (oder den Mailversand, oder sonst irgendeine Aktion, die wirklich nur einmal ablaufen soll), darf als Antwort an den Besucher KEINE vollständige HTML-Seite liefern, sondern NUR eine Weiterleitung auf eine andere Seite. Beispielsweise auf eine allgemeine "Danke für ihren Kauf"-Seite, die im Zweifel (egal ob über URL-Parameter, oder vom Kaufen-Skript in der Session gespeichert) irgendwie die Information erhält, was denn tatsächlich die letzte Aktion war, für die man sich bedanken soll, oder deren korrekte Ausführung dem Besucher zu bestätigen ist.
Mit dem Redirect schlägt man zwei Fliegen mit einer Klappe: Erstens bleibt im Browser nur eine Seite stehen, die man problemlos neu laden kann, ohne die eigentliche Aktion doppelt auszuführen.
Zweitens bleibt auch in der History keine Seite stehen, die die Aktion erneut ausführt - die Benutzung des Back-Buttons führt von der "Danke"-Seite direkt zurück zu der Seite, die VOR dem Aktionsstart aufgerufen wurde. Von dort aus kann man natürlich das ganze nochmal aufrufen - aber nicht unabsichtlich.
- Sven Rautenberg
Erstmal vielen Dank für die ausführliche Antwort.
Das Prinzip mit der zweiten Seite ist mir bekannt, nur passt sie nicht in das Konzept für die Seite, wurde von vornherein für nicht akzeptabel eingestuft. Ziel ist nun mal leider so wenig Klicks wie möglich. Für eine genauere Bearbeitung der Artikel ist der Warenkorb zuständig. Post verwende ich aus den Aspekten der Sicherheit, man soll wenigstens nicht sofort erkennen durch welche Variablen und Werte der Shop gesteuert wird. Deswegen auch der Umweg mit einem Seiten-Counter pro Besucher des Shops. Das Problem in diesem Prinzip ist wohl, das die Seiten in der History als HTML gespeichert werden, wenn ich mich nicht irre. Also es findet keine Kommunikation mit dem Server statt, womit auch keine aktuelle Datenbankabfrage möglich ist. Sehe ich das richtig? Ich kann leider keinen Code anfühgen, da alles objektorientiert programmiert ist.
gruß,
stephan
Moin!
Das Prinzip mit der zweiten Seite ist mir bekannt, nur passt sie nicht in das Konzept für die Seite, wurde von vornherein für nicht akzeptabel eingestuft. Ziel ist nun mal leider so wenig Klicks wie möglich.
Wieso Klicks? Im einfachsten Fall teilst du deine jetzige Arbeitsweise des Skriptes in zwei Schritte auf. Schritt 1 erledigt die Verarbeitung des POSTs und leitet zu Schritt 2 weiter, und dieser Schritt gibt dann das HTML an den Benutzer zurück, welches schon jetzt ausgegeben würde.
Das verbraucht absolut keinen einzigen Klick zusätzlich beim Benutzer.
Für eine genauere Bearbeitung der Artikel ist der Warenkorb zuständig. Post verwende ich aus den Aspekten der Sicherheit, man soll wenigstens nicht sofort erkennen durch welche Variablen und Werte der Shop gesteuert wird. Deswegen auch der Umweg mit einem Seiten-Counter pro Besucher des Shops. Das Problem in diesem Prinzip ist wohl, das die Seiten in der History als HTML gespeichert werden, wenn ich mich nicht irre. Also es findet keine Kommunikation mit dem Server statt, womit auch keine aktuelle Datenbankabfrage möglich ist. Sehe ich das richtig?
Richtig. Bewegung in der History läuft ohne Serverkommunikation ab. Deshalb ja auch der Vorteil der Weiterleitung: Die ursprünglich aufgerufene Seite erhält keinen Platz in der History, also werden die dadurch ausgeführten Shopaktionen auch nicht erneut aufgerufen.
- Sven Rautenberg