Hash-Wert von Array immer ein anderer

  • Vielleicht sieht hier einer einen Fehler, ich leider nicht. Im Grunde ist es ein simpler Reloadschutz für die Anfrage-Formulare. Leider kommt es aber dennoch immer wieder vor, dass ein Nutzer das Formular mehrfach absendet und das auch funktioniert. Eben eine Dame 7 mal "reloaded" binnen 5 Minuten.

    $checksum_arr = array();

    $checksum_arr['uk_id'] = $_POST['unterkunft_id'];

    $checksum_arr['name'] = $_POST['name'];

    $checksum_arr['email'] = $_POST['email'];

    $checksum_arr['telefon'] = $_POST['telefon'];

    $checksum_arr['nachricht'] = $_POST['nachricht'];

    $checksum_arr['anreise'] = $_POST['anreise'];

    $checksum_arr['abreise'] = $_POST['abreise'];

    $checksum_arr['personen'] = $_POST['personen'];

    $checksum_arr['kinder'] = $_POST['kinder'];

    $checksum_arr['hunde'] = $_POST['hunde'];

    // Checksumme über alle Anfragedaten bilden

    $checksum = md5(serialize($checksum_arr));

    Anschließend wird die Datenbank abgefragt, ob "$checksum" schon da ist. Wenn ja, dann wird normalerweise abgebrochen und wenn nein, dann werden die Daten normal in die DB geschrieben und die $checksum eben auch, damit sie dann bei einem Reload vorhanden wäre.

    So, das Problem nur, die $checksum ist bei diesen bestimmten Personen immer eine andere und ich habe keinen Schimmer warum. Ich nutzte ja extra aus dem Post-Array nur die bestimmten Daten, die bei einem Reload gleich bleiben. Es stehen auch exakt die gleichen Daten in der Datenbank, halt eben mehrfach. Nur die gebildete checksum ist anders. Rein theoretisch müssten also beim Reload andere Daten kommen, wenn dem aber so wäre, dann müssten auch andere Daten in der DB stehen.:/

    Hat einer eine Idee?

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • Zeitlich geht das nicht. Es gibt auch Leute, die sich vertippt haben und was korrigieren wollen. IP ist auch unsicher. Gibt genug Proxys, wo jeder Request eine andere IP ist.

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • cookie und auslesen eine Option?

    Soory wenn ich so dumm frage. Zur Eingangsfrage kann ich nichts sagen, ausser vielleicht das ei n caching drin sein könnte. Deswegen der neue Ansatz

    wenn etwas möglich erscheint mach ich das, wenn das nicht klappt gehts ans unmögliche und ansonsten das undenkbare.

    - nun stolz rauchfrei - Ich denke also Bing ich!

    Support 24h Bereitschaft 0173 6107465 - NUR Für Kunden von SEO NW!

  • Mit Cookies arbeite ich schon als zweiten Ansatz. Also alles was oben im Array steht steht auch noch mal in der Session und wird von der Verarbeitet. Da geht es aber schon mit dem Timeout los, wenn einer zwischen Eingabe und Absenden zu lange braucht.

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • Also nicht falsch verstehen. Die Lösung oben funktioniert sehr gut. Die fängt sicherlich 99,5% ab, aber ich weiß nicht, warum die anderen 0,5% nicht. Habe die gleiche Anfrage mir selbst mal geschickt und dann auf allen möglichen Wegen noch mal versucht. Ging nicht, wurde blockiert. Daher ist das ja das Komische, dass andere irgendwie "durchkommen".

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

    Einmal editiert, zuletzt von Synonym (19. Juli 2020 um 17:14)

  • Kann ich ja nicht sagen, daher frage ich ja, was das sein könnte. Normalerweise sendet ein Post-Request bei einem Reload die gleichen Daten noch mal. Oder eben, wenn man die Seite einfach per "back" zurück geht, dann hat man ein bereits ausgefülltes Formular und kann das neu abschicken per Button.

    Mit denen arbeite ich dann und kann eben sagen "ist schon da". Egal ob vor 2 Minuten oder 2 Tagen, so soll das auch sein. Nur irgendwelche schummeln sich da durch. Daher auch beide Ansätze, weil einige z.B. gar keine Cookies an haben und die Session nicht geht.

    Habe sogar gesehen, die 7 Anfragen, die die Dame heute geschickt hat, die hat sie gestern 100% genauso schon mal um 19 Uhr geschickt, aber nur einfach. Also sind es eigentlich 8 Anfragen. Gestern eine und heute gen 11 Uhr 7 mal binnen 5 Minuten.

    Und fülle ich eben das Formular mit den gleichen Daten aus, dann wird bei mir der Hash "1ed935abc7e7548e9384bdc4a592e122" errechnet. Mache ich das dann noch mal, dann kommt "Anfrage wurde bereits verschickt", weil der Wert erneut berechnet wird und eben schon in der DB steht. Bei den komischen Leuten / Anfragen, sind es immer unterschiedliche Hashes. Also muss bei den Daten ja was anders sein, auch wenn es nur ein Zeichen ist (genau der Grund, warum ich bei dem Vergleich Dinge wie IP, Zeitstempel etc nicht nutze, sondern nur die User-Eingaben selbst). Aber meine DB sagt nein, identisch. Lässt sich am besten nachvollziehen, ohne jedes Zeichen per Hand kontrollieren zu müssen, wenn ich dann in der DB bei allen Datensätzen durch die DB einen Hash erstellen lasse. Der ist dann gleich.

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • Schneller fix:

    Wenn es hilft kannst du auch einfach in deiner datenbank einen unique index ueber mehrere zellen machen die zusammen immer eindeutig sein muessen, in deinem fall wahrscheinlich [unterkunft_id, email, anreise]. Dann einfach ein INSERT IGNORE machen, und nur der erste request landet in der datenbank.

    Zuverlaessigerer fix:

    statt jedesmal neu name, email, telefon zu speichern ich wuerde im hintergrund immer einen neuen benutzer anlegen, wenn es sich um eine neue email handelt und dann nur die benutzer_id mit jeder anfrage speichern. Damit vermeidest du schonmal probleme wenn telefon leicht abweicht (123-456, 1 234 56, 123456) und kannst leichter pruefen ob der user schonmal was geschickt hast. Ausserdem hast du alle kunden zentral an einem platz, und verteilst keine kontaktinfos ueber verschiedene tables.

    Ich mache bei solchen kontaktanfragen immer ajax-request, und dabei wird der submit-button auf 'disabled' gesetzt solange der request noch laeuft, und leute koennen nichtmehr dopplelklicken.



    Code
    //in deiner formular seite:
    <form id="buchungsanfrage" ....></form>

    (sorry, formatierung ist verlorengegangen)

  • Danke Forumsfossil.

    Weg 1 ist nicht wirklich eine Lösung, denn so weit ich weiß bekommt man bei einem "insert irgnore" keine Rückmeldung, ohne da noch andere Abfragen zu starten. Es geht nicht um den Eintrag in die DB, sondern darum, dass der überhaupt erzeugt werden soll. Natürlich kann ich das auch so machen und damit zumindest verhindern, dass Mails mehrfach raus gehen.

    Weg 2, also normalisieren. Ist hier nicht gefragt oder sinnvoll. Das sind tausende verschiedene Nutzer, die tausende verschieden Kunden anfragen. In der Regel ist das eine Anfrage pro Nutzer. Normalisierung wäre hier nur nachteilig. Die Datenbank ist in dem Fall nur ein Massenspeicher. Die Daten werden später nie wieder benötigt.

    Dein Code hört sich interessant an, wobei ich eigentlich der bin, der von JS weg will. Deines scheint auch noch jQuery zu sein, aber das ist nicht das Problem, kann man ja auf "vanilla" umschreiben.

    Die Frage an sich ist aber immer noch. Warum werden bei bestimmten Usern MD5-Hashes aus dem gleichen Post-Request unterschiedlich errechnet? Heute wieder 12, die auch neu gesendet hatten. Die wurden abgefangen, gleicher Hash. Aber eben wieder einen, bei dem es nicht ging,

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • Kann es sein dass deine eingaben vielleicht doch nicht immer 100% gleich sind? leerzeichen am anfang oder ende? variable gesetzt oder nicht gesetzt? Wenn du bei Laravel die html-form components verwendest, werden immer automatisch csrf-tokens gesetzt, die sich beim reload aendern. Wenn das versteckte csrf-token mit serialisiert wird, aendert sich auch der hash.

    Ich wuerde die eingaben als erstes mal mit serialize($_POST) in ein log schreiben, und dann nachtraeglich einzeln mit md5($_POST['unterkunft_id']) , md5($_POST['name']) , ... schauen wo die abweichungen denn genau auftreten.

    Nebenbei bemerkt isses natuerlich ziehmlich optimistisch, einfach anzunehmen dass alle $_POST variablen korrekt gesetzt sind. Normalerweise hat man als erstes eine validierungsfunktion, die schaut ob die eingabe wirklich gesetzt ist und den richtigen typen (string, datum, email,...) hat bevor man die daten weitergibt, oder den user mit fehlermeldung auf die vorheige seite zurueckschickt....

  • Eigentlich sollte da nichts unterschiedlich sein, denn wenn ein Formular gesendet wurde, die "Dankes Seite" da ist und man F5 drückt, dann hat man ja keine Option, etwas zu ändern. Der Browser schickt dann ja einfach alles noch mal.

    Und nein, so was wie einen Token habe ich nicht. Bzw. schon, aber nicht im serialize. Da sind genau deswegen nur die Daten drinnen, die oben erwähnt sind. Natürlich gibt es noch weitere Daten, IP, Zeitstempel, andere Felder, DSGVO etc, aber das ist alles nicht im Hash enthalten.

    Und ja, ich logge nun schon das komplette $_POST mit. Bisher habe ich nur welche, die ebenfalls einen Reload machten, der aber abgefangen wurde. Seit dem Post oben kam wieder mal keiner doppelt und dreifach durch.

    Und ja, natürlich wird validiert. Die Zeilen oben sind quasi direkt nach der Prüfung, danach kommt DB-Eintrag. Vorher sind noch 200 weitere. Die Felder können z.B. nicht leer sein oder falsche Angaben enthalten, das wird vorher geprüft und wenn erforderlich, abgebrochen mit Fehlermeldung. Das Datum kann man z.B. gar nicht per Hand eingeben, das macht eine Auswahlbox, damit eben schon mal da das Format stimmt. Email wird geprüft, ob von der Syntax her richtig und der Host auch erreichbar ist etc.

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • Ich glaube den Fehler gefunden zu haben, auch wenn ich ihn nicht verstehe, kann aber eingreifen. Heute hatte ich drei auf einen Schlag, die mehrfach senden konnten. Geändert waren die Werte in Input-Feldern vom Typ "number". Das Feld (Anzahl Kinder oder Hunde) muss man nicht ausfüllen, kann leer bleiben. Also wird als Wert "" gesendet. Komischerweise senden die dann aber bei einem Reload den Wert "0". Beides ist bei mir zulässig. Nur "" und "0" sind im Hash eben anders. Also im System umgebogen, dass ein "0" eben wieder ein "" wird. Mal sehen was passiert.

    Alle drei User waren mobil auf der Seite mit Safari.

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • Ich glaube den Fehler gefunden zu haben, auch wenn ich ihn nicht verstehe,


    im System umgebogen, dass ein "0" eben wieder ein "" wird. Mal sehen was passiert.

    äh, wie genau macchst du das? andersrum wäre einfacher ...

    da da ein "zahl" kommen soll einfach im Script mit (int)$_POST verarbeiten, dann wird aus dem Leerzeichen die 0


    Wen da kein Häcker versucht dir was zu tun ...

    ... dann ist das wohl eine Browser-Ki

    beim ersten anzeigen, zeigt er einfach an ....

    ... beim zweiten anzeigen will er inteligent sein und macht (int)$RESTOR und du krigst die 0 obwohl du mehr NULL(also das SQL istnichts) haben wolltest

    ich schreib gerade, weil ich reg mich gerade über das "neue" Transaktionsprotokol auf ....

    ... gab da eine Umstellung von MyISAM auf innoDB und nunläuft immer dieses TProto mit

    wenn eine DB zu groß wird (hab da 1Giga Limit) kannste nicht einfach mal eine Teilmenge DELETE .... das macht nicht kleiner sondern größer

    eben hab ich in einer Tabelle eine Spalte hinzugefügt ... dann schauen um wiviel die Base jetzt größer ist

    hähä ... die ist jettz kleiner, weil der "ALTER TABLE" das gedönst aus dem TProto dann in den Mülleimer wirft

    das macht mich irre

  • da da ein "zahl" kommen soll einfach im Script mit (int)$_POST verarbeiten, dann wird aus dem Leerzeichen die 0

    Ich bin sparsam, ich will keine unnötigen "0"en in der Datenbank stehen haben ;)

    Und ja, der Browser scheint irgendwas bei einem Reload mit dem Feld zu machen, also anderes zu handhaben. Ist nur bei denen mit dem Typ, passiert nicht bei den normalen.

    eine Teilmenge DELETE .... das macht nicht kleiner sondern größer

    Das ist korrekt, weil alles was geändert wurde protokolliert wird. Die Datenbank an sich wird zwar kleiner, aber die Dateien auf dem Server größer. Empfehlung: Entweder ein "ALTER TABLE" oder besser aber umständlicher... Tabelle "kopieren", alte löschen, neuer den alten Namen geben. Dann haste den kleinsten Wert der möglich ist.

    Das hatte ich damals mal mit Piwik. Gut, Root, also kein DB-Limit, aber laut Piwik war die 5 GB groß. Meine Festplatte hatte 20 GB. Irgendwann ging nix mehr, Festplatte voll. Genau der Grund, Protokolle, die mit geschrieben werden. Die zeigt z.B. phpmyadmin in den Übersichten und Größen aber gar nicht mit an.

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • Das ist korrekt, weil alles was geändert wurde protokolliert wird.

    Empfehlung: Entweder ein "ALTER TABLE" oder besser aber umständlicher... Tabelle "kopieren", alte löschen,

    nach der Umstellung war ich noch so blöd und hab mir DegubInfos reingeschrieben ..... vor jeder "Absturzmöglichkeit" einen "Da ist das Script gerade"

    Die Befehler waren ja garnicht das Problem ... die funktionierten ja vorher auch

    und das Breakponting hat das Problem vergrößert

    Gestern alles wieder rausgeworfen und bin gerade am Ablauf Umbau ...

    der erste Lauf macht nur noch das wichtigte (schauen ob Preis verändert, der bekommt ein UPdate) für den Rest schreib ich eine neue csv und verarbeite die Nachgelagert


    Alter Table .... ohne die Tabelle zu verändern? geht das?

    kann ja keien Spalte löschen die ich noch brauch (ein Index würde gehen, um ihn dann wieder anzulegen .... das ist aber .... graus)

    kopieren geht schlecht, wenn kein Platz da ist ...

    eben kommt mir ... alter Table Autoinkrement setzen .... das ändert normal nichts ....

    ... und wenn die SQL so inteligent ist und das dann deswegen nicht macht

    1. Datensatz anlegen (die nun höchste Autoinkrement)

    2. diesen löschen

    3. Alter auf zurück

    wenn das so sein muß, dannmuß das so sein .... also kompliziert

    (da hatte ich was gelesen von "Optimiz Table" der aber auch nicht ausgeführt wird)


    Das mit dem Kleiner werden, ist glaub nicht wirklich so

    innoDB scheint da eher die Datensätze als "nicht genutzt" zu markieren aber in der Base zu lassen ...

    hab da auf meiner "was macht das Script gerade" eine Ausgabe wie die Belegungen sind

    und die Zahlen für Daten+Index werden bei delete nicht kleiner, nur die Daten+index+nochwas wird größer

    Base 1: 140597281 :::: 216.698.913 :::: 216.757.141

    Base 2: 289042668 :::: 483.754.220 :::: 504.728.880

    Base 3: 821198632 :::: 920.517.416 :::: 920.613.852

    Base 4: 369246208 :::: 463.257.600 :::: 506.249.216

    Base 5: 392790016 :::: 453.754.880 :::: 573.292.544

    Base 6: 727236608 :::: 768.884.736 :::: 780.419.072

    Base 7: 404307968 :::: 500.809.728 :::: 580.501.504

    Base 8: 454098944 :::: 537.821.184 :::: 674.136.064

    Base 9: 594247680 :::: 720.683.008 :::: 823.443.456

    Base 10: 508641280 :::: 674.742.272 :::: 800.571.392

    Base 11: 582090752 :::: 679.952.384 :::: 941.047.808

    Base 12: 184074240 :::: 395.657.216 :::: 414.531.584

    Base 13: 240943104 :::: 415.350.784 :::: 419.545.088

    leztens eingebaut, ab 940 Millionen kein Insert mehr

  • gerade wieder eine Überlastung ....

    Base 1: 140614496 :::: 216.719.200 :::: 216.784.120

    Base 2: 0 :::: 0 :::: 0

    Base 3: 821198672 :::: 920.517.456 :::: 920.613.892


    in Base 2 liegt die CronJOB Sache

    und scheinbar hau ich da regelmäßi 500Mega rein die dann geRollbackt werden

    i want rollback to myIsam ;(

  • Welche MyISAM optionen habt ihr denn in MySQL gesetzt, wenn die table groesser werden als sie sollten? Wenn

    Code
    myisam_recover_options=BACKUP

    gesetzt ist, dann wird im hintergrund eine .bak datei mit timestamp angelegt die speicher braucht - ansonsten eben auf OFF setzten.

    Zitat


    Ich bin sparsam, ich will keine unnötigen "0"en in der Datenbank stehen haben ;)

    Wenn moeglich sollte man aber keine NULL-werte in der DB zulassen; weil dann abfragen langsamer werden und der verwaltungsaufwand steigt. Soweit ich das verstanden habe muss MySQL dann im hintergrund zum eigentlichen wert noch ein weiteres flag setzten ob das feld NULL oder NOT NULL ist, bei WHERE, JOIN, GROUP usw. immer beide checks machen, also einmal ob es NULL oder ein gesetzter wert ist, und dann ob der wert entsprechend der abfrage passt.

    Ein anderes problem mit NULL werten hatte ich mal bei einer alten MySQL konfiguration, dabei wurden beim addieren von feldern die auch NULL sein konnten das ergebniss immer zurueckgesetzt:

    SUM(1,2,NULL,3,4) ergab dann 7 (3+4), und nicht 10, da x+NULL immer 0 ergeben hat.


    Die filegroessen kann man auch mit einer simplen SQL abfrage sehen, ohne erst PHP code dafuer schreiben zu muessen:

    SQL
    SELECT TABLE_SCHEMA, TABLE_TYPE, GROUP_CONCAT(TABLE_NAME) as table_names, ENGINE, SUM(TABLE_ROWS) as total_rows, SUM(DATA_LENGTH)/1024/1024 as total_data_MB, SUM(INDEX_LENGTH)/1024/1024 as total_index_lengt_MB
    FROM information_schema.tables
    WHERE TABLE_SCHEMA LIKE 'datenhalde'
    GROUP BY ENGINE, TABLE_TYPE
  • Dein Problem ist sehr wahrscheinlich ibdata und ib_logfileXX. Diese Files werden bei Mysql immer größer, niemanls von selbst kleiner (auto-extended). Sinnvoll wäre der Einsatz von innodb_file_per_table, den kann man ein OPTIMIZE TABLE laufen lassen. (war mein Fehler, ich meinte Optimize, nicht Alter) Was aber auch noch dazu kommt, und ich weiß nicht, wie Dein Hoster die Umstellung machte. Wenn man einfach so myisam auf innodb umstellt oder auf "innodb_file_per_table", dann zählt das immer nur für neue Tabellen. Bei der Umstellung von myisam auf innodb bleiben sogar die alten Dateien von myisam auf dem Server erhalten und brauchen Speicherplatz. Lösungsansatz: Dump von DB ziehen. DB löschen. Dump neu einspielen. Dann werden auch alle nicht benötigten Daten gelöscht.

    Aber Rollback zu myisam. Warum sollte das nicht gehen? Das kannst Du doch eigentlich per default dort einstellen bei den Tabellen. Innodb wurde bei neueren Versionen nur mal STandard, muss aber nicht bedeutet, dass man das nutzen muss.

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(

  • Mal paar Links dazu:

    http://magento.xonu.de/tipps-und-tric…isch-freigeben/

    https://www.thomas-krenn.com/de/wiki/MySQL_Optimize_Table

    https://www.it-swarm.dev/de/mysql/loesc…lle/l958336742/

    @Forumsfossil Ich speichere auch keine NULL, weil mir damit schon die Abfragen zu doof werden. Also entweder wirklich "0" oder eben leerer String "".Ich weiß, dass int 0 besser ist als varchar "", aber es handelt sich zu 98% nur um einen Datenspeicher. Und wenn es dann mal ein Select geben sollte, dann ist das ohnehin ein Full-Select ohne WHERE, also Indexe sind da ohnehin egal.

    P.S. Mir ist klar, dass ein Varchar "" auch ein Byte braucht wie ein int 0, oder ein Varchar "1" eben 2 Byte. Sparsam war hier auf Ansicht bezogen. Man erkennt schneller was in der DB, wenn ein Feld einfach leer ist, anstelle von 0 oder Null. Für den menschlichen Verstand ist "leer" eben leer und nicht 0 ;)

    Wenn ein Mensch nicht um dich kämpft, hat er nur gewartet, dass du gehst. ;(