Wiki-Artikel Reloadsperre
Matthias Apsel
- php
- programmiertechnik
- selfhtml-wiki
Hallo alle,
ich habe heute zufällig den Artikel zur Reloadsperre von 2013 gefunden. Was müsste geändert werden, damit der in den Hauptnamensraum darf?
Bis demnächst
Matthias
Hallo Matthias,
ich habe heute zufällig den Artikel zur Reloadsperre von 2013 gefunden. Was müsste geändert werden, damit der in den Hauptnamensraum darf?
Der Teil mit der Weiterleitung muss überarbeitet werden: wenn man History Back klickt, gelangt man nicht zum POST
-Request, sondern zum vorhergehenden GET
-Request. Die beiden anderen Methoden funktionieren weiterhin, allerdings hat sich der Redirect nach dem POST
als best practice herausgestellt.
LG,
CK
Hallo Christian Kruse,
wenn man History Back klickt, gelangt man nicht zum
POST
-Request, sondern zum vorhergehendenGET
-Request.
Hm. Die Screenshots hab ich mir ja nicht ausgedacht. Und wenn ich mich recht erinnere, gelingt es tatsächlich, das Formular erneut abzusenden.
Bis demnächst
Matthias
Hallo Matthias,
wenn man History Back klickt, gelangt man nicht zum
POST
-Request, sondern zum vorhergehendenGET
-Request.Hm. Die Screenshots hab ich mir ja nicht ausgedacht. Und wenn ich mich recht erinnere, gelingt es tatsächlich, das Formular erneut abzusenden.
Dinge ändern sich. Früher war das so - heute nicht mehr.
Auf diesem Prinzip basieren viele Web-Anwendungen, im Rails-Framework, im Django-Framework, im Zend-Framework – überall wird dieses Prinzip so genutzt. Du kannst es hier im Forum ja selber mal testen. Die letzte Zeile im Messages-Controller:
redirect_to message_url(@thread, @message), :notice => I18n.t('messages.created')
LG,
CK
Hallo Christian Kruse,
Auf diesem Prinzip basieren viele Web-Anwendungen, im Rails-Framework, im Django-Framework, im Zend-Framework – überall wird dieses Prinzip so genutzt. Du kannst es hier im Forum ja selber mal testen. Die letzte Zeile im Messages-Controller:
redirect_to message_url(@thread, @message), :notice => I18n.t('messages.created')
Aber mit einem redirect allein bin ich offenbar trotzdem noch nicht auf der sicheren Seite. Versuche etwa dieses Formular.
Bis demnächst
Matthias
Hallo Matthias,
Aber mit einem redirect allein bin ich offenbar trotzdem noch nicht auf der sicheren Seite. Versuche etwa dieses Formular.
Da findet kein Redirect statt.
LG,
CK
Hallo Christian Kruse,
Da findet kein Redirect statt.
Dann reden wir wohl (wieder mal) aneinander vorbei ;-)
Im Artikel heißt es: „Wenn die Daten nicht eindeutig sein müssen, wird häufig empfohlen, auf eine Seite weiterzuleiten, die nicht das Formular enthält, sondern lediglich eine Mitteilung darüber, dass die Übertragung der Daten erfolgreich war.“
Genau das passiert doch in meinem Beispiel??
Bis demnächst
Matthias
Hallo Matthias,
Dann reden wir wohl (wieder mal) aneinander vorbei ;-)
Ich glaube nicht.
Im Artikel heißt es: „Wenn die Daten nicht eindeutig sein müssen, wird häufig empfohlen, auf eine Seite weiterzuleiten, die nicht das Formular enthält, sondern lediglich eine Mitteilung darüber, dass die Übertragung der Daten erfolgreich war.“
Genau das passiert doch in meinem Beispiel??
Nein, es wird nur eine Efolgsmeldung auf den POST-Request ausgeliefert (Status 200), siehe Screenshot. Es muss aber ein redirect stattfinden (Status 302), das weiterleiten aus dem obigen Text fehlt. Pseudo-Code von dem, was in deinem Form-Mailer passiert:
parseData();
createDatabaseEntry();
sendSuccessResponse();
Was passieren müsste:
parseData();
createDatabaseEntry();
sendRedirect(status: 302, url: '/foo/bar');
LG,
CK
Hallo Christian Kruse,
Nein, es wird nur eine Efolgsmeldung auf den POST-Request ausgeliefert (Status 200), siehe Screenshot. Es muss aber ein redirect stattfinden (Status 302), das weiterleiten aus dem obigen Text fehlt.
Danke. Das war mir in der Deutlichkeit nicht klar.
Was passieren müsste:
parseData(); createDatabaseEntry(); sendRedirect(status: 302, url: '/foo/bar');
Und wenn das so gemacht wird, sollte ich nicht mehr entsprechend der Screenshots (aus dem Wiki-Artikel) gefragt werden ob ich die Daten erneut absenden möchte, falls ich den zurück-Button des Browsers verwende?
Bis demnächst
Matthias
Hallo Matthias,
parseData(); createDatabaseEntry(); sendRedirect(status: 302, url: '/foo/bar');
Und wenn das so gemacht wird, sollte ich nicht mehr entsprechend der Screenshots (aus dem Wiki-Artikel) gefragt werden ob ich die Daten erneut absenden möchte, falls ich den zurück-Button des Browsers verwende?
Ich finde deine Formulierung ein wenig verwirrend, deshalb formuliere ich das Verhalten, dass Browser an den Tag legen:
Wenn ein Server auf einen POST
-Request mit einem 302 antwortet und der User dann History Back auslöst, dann wird der POST
-Request nicht wiederholt sondern man kehrt zur vorhergehenden GET
-Ressource zurück. Du kannst das aber immer noch gerne hier im Forum testen, du kehrst dann zu /new
zurück ;-)
LG,
CK
Hallo Christian Kruse,
Ich finde deine Formulierung ein wenig verwirrend,
siehste, doch ein wenig an einander vorbei ;-)
Wenn ein Server auf einen
POST
-Request mit einem 302 antwortet und der User dann History Back auslöst, dann wird derPOST
-Request nicht wiederholt sondern man kehrt zur vorhergehendenGET
-Ressource zurück. Du kannst das aber immer noch gerne hier im Forum testen, du kehrst dann zu/new
zurück ;-)
Teste ich.
Bis demnächst
Matthias
Hallo Christian Kruse,
Ich finde deine Formulierung ein wenig verwirrend,
siehste, doch ein wenig an einander vorbei ;-)
Wenn ein Server auf einen
POST
-Request mit einem 302 antwortet und der User dann History Back auslöst, dann wird derPOST
-Request nicht wiederholt sondern man kehrt zur vorhergehendenGET
-Ressource zurück. Du kannst das aber immer noch gerne hier im Forum testen, du kehrst dann zu/new
zurück ;-)
Teste ich.
Bis demnächst
Matthias
Hallo Matthias Apsel, @Christian Kruse
Wenn ein Server auf einen
POST
-Request mit einem 302 antwortet und der User dann History Back auslöst, dann wird derPOST
-Request nicht wiederholt sondern man kehrt zur vorhergehendenGET
-Ressource zurück. Du kannst das aber immer noch gerne hier im Forum testen, du kehrst dann zu/new
zurück ;-)Teste ich.
So. Zwei identische Nachrichten. Ich schrieb ja auch nicht, dass der Request automatisch wiederholt wird, sondern dass man ihn wiederholen kann.
Bis demnächst
Matthias
Hallo Matthias,
So. Zwei identische Nachrichten. Ich schrieb ja auch nicht, dass der Request automatisch wiederholt wird, sondern dass man ihn wiederholen kann.
Nein, du schriebst von einer Reload-Sperre. History back und das formular händisch erneut absenden (mit ggfls einigen Änderungen) ist ein valider Anwendungsfall und fällt nicht in das Thema Reloadsperre.
LG,
CK
Hallo Christian Kruse,
Nein, du schriebst von einer Reload-Sperre. History back und das formular händisch erneut absenden (mit ggfls einigen Änderungen) ist ein valider Anwendungsfall und fällt nicht in das Thema Reloadsperre.
Ok. Also ist auch der Abschnitt Weiterleitung prinzipiell richtig?
Übrigens wird dann auch mit Status 200 das Formular nicht automatisch erneut abgesendet.
Bis demnächst
Matthias
Hallo Matthias,
Ok. Also ist auch der Abschnitt Weiterleitung prinzipiell richtig?
Nein. Die Meldung aus deinen Screenshots gibt es nicht bei einem 302.
Übrigens wird dann auch mit Status 200 das Formular nicht automatisch erneut abgesendet.
Doch. Bei einem Status 200 auf einen POST
wird bei einem Reload der POST
-Request wiederholt – und in diesem Fall wird auch eine entsprechende Meldung bei einem History Back gezeigt.
Ich versuche das nochmal zu skizzieren, mir scheint das Verhalten ist noch nicht klar.
GET
-Request auf das Formular)LG,
CK
Hallo Christian Kruse,
Ich versuche das nochmal zu skizzieren, mir scheint das Verhalten ist noch nicht klar.
Mir scheint, die (mein) Browser verhalten sich anders als sie sollten, zumindest anders als du es beschreibst. Schade, dass wir in Erfurt nicht darüber sprechen können.
Vielleicht fehlen mir auch wieder die korrekten Fachtermini.
Bis demnächst
Matthias
Hallo Matthias,
Ich versuche das nochmal zu skizzieren, mir scheint das Verhalten ist noch nicht klar.
Mir scheint, die (mein) Browser verhalten sich anders als sie sollten, zumindest anders als du es beschreibst.
Das bezweifle ich ;-) Aber mach doch mal ein Video oder eine Screenshot-Serie, dann kann man nachvollziehen was du meinst.
Schade, dass wir in Erfurt nicht darüber sprechen können.
Finde ich auch.
LG,
CK
Hallo Christian Kruse,
Das bezweifle ich ;-) Aber mach doch mal ein Video oder eine Screenshot-Serie, dann kann man nachvollziehen was du meinst.
Ok. Fehler im Kommunikationsprotokoll gefunden ;-)
Das, was du beschreibst trifft für die Seite zu, auf die man gelangt, nachdem das Formular abgesendet wurde. Was allerdings immer möglich ist: Ich kann durch Verwenden des Zurückbuttons wieder zu der Seite mit dem schon ausgefüllten Formular gelangen und es von dort erneut absenden.
Bis demnächst
Matthias
Hi,
Das, was du beschreibst trifft für die Seite zu, auf die man gelangt, nachdem das Formular abgesendet wurde.
genau, denn dort ist man per Redirect hingekommen, und diese Seite wurde dann vom Browser mit GET angefordert. Die kann man auch beliebig oft neu laden, bis man keine Lust mehr hat. ;-)
Was allerdings immer möglich ist: Ich kann durch Verwenden des Zurückbuttons wieder zu der Seite mit dem schon ausgefüllten Formular gelangen und es von dort erneut absenden.
Das wiederum kann klappen, muss aber nicht. Ob beim Zurück-Navigieren die Formularinhalte noch da sind oder nicht, ist von den Browser-Einstellungen abhängig. Und davon, was in der Zwischenzeit so alles im Browser-Cache passiert ist.
Ciao,
Martin
Hallo
Was allerdings immer möglich ist: Ich kann durch Verwenden des Zurückbuttons wieder zu der Seite mit dem schon ausgefüllten Formular gelangen und es von dort erneut absenden.
Das wiederum kann klappen, muss aber nicht. Ob beim Zurück-Navigieren die Formularinhalte noch da sind oder nicht, ist von den Browser-Einstellungen abhängig.
… und im Falle des Falles, wie in dem, den Christian beschreibt, so gewollt. Das erneute absenden des Formularinhalts, so noch vorhanden, bedarf dann ja einer bewussten Aktion und geschieht nicht „aus Versehen“.
Tschö, Auge
Hallo Auge,
Das erneute absenden des Formularinhalts, so noch vorhanden, bedarf dann ja einer bewussten Aktion und geschieht nicht „aus Versehen“.
Exakt, danke für die bessere Formulierung.
LG,
CK
Hallo Matthias,
Das, was du beschreibst trifft für die Seite zu, auf die man gelangt, nachdem das Formular abgesendet wurde. Was allerdings immer möglich ist: Ich kann durch Verwenden des Zurückbuttons wieder zu der Seite mit dem schon ausgefüllten Formular gelangen und es von dort erneut absenden.
Ja, wie ich bereits sagte: das ist ein valider Anwendungsfall und nicht das Thema einer Reload-Sperre. Das ist als wenn der User erneut zum Formular navigiert und dort alles nochmal einträgt und nochmal absendet. Wenn man doppelte Einsendungen vermeiden will, dann hilft keine der benannten Methoden, sondern nur in der Datenbank nachschauen ob ein Datensatz mit identischen Werten bereits existiert.
LG,
CK, prokrastinierend ;-)
wenn man History Back klickt, gelangt man nicht zum
POST
-Request, sondern zum vorhergehendenGET
-Request.Hm. Die Screenshots hab ich mir ja nicht ausgedacht. Und wenn ich mich recht erinnere, gelingt es tatsächlich, das Formular erneut abzusenden.
Dinge ändern sich. Früher war das so - heute nicht mehr.
Hmm... Wie lange soll das denn her sein? Ich meine, dass vor ca. 10 Jahren schon mal so implementiert zu haben - ohne Probleme.
Hallo Mitleser,
Hmm... Wie lange soll das denn her sein? Ich meine, dass vor ca. 10 Jahren schon mal so implementiert zu haben - ohne Probleme.
Sehr lange - Netscape 3? Ich glaube, das könnte hinkommen, aber ich bin mir nicht sicher.
LG,
CK
Hallo Christian Kruse,
Die beiden anderen Methoden funktionieren weiterhin,
Kannst du bitte noch mal über den Teil 1 schauen?
Bis demnächst
Matthias
Hallo Matthias,
Die beiden anderen Methoden funktionieren weiterhin,
Kannst du bitte noch mal über den Teil 1 schauen?
Autowert… urghs. ;-)
$id_check -> bindParam(':BName', $_POST['bname']);
$id_check -> execute();
Ich würde hier lieber die Parameter an execute()
übergeben, das ist einfacher lesbar:
$id_check -> execute(array(':BName' => $_POST['bname']));
Das gleiche weiter unten. Weiter:
if(isset($benutzer['ID'])) array_push($fehler,'Dieser Benutzer existiert schon.');
Diese Notation ist gefährlich, siehe goto fail
- ich würde immer Klammern nutzen. In dem INSERT
hast du einen Quoting-Fehler: "Ich"
, es müsste aber \"Ich\"
sein (SQL embedded in PHP).
Bzgl des Inhalts: ich würde mir die Bemerkung über natürliche Primärschlüssel sparen: es macht den Satz schlechter lesbar, tut hier nichts zur Sache und der Wahrheitsgehalt ist mindestens strittig (um natürliche vs künstliche Primärschlüssel existiert seit Ewigkeiten eine leidenschaftliche Diskussion). Bei den Error-Codes würde ich explizit MySQL erwähnen, vllt im Stile von „so lauten der Error-Code und die entsprechende Fehlermeldung bei MySQL“ oder so.
Ansonsten sieht das gut aus.
LG,
CK
Hallo Christian Kruse,
Autowert… urghs. ;-)
Ich bin dabei ;-)
$id_check -> bindParam(':BName', $_POST['bname']); $id_check -> execute();
Ich würde hier lieber die Parameter an
execute()
übergeben, das ist einfacher lesbar:$id_check -> execute(array(':BName' => $_POST['bname']));
Ist damit auch der Kontextwechsel abgesichert? bindParam
sorgt ja auch dafür, dass eben nicht mehr mysql_real_escape_string()
o. ä. verwendet werden muss oder sehe ich das falsch und das macht schon das prepare
?
Ansonsten sieht das gut aus.
:-)
Bis demnächst
Matthias
Hallo Matthias,
Ich würde hier lieber die Parameter an
execute()
übergeben, das ist einfacher lesbar:$id_check -> execute(array(':BName' => $_POST['bname']));
Ist damit auch der Kontextwechsel abgesichert?
Ja. Das ist ein Shortcut für bindValue
.
bindParam
sorgt ja auch dafür, dass eben nicht mehrmysql_real_escape_string()
o. ä. verwendet werden muss oder sehe ich das falsch und das macht schon dasprepare
?
Das macht das Konzept der prepared statements mit placeholders, ja. Wobei bei PostgreSQL das gleiche Konzept auf für normale Statements existiert (Stichwort EXECUTE
). Das bindParam
ist nur ein Konzept, um prepared statements in Loops zu optimieren. Die Variablen werden via Referenz an den Parameter gebunden und können vor dem execute
nochmal geändert werden. Das erlaubt es, das bindParam
vor dem Loop einmal auszuführen und im Loop nur noch den Wert der Variablen zu ändern:
create table foo (bar int);
$db = new PDO("pgsql:host=localhost;dbname=test");
$bar = 0;
$stmt = $db->prepare("INSERT INTO foo (bar) VALUES (:bar)");
$stmt->bindParam(':bar', $bar);
for($bar = 0; $bar < 10; $bar++) {
$stmt->execute();
}
test=# select * from foo;
bar
-----
0
1
2
3
4
5
6
7
8
9
(10 rows)
LG,
CK
Hallo Christian Kruse,
Ist damit auch der Kontextwechsel abgesichert?
Ja. Das ist ein Shortcut für
bindValue
.
Danke für die ausführliche Erläuterung.
[
bindParam
: ] Die Variablen werden via Referenz an den Parameter gebunden.
Deshalb kann man in Schleifen eben nicht bindValue
verwenden, weil da der zum Zeitpunkt des Aufrufs aktuelle Variablenwert an den Parameter gebunden wird - richtig?
Falls du magst, könntest du noch mal über die Endfassung schauen.
Bis demnächst
Matthias
Hallo Matthias,
bindParam
: Die Variablen werden via Referenz an den Parameter gebunden.Deshalb kann man in Schleifen eben nicht
bindValue
verwenden, weil da der zum Zeitpunkt des Aufrufs aktuelle Variablenwert an den Parameter gebunden wird - richtig?
Doch, können sie: aber halt bei jedem Schleifenaufruf erneut :-) Weil, wie du korrekt erkannst hast, bindValue
den Wert der Expression an den Parameter bindet.
Falls du magst, könntest du noch mal über die Endfassung schauen.
Sieht gut aus, mir gefallen die Änderungen. Jetzt noch zum dritten Teil: üblich ist hier nicht, das Token in der Session zu speichern, sondern in einer Spalte bei dem Datum mit einem UNIQUE
-Constraint. Sonst muss man das Token bei jedem Formular-Aufruf neu generieren und in der Session ändern; und wenn man das macht, ist man auch nicht mehr wirklich gegen einen Reload geschützt: ich rufe das Formular erneut auf, das Token ändert sich, ich lade die Seite mit dem POST
-Request neu, das Token unterscheidet sich - zack, doppelter Datensatz.
Speichert man es bei dem Datum, hat man dieses Problem nicht.
LG,
CK
Hallo Christian Kruse,
Jetzt noch zum dritten Teil: üblich ist hier nicht, das Token in der Session zu speichern, sondern in einer Spalte bei dem Datum mit einem
UNIQUE
-Constraint.
Ok. Verstehe.
Sonst muss man das Token bei jedem Formular-Aufruf neu generieren und in der Session ändern; und wenn man das macht, ist man auch nicht mehr wirklich gegen einen Reload geschützt: ich rufe das Formular erneut auf, das Token ändert sich, ich lade die Seite mit dem
POST
-Request neu, das Token unterscheidet sich - zack, doppelter Datensatz.
Aber das muss man ja auch schon absichtlich machen. Zum Beispiel in zwei Browsertabs das Formular öffnen, es nur in einem abschicken und dann in beiden Tabs F5 drücken.
Bis demnächst
Matthias
Hallo Matthias,
Sonst muss man das Token bei jedem Formular-Aufruf neu generieren und in der Session ändern; und wenn man das macht, ist man auch nicht mehr wirklich gegen einen Reload geschützt: ich rufe das Formular erneut auf, das Token ändert sich, ich lade die Seite mit dem
POST
-Request neu, das Token unterscheidet sich - zack, doppelter Datensatz.Aber das muss man ja auch schon absichtlich machen. Zum Beispiel in zwei Browsertabs das Formular öffnen, es nur in einem abschicken und dann in beiden Tabs F5 drücken.
Vielleicht, aber nicht mit dem Wunsch den Reload zu umgehen. Meinem Chef passiert das öfter, einfach weil er gerne schonmal den Überblick über seine Browser-Tabs verliert. Und durch mangelnde Geduld wird dann halt einfach CMD+r gedrückt. Bei uns ist das allerdings idR kein Problem, dem Redirect sei dank ;-)
LG,
CK
Hallo Christian Kruse,
Sieht gut aus, mir gefallen die Änderungen. Jetzt noch zum dritten Teil: üblich ist hier nicht, das Token in der Session zu speichern, sondern in einer Spalte bei dem Datum mit einem
UNIQUE
-Constraint. Sonst muss man das Token bei jedem Formular-Aufruf neu generieren und in der Session ändern; und wenn man das macht, ist man auch nicht mehr wirklich gegen einen Reload geschützt: ich rufe das Formular erneut auf, das Token ändert sich, ich lade die Seite mit demPOST
-Request neu, das Token unterscheidet sich - zack, doppelter Datensatz.
Ich bin (immer noch nicht sicher | jetzt wieder unsicher), ob das so stimmt:
Bis demnächst
Matthias
Hallo Matthias,
- Formular wird im 1. Tab geladen -> $_POST-token = foo
- Formular wird im 2. Tab geladen -> $_POST-token = bar
- Formular wird im 2. Tab abgeschickt -> $_SESSION-token = bar
- 1. Tab wird refreshed -> $_POST-token = quz
- 2. Tab wird refreshed -> $_POST-token = $_SESSION-token = bar
- => keine erneute Eintragung
Das ist nicht das Szenario, das ich skizziert habe ;)
LG,
CK
Hallo Christian Kruse,
Das ist nicht das Szenario, das ich skizziert habe ;)
Ok. Aus deiner Skizze konnte ich aber das Szenario nicht entnehmen ;-)
Aber das leuchtet ein.
Bis demnächst
Matthias
Hallo Christian Kruse,
Falls du magst, könntest du noch mal über die Endfassung schauen.
Jetzt noch zum dritten Teil: üblich ist hier nicht, das Token in der Session zu speichern, sondern in einer Spalte bei dem Datum mit einem
UNIQUE
-Constraint.
Ich habe noch folgendes ergänzt:
„Allerdings könnte es unter Umständen, etwa wenn mehrere Tabs oder Browserfenster im Spiel sind, immer noch passieren, dass die Daten versehentlich erneut abgesendet werden.
Um dies zu umgehen, können Sie statt in der Session das Token auch als eindeutigen Wert in die Datenbank schreiben. Die Datenbankoperationen würden dann wie im ersten Abschnitt umgesetzt werden.“
Bis demnächst
Matthias
Hallo Matthias,
„Allerdings könnte es unter Umständen, etwa wenn mehrere Tabs oder Browserfenster im Spiel sind, immer noch passieren, dass die Daten versehentlich erneut abgesendet werden.
Um dies zu umgehen, können Sie statt in der Session das Token auch als eindeutigen Wert in die Datenbank schreiben. Die Datenbankoperationen würden dann wie im ersten Abschnitt umgesetzt werden.“
Wäre es nicht sinnvoller, den Absatz zu streichen und den ersten Absatz umzuschreiben, so dass man nur die Variante mit dem UNIQUE
-Constraint hat? Die Session-Variante hab ich in freier Wildbahn so noch nicht gesehen, und mir erscheint sie auch nicht unbedingt einen Vorteil zu bieten, eher im Gegenteil.
Just my 2 cents.
LG,
CK
Hallo Christian Kruse,
Die Session-Variante hab ich in freier Wildbahn so noch nicht gesehen,
Ich werde doch nicht etwa der Erfinder dieser Variante sein?
und mir erscheint sie auch nicht unbedingt einen Vorteil zu bieten, eher im Gegenteil.
das spräche dafür.
Wäre es nicht sinnvoller, den […] ersten Absatz umzuschreiben, so dass man nur die Variante mit dem UNIQUE-Constraint hat?
Also auch auf die Erläuterungen mit den Primärschlüsseln verzichten? Denn das Token als UNIQUE-Constraint-Spalte in die DB einzutragen entspricht ja eigentlich dem, was unter natürliche Primärschlüssel beschrieben ist.
Bis demnächst
Matthias
Hallo Matthias,
Die Session-Variante hab ich in freier Wildbahn so noch nicht gesehen,
Ich werde doch nicht etwa der Erfinder dieser Variante sein?
Das kann ich nicht beurteilen :-)
Wäre es nicht sinnvoller, den […] ersten Absatz umzuschreiben, so dass man nur die Variante mit dem UNIQUE-Constraint hat?
Also auch auf die Erläuterungen mit den Primärschlüsseln verzichten?
Nicht aus dem Kontext reissen ;-) ich bezog mich vollständig auf den dritten Teil des Artikels. Ich würde Teil 1 und Teil 2 lassen und in Teil 3 ein künstliches UNIQUE
-Constraint vorstellen, denn das unterscheidet sich ja schon deutlich von einem Primärschlüssel.
Denn das Token als UNIQUE-Constraint-Spalte in die DB einzutragen entspricht ja eigentlich dem, was unter natürliche Primärschlüssel beschrieben ist.
Der Grundgedanke ist der Gleiche, ja - ist er aber ja auch bei der Variante mit den Sessions. Ich betrachte ein eindeutiges Kriterium um zu prüfen, ob ich die Daten schonmal hatte.
LG,
CK
Hallo Christian Kruse,
Nicht aus dem Kontext reissen ;-) ich bezog mich vollständig auf den dritten Teil des Artikels.
Ah. OK. Das hatte ich nicht so verstanden.
Bis demnächst
Matthias
Hallo Christian Kruse,
Ich würde Teil 1 und Teil 2 lassen und in Teil 3 ein künstliches
UNIQUE
-Constraint vorstellen, denn das unterscheidet sich ja schon deutlich von einem Primärschlüssel.
Naja, so groß sind die Unterschiede ja nun wirklich nicht. Beide fordern die Eindeutigkeit der entsprechenden Spalten, bei UNIQUE
ist NULL
(für jede beteiligte Spalte) genau einmal erlaubt, bei PRIMARY KEY
nicht. Damit ist eine UNIQUE
-Spalte doch auch nur ein Zweit- oder Drittschlüssel.
Denn das Token als UNIQUE-Constraint-Spalte in die DB einzutragen entspricht ja eigentlich dem, was unter natürliche Primärschlüssel beschrieben ist.
Der Grundgedanke ist der Gleiche, ja - ist er aber ja auch bei der Variante mit den Sessions. Ich betrachte ein eindeutiges Kriterium um zu prüfen, ob ich die Daten schonmal hatte.
Hebt man denn die Tokens bis in alle Ewigkeit auf? Denn es könnte ja nun passieren, dass identische Tokens generiert werden. (Wenn die Wahrscheinlichkeit doch auch sehr klein ist) Speichert man da zusätzlich noch einen Zeitstempel mit und setzt man Token und Zeitstempel zusammen auf UNIQUE
Oder macht man sich um diesen praktisch nur theoretisch (sic) auftretenden Fall keine Gedanken?
Bis demnächst
Matthias
Hallo Matthias,
Ich würde Teil 1 und Teil 2 lassen und in Teil 3 ein künstliches
UNIQUE
-Constraint vorstellen, denn das unterscheidet sich ja schon deutlich von einem Primärschlüssel.Naja, so groß sind die Unterschiede ja nun wirklich nicht. Beide fordern die Eindeutigkeit der entsprechenden Spalten, bei
UNIQUE
istNULL
(für jede beteiligte Spalte) genau einmal erlaubt, beiPRIMARY KEY
nicht. Damit ist eineUNIQUE
-Spalte doch auch nur ein Zweit- oder Drittschlüssel.
Was?? Nein, NULL != NULL
ist wahr, du kannst soviele NULL
-Werte einfügen wie du willst:
MariaDB [test]> CREATE TABLE foo(bar INT UNIQUE);
Query OK, 0 rows affected (0.05 sec)
MariaDB [test]> INSERT INTO foo (bar) VALUES (NULL);
Query OK, 1 row affected (0.01 sec)
MariaDB [test]> INSERT INTO foo (bar) VALUES (NULL);
Query OK, 1 row affected (0.01 sec)
MariaDB [test]> INSERT INTO foo (bar) VALUES (NULL);
Query OK, 1 row affected (0.01 sec)
MariaDB [test]> INSERT INTO foo (bar) VALUES (NULL);
Query OK, 1 row affected (0.00 sec)
MariaDB [test]> SELECT * FROM foo;
+------+
| bar |
+------+
| NULL |
| NULL |
| NULL |
| NULL |
+------+
4 rows in set (0.00 sec)
MariaDB [test]>
Das gilt für MySQL und PostgreSQL auch, nur MS SQL ist da kaputt und hält sich nicht an den Standard.
Mir ging es aber auch um den logischen Unterschied, nicht um den technischen.
Denn das Token als UNIQUE-Constraint-Spalte in die DB einzutragen entspricht ja eigentlich dem, was unter natürliche Primärschlüssel beschrieben ist.
Der Grundgedanke ist der Gleiche, ja - ist er aber ja auch bei der Variante mit den Sessions. Ich betrachte ein eindeutiges Kriterium um zu prüfen, ob ich die Daten schonmal hatte.
Hebt man denn die Tokens bis in alle Ewigkeit auf?
Ja.
Denn es könnte ja nun passieren, dass identische Tokens generiert werden. (Wenn die Wahrscheinlichkeit doch auch sehr klein ist) Speichert man da zusätzlich noch einen Zeitstempel mit und setzt man Token und Zeitstempel zusammen auf
UNIQUE
Oder macht man sich um diesen praktisch nur theoretisch (sic) auftretenden Fall keine Gedanken?
Man nutzt eine Funktion, die einem mehr oder weniger garantiert, dass die ID nur einmal auftreten kann. In anderen Sprachen wäre das eine UUID oder eine GUID, in PHP muss man dafür auf uniqueid()
zurückgreifen; da die Funktion aber eine Funktion der Zeit ist, sollte das hier auch gegeben sein. Kollisionen werden damit so unwahrscheinlich, dass man sie ignoriert. Wenn man es aber richtig[tm] machen will, setzt man die Spalte regelmäßig auf NULL
oder so, ja.
LG,
CK
Hallo Christian Kruse,
Was?? Nein,
NULL != NULL
ist wahr, du kannst sovieleNULL
-Werte einfügen wie du willst:
Das gilt für MySQL und PostgreSQL auch, nur MS SQL ist da kaputt und hält sich nicht an den Standard.
Aha. Auch das war mir nicht bewusst.
Mir ging es aber auch um den logischen Unterschied, nicht um den technischen.
Der da wäre? Dass über die Primärschlüssel die referentielle Integrität abgesichert wird, ist ja auch eher technisch,
Oder macht man sich um diesen praktisch nur theoretisch (sic) auftretenden Fall keine Gedanken?
Kollisionen werden damit so unwahrscheinlich, dass man sie ignoriert. Wenn man es aber richtig[tm] machen will, setzt man die Spalte regelmäßig auf
NULL
oder so, ja.
Das fällt dann aber unter Datenbankhygiene, oder?
Bis demnächst
Matthias
Hallo Matthias,
Was?? Nein,
NULL != NULL
ist wahr, du kannst sovieleNULL
-Werte einfügen wie du willst:Das gilt für MySQL und PostgreSQL auch, nur MS SQL ist da kaputt und hält sich nicht an den Standard.
Aha. Auch das war mir nicht bewusst.
Es ist auch nicht besonders logisch, finde ich… ;-)
Mir ging es aber auch um den logischen Unterschied, nicht um den technischen.
Der da wäre? Dass über die Primärschlüssel die referentielle Integrität abgesichert wird, ist ja auch eher technisch,
Der Primärschlüssel identifiziert einen Datensatz eindeutig, die Aufgabe der Unique-ID ist es den Request eindeutig zu identifizieren.
Edit: was ich damit meine: der PK ist somit oft erst nach dem INSERT
bekannt, die UID zwangsläufig immer vorher.
Oder macht man sich um diesen praktisch nur theoretisch (sic) auftretenden Fall keine Gedanken?
Kollisionen werden damit so unwahrscheinlich, dass man sie ignoriert. Wenn man es aber richtig[tm] machen will, setzt man die Spalte regelmäßig auf
NULL
oder so, ja.Das fällt dann aber unter Datenbankhygiene, oder?
IMHO ja.
LG,
CK
Hallo Christian Kruse,
Edit: was ich damit meine: der PK ist somit oft erst nach dem
INSERT
bekannt, die UID zwangsläufig immer vorher.
Ja, das ist einleuchtend.
Ich habe den 3. Abschnitt deutlich gekürzt und den Artikel in den Hauptnamensraum verschoben. Hast du noch Anmerkungen?
Danke noch mal für deine Geduld.
Bis demnächst
Matthias
Hallo Matthias,
Ich habe den 3. Abschnitt deutlich gekürzt und den Artikel in den Hauptnamensraum verschoben. Hast du noch Anmerkungen?
Sieht gut aus, IMHO.
Danke noch mal für deine Geduld.
Äh… gerne? ;)
LG,
CK
Der Page-Token ist bei Doppelklicks wirkungslos, weil er immer noch derselbe ist. Eine Checksum der gesendeten Daten in die Session schreiben ist der richtige Weg. Idealerweise mit dem URL der Seite als Schlüssel (ein Page-Token kann manipuliert werden, der url nicht).
Und wenns dann doch in MySQL ankommt -- MySQL kann auch Checksummen bilden.
Und dann wäre noch die Möglichkeit, eine Checksumme mit JS zu erzeugen und mitzuzählen, wie oft Daten mit dieser Checksum submittet wurden.
MfG