Martin: PHP Session + MySQL

Hi!
Ich habe einen Warenkorb programmiert, jedoch hat dieser eine kleine Macke:
Hauptaufgabe ist es, eine MySQL INSERT Operation durchzuführen. Das funktioniert aber nicht immer...

Ich verwende das 3 Dateien Modell d.h. Die erste Datei ruft den Insert Befehl auf (2. Datei) und die Anzeige, das nun etwas in dem Warenkorb liegt erfolgt mit einer 3. Datei.
Und dabei kommt das Programm ins "stocken". Ich werde nicht mehr, mittels $HTTP_REFERER zur Ausgangsdatei weitergeleitet.
Eine leere Seite ist zu sehen, jeder Reloadversuch legt den Artikel in die MySQL Tabelle.
(3 * Reload = 3 Artikel im Warenkorb) aber das ist ja php und mysql auf einer seite, quasi normal...

Mein  SESSION Problem:
Es wird eine Session Datei angelegt, die  - sofern nichts registriert - leer ist. In diesem Fall funktioniert die $HTTP_REFERER weiterleitung nicht.

Ist in dieser Session Datei ein Wert abgelegt, funktioniert das System einwandfrei. Wirklich!

Kann mir jemand helfen? Liegts am Apache?
Die Konfiguration:
WinXP, Apache 2.0.52, php 4.3.5,
Sessions funktionieren, register globals = on

Viele Grüße
Martin

Die Datei für dem Warenkorb:
http://www.htwm.de/mbehnke/php/cart.txt

Das Spielzeug:
http://www.htwm.de/mbehnke/php/showItem.php?offset=0&min=18000&id=7

  1. Wenn ich mich so durchklicke klappt alles soweit.

    1. @Sebastian
      Danke!

      Hmm, komisch.
      Kann es sein, das ich hier Probleme habe, da ich die Seite hier lokal teste und dann auf dem htwm.de Server?

      Kann das zu Sessionproblemen führen?

  2. Moin!

    Und dabei kommt das Programm ins "stocken". Ich werde nicht mehr, mittels $HTTP_REFERER zur Ausgangsdatei weitergeleitet.

    Vergiß bitte den HTTP_REFERER! Sofort.

    Der HTTP-Standard erlaubt es, dass man einen Referrer senden KANN, man MUSS aber nicht. Und sehr viele Benutzer tun es auch nicht! Bzw. können es gar nicht beeinflussen, weil ihr Admin das so will.

    Also arbeite nicht mit dem Referrer, alles, was darauf basiert, ist sehr zerbrechlich. Du hast Sessions, du kannst darin speichern, wohin man wieder zurückkommen soll, und das entsprechend verwenden. Oder du nutzt $_SERVER['PHP_SELF'] und arbeitest die Formulardatenübertragung immer unter EINER URL ab - geht auch mit deinem "3-Seiten-Modell", denn nirgendwo ist gefordert, dass die drei Seiten unterschiedliche Skriptadressen haben müssen.

    Sessions funktionieren, register globals = on

    Das solltest du mal auf off stellen. Wirst du in der Zukunft bei Hostern kaum anders vorfinden - besser, du bist darauf vorbereitet. Wird ja auch erst seit drei Jahren (seit PHP 4.2.0) propagiert... <seufz>

    • Sven Rautenberg
    1. @Sven

      Ja, stimmt. Da kann ich ja in den Sessions speichern, wo ich hin will.

      Das mit dem $HTTP_REFERER habe ich garnicht gewusst. Muss ich mal weiterforschen.

      Danke!

      1. Hello,

        Ja, stimmt. Da kann ich ja in den Sessions speichern, wo ich hin will.

        Und zwar speicherst Du das am besten in der ersten Seite in die Session
        Die weiß schließlich selber, wo sie steht.

        Und dann gibst Du der ersten Seite im Form eine Unique-ID mit. Die steht sogar schon in $_SERVER['UNIQUE_ID'] drin. Diese ID trägst Du auch in eine Tabelle ein

        UNIQUE_ID    das ist dann gelich der Primärschlüssel!
          Datum/Zeit   Wann sie eingetragen wurde.
                       Schade dass MySQL kein Default-Wert mit Date() macht (oder?)
          erledigt     Kennzeichen, wenn dieses Formular seine Arbeit erledigt hat.

        1)

        Wenn jetzt ein Formular zum Eintrag in den Warenkorb benutzt wird, und dieser Eintrag stattfindet, dann muss ein Zertifikat in der DB vorhanden sein, dass noch nicht abgelaufen ist. Du darfst nur nicht vergessen, jedem Ausgangsformular (Liste der Artikel) ein neues Zertifikat mitzugeben, dass jedes Script, das den Eintrag dann vornehmen soll, erst überprüft.

        Bei einfachen Systemen kann man diese Vorgangsüberwachung auch so aufbauen, dass einfach die mit dem Formular ausgelieferte Unique-ID mit in den Warenkorb eingetragen wird, und dann eben beim Eintrag geschaut wird, ob sie schon vorhanden ist...

        Aber...1):

        Wenn sich Dein System nämlich weiterentwickelt, dann kann man in der Überwachungstabelle auch den User, den Typ des offenen Vorganges und weitere zu überwachende Daten ablegen. Man kann damit auch prüfen, ob der User einen bestimmten Zwangsablauf eingehalten hat, und ob er zu der angeforderten Aktion überhaupt berechtigt ist.

        Harzliche Grüße aus http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau
        1. Moin!

          Schade dass MySQL kein Default-Wert mit Date() macht (oder?)

          Feldtyp TIMESTAMP. Das erste derartige Feld in einer Tabelle wird bei INSERT- und UPDATE-Operationen auf die aktuelle Zeit gesetzt, sofern es nicht explizit auf einen anderen Wert gesetzt wird.

          • Sven Rautenberg
          1. Hello,

            Schade dass MySQL kein Default-Wert mit Date() macht (oder?)

            Feldtyp TIMESTAMP. Das erste derartige Feld in einer Tabelle wird bei INSERT- und UPDATE-Operationen auf die aktuelle Zeit gesetzt, sofern es nicht explizit auf einen anderen Wert gesetzt wird.

            Das ist nicht ganz, was man unter Default- oder Standardwert versteht.
            Ein Standardwert wird nur dann in die Spalte eingefügt, wenn diese bei einem Insert keinen externen Wert übertragen bekommt, nicht aber wenn dieser vorhanden ist, oder ein Update durchgeführt wird.

            Ich hatte nun versucht, als Default (das wäre also der gesuchte und MySQL hat sowas ja auch) eine Funktion anzugeben, nämlich date(). Aber MySQL (zumindest meine verfügbaren Versionen) unterstützen das noch nicht. Sowas wäre aber essentiell. Kann man denen das irgendwo vorschlagen?

            Harzliche Grüße aus http://www.annerschbarrich.de

            Tom

            --
            Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
            Nur selber lernen macht schlau
            1. Moin!

              Ich hatte nun versucht, als Default (das wäre also der gesuchte und MySQL hat sowas ja auch) eine Funktion anzugeben, nämlich date().

              Die Doku sagt:
              DATE(expr)
              Extracts the date part of the date or datetime expression expr.

              Und ich sage:
              No expression - no date.

              Was du suchst, ist das zum Zeitpunk der Eintragung aktuelle Datum, das sich danach nicht mehr verändern soll.

              Schon mal was von NOW() gehört?

              • Sven Rautenberg
              1. Hello,

                Was du suchst, ist das zum Zeitpunk der Eintragung aktuelle Datum, das sich danach nicht mehr verändern soll.

                Schon mal was von NOW() gehört?

                Und "now()" funktioniert als default-Wert?

                Wie die Funktion genau heißen muss, ist mir eigentlich scheißegal, Hauptsache, sie funktioniert als Default-Wert!

                Harzliche Grüße aus http://www.annerschbarrich.de

                Tom

                --
                Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                Nur selber lernen macht schlau
              2. Was du suchst, ist das zum Zeitpunk der Eintragung aktuelle Datum, das sich danach nicht mehr verändern soll.

                Schon mal was von NOW() gehört?

                Deine Frage ist missverständlich. Was du meinst ist

                create table table_name (...., ts) values(...., TIMESTAMP NOT NULL DEFAULT 'NOW()');

                das laut einem Userkommentar gehen soll.

                Grad ausprobiert geht das, aber 1. nur wenn man die ' weglässt und 2. auch nur für TIMESTAMP-Felder.
                Man kann das DEFAULT NOW() beim ersten TIMESTAMP-Feld auch weglassen, da es automagisch gesetzt wird, wenn kein DEFAULT-Wert angegeben ist.
                Ansonsten gilt auch in Version 4.1 immer noch: Es kann nur einen (automatisch gesetzten Timestamp) geben.

                1. Hello,

                  Man kann das DEFAULT NOW() beim ersten TIMESTAMP-Feld auch weglassen, da es automagisch gesetzt wird, wenn kein DEFAULT-Wert angegeben ist.
                  Ansonsten gilt auch in Version 4.1 immer noch: Es kann nur einen (automatisch gesetzten Timestamp) geben.

                  Was wird denn dann eingesetzt? Der Now()-Wert während des Erzeugens der Tebellendefinition oder der Now()-Wert während des Einfügens eines neuen Datensatzes?

                  Soweit ich das durchschaue, kann MxSQL keine Funktionen als Default, sondern nur Kontanten. Das Ergebnis einer Funktion, das dann in die Definition aufgenommen wird, ist ja während der Laufzeit eine Konstante. Das nützt mir aber nichts.

                  Mit der vierten Dimension haben es die Poster hier nicht so, scheint mir ;-()

                  Harzliche Grüße aus http://www.annerschbarrich.de

                  Tom

                  --
                  Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                  Nur selber lernen macht schlau
                  1. Ansonsten gilt auch in Version 4.1 immer noch: Es kann nur einen (automatisch gesetzten Timestamp) geben.

                    Was wird denn dann eingesetzt? Der Now()-Wert während des Erzeugens der Tebellendefinition oder der Now()-Wert während des Einfügens eines neuen Datensatzes?

                    Beim Einfügen eines Datensatzes wird der aktuelle Wert von CURRENT_TIMESTAMP/NOW()/... (es gibt da ja 8 Synonyme davon) genommen.

                    MySQL 4.1 erweitert das ganze dann noch zu

                    feldname timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP

                    Es besteht also damit auch die Möglichkeit, beim UPDATE das Feld ändern zu lassen.

                    (Außerdem hat sich noch das Ausgabeformat von Timestamp-Feldern geändert. Es ist jetzt wie bei DATETIME: 0000-00-00 00:00:00)

                    Soweit ich das durchschaue, kann MxSQL keine Funktionen als Default, sondern nur Kontanten.

                    Das ist richtig. Aus NOW() wird automatisch CURRENT_TIMESTAMP (die Konstante, nicht die Funktion).

                    Literaturtipp: http://dev.mysql.com/doc/mysql/en/timestamp-4-1.html

                    1. Hello,

                      Das ist richtig. Aus NOW() wird automatisch CURRENT_TIMESTAMP (die Konstante, nicht die Funktion).
                      Literaturtipp: http://dev.mysql.com/doc/mysql/en/timestamp-4-1.html

                      Es funktioniert nicht, eine Timestamp-Spalte zum Vermerken der letzen Änderung sowie eine zum Vermerken des Erstellungsdatums szu führen.

                      Sowas sollte ein DBMS, das Geld kostet, schon leisten.

                      "Mein" immer noch im Einsatz befindliches 3.23.55 (oder 3.23.58 mit diversen Bugfixes) kann es auf keinen Fall, aber das hat ja auch noch nix gekostet.

                      Von den 4er Versionen erwarte ich das aber, oder habe ich da immer noch was nicht richtig verstanden?

                      Harzliche Grüße aus http://www.annerschbarrich.de

                      Tom

                      --
                      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                      Nur selber lernen macht schlau
                      1. Es funktioniert nicht, eine Timestamp-Spalte zum Vermerken der letzen Änderung sowie eine zum Vermerken des Erstellungsdatums szu führen.

                        CREATE TABLE test1 (
                        tsc timestamp NOT NULL default CURRENT_TIMESTAMP ,
                        tsm timestamp NOT NULL ON UPDATE CURRENT_TIMESTAMP )

                        #1293 - Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause

                        Von den 4er Versionen erwarte ich das aber, oder habe ich da immer noch was nicht richtig verstanden?

                        4.0 kennt "on update" nicht. Das gibt's erst ab 4.1.

                        4.1 enthält gegenüber 4.0 noch eine Menge weitere Leistungsmerkmale. Meiner Meinung nach wäre 4.5 eine bessere Versionsnummer gewesen. Aber wer will schon meine Meinung hören... :-)

                      2. Moin!

                        Es funktioniert nicht, eine Timestamp-Spalte zum Vermerken der letzen Änderung sowie eine zum Vermerken des Erstellungsdatums szu führen.

                        Sowas sollte ein DBMS, das Geld kostet, schon leisten.

                        Punkt 1: Mein MySQL kam ganz kostenlos aus dem Internet.
                        Punkt 2: Ich hab kein Problem mit zwei Timestamp-Spalten in einer Tabelle. Die erste Spalte enthält nach Updates das aktuelle Datum, die zweite Spalte füllt sich beim Insert und bleibt dann konstant.

                        "Mein" immer noch im Einsatz befindliches 3.23.55 (oder 3.23.58 mit diversen Bugfixes) kann es auf keinen Fall, aber das hat ja auch noch nix gekostet.

                        Hier: 4.0.22, ich bin mir aber ziemlich sicher, es mit einer 3er-Version auch schon probiert zu haben - ist aber schon etwas her.

                        Von den 4er Versionen erwarte ich das aber, oder habe ich da immer noch was nicht richtig verstanden?

                        Offenbar.

                        • Sven Rautenberg
                        1. Hello,

                          Punkt 2: Ich hab kein Problem mit zwei Timestamp-Spalten in einer Tabelle. Die erste Spalte enthält nach Updates das aktuelle Datum, die zweite Spalte füllt sich beim Insert und bleibt dann konstant.

                          Wenn Du mir einfach verraten würdest, wie die Tabellendefintion dafür lauten muss, damit das (ohne Zutun der API) von der Datenbankmaschine alleine bewältigt wird, bin ich bereit, mir über das "offenbar" Gedanken zu machen ;-)

                          Harzliche Grüße aus http://www.annerschbarrich.de

                          Tom

                          --
                          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                          Nur selber lernen macht schlau
                          1. Moin!

                            Punkt 2: Ich hab kein Problem mit zwei Timestamp-Spalten in einer Tabelle. Die erste Spalte enthält nach Updates das aktuelle Datum, die zweite Spalte füllt sich beim Insert und bleibt dann konstant.

                            Wenn Du mir einfach verraten würdest, wie die Tabellendefintion dafür lauten muss, damit das (ohne Zutun der API) von der Datenbankmaschine alleine bewältigt wird, bin ich bereit, mir über das "offenbar" Gedanken zu machen ;-)

                            CREATE TABLE test1 (
                              zahl int(11) NOT NULL default '0',
                              ts1 timestamp(14) NOT NULL,
                              ts2 timestamp(14) NOT NULL default '00000000000000'
                            ) TYPE=MyISAM;

                            INSERT INTO test1 (zahl, ts2) VALUES (2, NULL);

                            SELECT * FROM test1;
                            zahl  ts1               ts2
                            2     20050308100309    20050308100309

                            UPDATE test1 SET zahl = 3 WHERE zahl = 2;

                            SELECT * FROM test1;
                            zahl  ts1               ts2
                            3     20050308100542    20050308100309

                            • Sven Rautenberg
                            1. Hello,

                              ganz großen Dank dafür, Sven!

                              Es funktioniert so auch auf MySQL 3.23.55
                              Man muss dann nur dafür sorgen, dass die Spalte ts2 beim Update nicht angefasst wird.

                              CREATE TABLE test1 (
                                zahl int(11) NOT NULL default '0',
                                ts1 timestamp(14) NOT NULL,
                                ts2 timestamp(14) NOT NULL default '00000000000000'
                              ) TYPE=MyISAM;

                              ts1 = Last Update
                              ts2 = First Entry

                              INSERT INTO test1 (zahl, ts2) VALUES (2, NULL);

                              SELECT * FROM test1;
                              zahl  ts1               ts2
                              2     20050308100309    20050308100309

                              UPDATE test1 SET zahl = 3 WHERE zahl = 2;

                              SELECT * FROM test1;
                              zahl  ts1               ts2
                              3     20050308100542    20050308100309

                              Offenbar hatte ich das mit den mehreren Timestamp-Spalten und der automatischen Wertzuweisung also doch verkehrt verstanden. Ich war davon ausgegangen, dass "nur die erste TS-Splate wird automatisch geführt" auch bedeuet, dass einer weiteren niemals automatisch ein Wert zugewiesen wird. Das "automatisch" bezieht sich aber nur auf das Übergeben von NULL an die erste Spalte. Unterlässt man es, sie anzusprechen, wird genauso der aktuelle Wert eingestanzt, als wenn man NULL zuweist. Bei der zweite wird aber nur updated, wenn man sie in den Values mit NULL bedenkt.

                              Wenn das auch irgendwo so ausführlich im MySQL-Manual stehen sollte, habe ich es wohl jedes Mal überlesen.

                              Harzliche Grüße aus http://www.annerschbarrich.de

                              Tom

                              --
                              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                              Nur selber lernen macht schlau
                              1. Moin!

                                Es funktioniert so auch auf MySQL 3.23.55
                                Man muss dann nur dafür sorgen, dass die Spalte ts2 beim Update nicht angefasst wird.

                                Das kannst du ja notfalls HART regeln, indem du dem DB-User, mit dem du Inserts und Updates machst, das Privileg "UPDATE" für diese Spalte entziehst.

                                MySQL hat schließlich ein sehr ausgefeiltes Rechtekonzept - das darf man nutzen.

                                • Sven Rautenberg
                                1. Hello,

                                  Man muss dann nur dafür sorgen, dass die Spalte ts2 beim Update nicht angefasst wird.

                                  Das kannst du ja notfalls HART regeln, indem du dem DB-User, mit dem du Inserts und Updates machst, das Privileg "UPDATE" für diese Spalte entziehst.

                                  Gute Idee. Dann kann eigentlich gar nichts mehr schiefgehen.

                                  Harzliche Grüße aus http://www.annerschbarrich.de

                                  Tom

                                  --
                                  Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                                  Nur selber lernen macht schlau
    2. »» Das solltest du mal auf off stellen. Wirst du in der Zukunft bei Hostern kaum anders vorfinden - besser, du bist darauf vorbereitet. Wird ja auch erst seit drei Jahren (seit PHP 4.2.0) propagiert... <seufz>

      *nickt*
      Höre und lese ich auch öfters. Doch verstehe ich nicht wie ich dann Links stattdessen erstelle...

      Angenommen ich habe eine Seite und man geht auf /index.php?mode=5&id=100
      Wie kann ich soetwas denn anders lesen? Ich muss die Werte doch irgendwie übergeben. Und ich weiss ja nicht vorher welchen Link der User drückt...

      oder habe ich da was falsch verstanden?

      ciao

      1. Moin!

        Höre und lese ich auch öfters. Doch verstehe ich nicht wie ich dann Links stattdessen erstelle...

        Was haben denn die Links mit der Art des Zugriffs durch PHP zu tun?

        Angenommen ich habe eine Seite und man geht auf /index.php?mode=5&id=100
        Wie kann ich soetwas denn anders lesen? Ich muss die Werte doch irgendwie übergeben. Und ich weiss ja nicht vorher welchen Link der User drückt...

        Der Link bleibt genau so, wie er ist.

        Aber du fragst in PHP nicht mehr $mode und $id ab, sondern $_GET['mode'] und $_GET['id'].

        Das hat mehrere wichtige Vorteile:

        1. Niemand kann in deinem Skript mehr eine Variable "vorbelegen", indem er z.B. "/index.php?andererwert=test" aufruft (das würde ja dazu führen, dass $andererwert mit dem Inhalt "test" beim Skriptstart existiert).

        2. Du hast wieder völlige Freiheit bei der Wahl deiner globalen Variablennamen, ohne darauf achten zu müssen, welche Parameternamen in irgendwelchen Links benutzt werden.

        3. Du greifst mit $_GET _garantiert_ auf den Inhalt des URL-Parameters zu. In $mode werden die Werte von GET, POST, COOKIE, SERVER, ENV und SESSION gesammelt, dadurch kannst du nicht mehr feststellen, aus welcher Quelle die Information kommt. Und es wäre doch schön, wenn man nicht aufpassen muß, dass man als Session-Variable nicht aus Versehen (oder beim testen) eine Variable nimmt, die schon als Parametername in der URL verwendet wird. Das gibt dann nämlich ganz häßliche und seltsame Fehler.

        • Sven Rautenberg
        1. Achso... jetzt versteh ich das erst.

          Ich dachte das global=off nimmt einem die möglichkeit auch variabeln übern die adressleiste zu übergeben (von wegen der user sieht nicht welche informationen ich übertrage)...

          Aber so versteh ich es... ist irgendwo ja auch logisch.

          Was mich jetzt nur ärgert: Arg... meine ganzen bisher gescripteten sachen sind dann woh bald auslaufware =/

          selber schuld.

          aber danke

          ciao

          1. Niemand kann in deinem Skript mehr eine Variable "vorbelegen", indem er z.B. "/index.php?andererwert=test" aufruft (das würde ja dazu führen, dass $andererwert mit dem Inhalt "test" beim Skriptstart existiert).

          Mal abgesehen davon dass das soweit stimmt, ist es eh eine schlechte Idee, Variablen uninitialisiert zu verwenden. PHP bietet das zwar so an, gibt aber nicht ohne Grund dafür auch eine Notice aus.
          Nicht nur der Einfluss von außen, auch die eigene Fehler, stellen Stolperfallen dar: "Ups, die Variable war ja doch nicht mehr leer... Da hab ich doch weiter oben übersehen, dass ich die da schonmal verwende..."

          1. Hello,

            Nicht nur der Einfluss von außen, auch die eigene Fehler, stellen Stolperfallen dar: "Ups, die Variable war ja doch nicht mehr leer... Da hab ich doch weiter oben übersehen, dass ich die da schonmal verwende..."

            oder aber sie schon dreißigmal beschreiben habe, und es ist immer noch nichts drin.

            klar, weil ich mich entweder bei der Initialisierung oder der Abfrage verschrieben hatte...

            Harzliche Grüße aus http://www.annerschbarrich.de

            Tom

            --
            Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
            Nur selber lernen macht schlau