Lukas.: Session geht sporadisch verloren / Teil 2

Hallo,

auf meiner Suche nach dem Fehler, warum meine Session sporadisch verloren geht, bin ich einen entscheidenden Schritt weiter gekommen.

Die Session selber geht nicht verloren, sie bleibt auf dem Server bestehen und ist lesbar.

Meine Session ist so aufgebaut, dass unterschiedliche Nutzergruppen in eine "extra Arrayeben" gepackt werden, sodaß bsp. der Nutzername dann in $_SESSION[$nutzergruppe]['Nutzer'] landet. Was nun verloren geht, ist die Variable $nutzergruppe.

Eigentlich lade ich am Anfang jeder Datei die Konfigurationsdaten ein, darin befindet sich auch die $nutzergruppe.

Merken, dass mal wieder ein Session verloren ging, tue ich es über eine Mail, die ich mir für diesen Fall generieren lasse. Aber selbst innerhalb der Mail ist die $nutzergruppe unbekannt, obwohl ich eigens zuvor nochmal die Konfiguratkionsdaten einlese:

include_once ("sub/konfiguration.php");
$betreff="Session verloren/ ".$Nutzer.": ".$nutzergruppe." / Nummer: ".$nummer;
usw.

ergibt:

alles, nur ohne den $Nutzer und die $nutzergruppe

Wie kann das denn?

Lukas

P.S: Klar ist aber nur, an welcher Stelle die Session verloren geht, nämlich gar nicht. $_SESSION[]['Nutzer'] gibts einfach nicht, wurde ja aber auch nie angelegt.

  1. Hallo Lukas.,

    Was nun verloren geht, ist die Variable $nutzergruppe.

    Eigentlich lade ich am Anfang jeder Datei die Konfigurationsdaten ein, darin befindet sich auch die $nutzergruppe.

    Relevanter Code?

    include_once ("sub/konfiguration.php");
    $betreff="Session verloren/ ".$Nutzer.": ".$nutzergruppe." / Nummer: ".$nummer;
    usw.
    

    Pack nochmal

    ob_start();
    var_dump($_SESSION);
    $result = ob_get_clean();
    

    mit in die Mail.

    alles, nur ohne den $Nutzer und die $nutzergruppe

    Wo sollen $Nutzer und $nutzergruppe herkommen? Es fehlt hier der Code um das zu debuggen.

    LG,
    CK

    1. Hallo Chistian,

      Relevanter Code?

      include_once ("sub/konfiguration.php");

      Pack nochmal

      ob_start();
      var_dump($_SESSION);
      $result = ob_get_clean();
      

      mit in die Mail.

      Kannst Du mir kurz sagen, was das bewirkt?

      alles, nur ohne den $Nutzer und die $nutzergruppe

      Wo sollen $Nutzer und $nutzergruppe herkommen? Es fehlt hier der Code um das zu debuggen.

      Na das hatte ich aber schon ganz gut erklärt in meiner Ausgangsmail. Der Nutzer steht in der Session. Die Nutzergruppe steht in der Konfigurationsdatei. Nutzer gibts nicht per Mail, weil Nutzergruppe verloren geht. Daher die Frage, wie kann das passieren? Zusatzfrage: Die Datei, die die Mail generiert, ist ebenfalls im "sub-Verzeichnis" und wird in die Hauptdatei includiert. Hätte ich dann innerhalb der Datei den Pfad zur Konfigurationsdatei von der includierten Datei aus wählen müssen? Und wenn ja, hätte mir dann nciht der Errorlog einen Hinweis darauf geben müssen?

      Lukas

      1. Hallo Lukas,

        Relevanter Code?

        include_once ("sub/konfiguration.php");

        Na gut, wenn du keinen Code zeigen möchtest - dann kann man dir aber leider auch nicht helfen.

        ob_start();
        var_dump($_SESSION);
        $result = ob_get_clean();
        

        mit in die Mail.

        Kannst Du mir kurz sagen, was das bewirkt?

        Es speichert dir einen Dump der $_SESSION in die Variable $result.

        alles, nur ohne den $Nutzer und die $nutzergruppe

        Wo sollen $Nutzer und $nutzergruppe herkommen? Es fehlt hier der Code um das zu debuggen.

        Na das hatte ich aber schon ganz gut erklärt in meiner Ausgangsmail.

        Nein, im OP sprichst du von $_SESSION[$nutzergruppe]['Nutzer']. Dann auf einmal von $Nutzer. Großer Unterschied.

        Der Nutzer steht in der Session. Die Nutzergruppe steht in der Konfigurationsdatei. Nutzer gibts nicht per Mail, weil Nutzergruppe verloren geht. Daher die Frage, wie kann das passieren?

        Das ist so nicht beantwortbar. Code ist Trumpf.

        Zusatzfrage: Die Datei, die die Mail generiert, ist ebenfalls im "sub-Verzeichnis" und wird in die Hauptdatei includiert. Hätte ich dann innerhalb der Datei den Pfad zur Konfigurationsdatei von der includierten Datei aus wählen müssen?

        Nein. include_once und include gehen vom CWD aus.

        Und wenn ja, hätte mir dann nciht der Errorlog einen Hinweis darauf geben müssen?

        Nein, das ist ja gerade der Unterschied zu require/require_once. include/include_once geben dir false im Fehlerfall zurück und, je nach Konfiguration, maximal eine Warning.

        LG,
        CK

  2. Tach!

    Was nun verloren geht, ist die Variable $nutzergruppe.

    Hast du auch das error_reporting auf E_ALL stehen? display_errors sollte auf 0 bleiben, denn das ist ja ein Produktivsystem, auf dem du da testest, oder? Aber das error_log sollte so konfiguriert sein, dass in eine Datei geschrieben wird. Man kann das dann auch gleich für eigene Debug-Texte nutzen, indem man die Funktion error_log() aufruft. Komplexe Variablenstrukturen kann man dann mit print_r($foo, true) "serialisieren" lassen. Für var_dump() gibt es leider keinen Parameter, der die Ausgabe zurückgibt statt an die Front zu werfen.

    dedlfix.

    1. Hi dedlfix,

      Was nun verloren geht, ist die Variable $nutzergruppe.

      Hast du auch das error_reporting auf E_ALL stehen? display_errors sollte auf 0 bleiben, denn das ist ja ein Produktivsystem, auf dem du da testest, oder?

      In diesem Fall ist es leider das Produktivsystem. Normalerweise natürlich nicht, aber was willst machen, wenn ein Fehler ausschließlich im Produktivsystem auftaucht und das auch nur sporadisch.

      Komplexe Variablenstrukturen kann man dann mit print_r($foo, true) "serialisieren" lassen. Für var_dump() gibt es leider keinen Parameter, der die Ausgabe zurückgibt statt an die Front zu werfen.

      Cool, wußte ich noch gar nicht. Und das war schon öfter mal mein Wunsch, auch wenn ich in irgendwelchen Ajax-Kontexten in Dateien geloggt habe.

      Lukas

      1. Tach!

        Hast du auch das error_reporting auf E_ALL stehen? display_errors sollte auf 0 bleiben, denn das ist ja ein Produktivsystem, auf dem du da testest, oder?

        In diesem Fall ist es leider das Produktivsystem. Normalerweise natürlich nicht, aber was willst machen, wenn ein Fehler ausschließlich im Produktivsystem auftaucht und das auch nur sporadisch.

        Schon klar, deswegen ja display_errors auf 0 lassen. Aber das error_reporting möchte ich deshalb auf E_ALL stehen sehen, damit es auch für Zugriffe auf nicht vorhandene Variablen Meldungen erzeugt, die vom error_log mitgemeißelt werden können. Manchmal existieren Variablen nämlich nicht, weil man sich vertippt hat. Vielleicht reportiert PHP aber auch ganz andere Fehler.

        dedlfix.

        1. Schon klar, deswegen ja display_errors auf 0 lassen. Aber das error_reporting möchte ich deshalb auf E_ALL stehen sehen, damit es auch für Zugriffe auf nicht vorhandene Variablen Meldungen erzeugt, die vom error_log mitgemeißelt werden können. Manchmal existieren Variablen nämlich nicht, weil man sich vertippt hat. Vielleicht reportiert PHP aber auch ganz andere Fehler.

          Gute Idee. Muß ich aber meinen Provider fragen, ob ich das übers Script machen kann. Früher war es so, dass man das über ein Menü einstellen konnte, das ist aber anscheinend geändert worden.

          Lukas

          1. Tach!

            Muß ich aber meinen Provider fragen, ob ich das übers Script machen kann. Früher war es so, dass man das über ein Menü einstellen konnte, das ist aber anscheinend geändert worden.

            Die Error-Reporting-Geschichten kannst du auch erst im Script konfigurieren, dann am besten am zentralen Einstieg, wenn du einen hast, oder einer Konfig-Datei, die stets inkludiert wird, oder ….

            dedlfix.

            1. Die Error-Reporting-Geschichten kannst du auch erst im Script konfigurieren, dann am besten am zentralen Einstieg, wenn du einen hast, oder einer Konfig-Datei, die stets inkludiert wird, oder ….

              Na wie gut das mit der "Konfig-Datei, die stets inkludiert wird," klappt, sehe ich ja gerade ;-)

              Lukas

  3. Meine Session ist so aufgebaut, dass unterschiedliche Nutzergruppen in eine "extra Arrayeben" gepackt werden, sodaß bsp. der Nutzername dann in $_SESSION[$nutzergruppe]['Nutzer'] landet. Was nun verloren geht, ist die Variable $nutzergruppe.

    Das raff ich jetzt nicht. Ich gebe mir seit Jahren Mühe mich so dumm zu stellen wie es das Programmieren nun einmal erfordert und Du stellst mich vor solche Herausforderungen.

    Ich würde mich an "Bekanntes" halten. Und "Bekanntes" ist, dass ein Nutzer Mitglied mehrerer Gruppen sein kann.

    Also:

    $_SESSION['username']='foo';
    $_SESSION['groups'][]='bar';
    $_SESSION['groups'][]='tok';
    

    Freilich will ich Dir nicht im Wege stehen, wenn Du es extrem schwierig, völlig undurchsichtig, furchtbar kompliziert und irre fehlerträchtig machen willst.

    1. Hi,

      Ich würde mich an "Bekanntes" halten. Und "Bekanntes" ist, dass ein Nutzer Mitglied mehrerer Gruppen sein kann.

      Dann liegt das an unterschiedlicher Definition von Nutzer und Nutzergruppe. Meine Nutzer dürfen keinesfalls in mehreren Gruppen Mitglied sein.

      Freilich will ich Dir nicht im Wege stehen, wenn Du es extrem schwierig, völlig undurchsichtig, furchtbar kompliziert und irre fehlerträchtig machen willst.

      Was ist daran so kompliziert, wenn ich anstelle von:

      $_SESSION['Nutzer'] = 'Karl'; $_SESSION['Geburt'] = 1986; usw.

      $_SESSION['Nutzergroup1']['Nutzer'] = 'Karl'; $_SESSION['Nutzergroup1']['Geburt'] = 1986; usw.

      schreibe?

      Ich meine, wir arbeiten doch zu Hauf mit mehrdimensionalen Arrays?

      Lukas

      1. Ich meine, wir arbeiten doch zu Hauf mit mehrdimensionalen Arrays?

        Klar. Aber ist das ein Grund, diese mit sachverhaltswidriger Logik zusammenzubauen und dann - das genau ist es, was bei Dir geschieht - darüber zu stolpern?

  4. Deine Baustellen (Übersicht über das hier zu Tage getretene):

    • Falsche Datenstruktur verbessern,
    • Verzeichnisstruktur überdenken oder/und über
      • require( realpath($_SERVER['DOCUMENT_ROOT'] . 'lib/bibliothek.php') ); ,
      • set_include_path('Pfad zu Include-Dir');
      • ini_set('include_path', 'Pfad zu Include-Dir'); oder,
      • am besten php_value include_path ".:Pfad zu Deinem weiteren Include-Dir" in der .htaccess nachdenken.
    • Errorreporting benutzen,
    • über den Sinn von require/include_once nachdenken, das Ergebnis konsequent anwenden und insgesamt:
    • PHP lernen. Auf einem Produktivsystem bzw. vom Internet oder auch nur von Dritten (auch Mitarbeiter können Böses wollen) aus erreichbaren System sehe ich übrigens bei den hier auch ohne nur eine Zeile Code sichtbar gewordenen Baustellen die Gefahr ganz erheblicher Sicherheitslücken.
    1. Da ich nichts erkennen kann, was an meiner Zusammenfassung auch nur falsch sein könnte, freue ich mich über die Diskussion und Beachtung der gefundenen Baustellen.

    2. Hi,

      • über den Sinn von require/include_once nachdenken, das Ergebnis konsequent anwenden

      Ich fange mal hiermit an. Denn, ein weiterer Test, bei dem mir eine Mail zugesendet wird, hat soeben Folgendes ergeben:

      include_once ("sub/konfiguration.php");
      include_once ("sub/vergleichstest.php");
      
      $betreff="Session verloren ".$test1." ".$test2.";
      usw.
      

      wobei die Variable: $test1 in sub/konfiguration.php zu finden ist ($test1 = "Inhalt1";) $test2 in sub/vergleichstest.php zu finden ist ($test2 = "Inhalt2";)

      Der Mailbetreff der eingetroffenen Mail lautete:

      Session verloren   Inhalt2
      

      Soll heißen, nur eine der Dateien wurde inkludiert. Beide Dateien befinden sich aber imselben Verzeichnis "sub".

      Lukas

      1. Tach!

        Soll heißen, nur eine der Dateien wurde inkludiert. Beide Dateien befinden sich aber imselben Verzeichnis "sub".

        Es kann auch sein, dass die Abarbeitung endete, bevor $test1 deklariert wurde. Was sagt das Error-Log? (Ist doch nun hoffentlich so konfiguriert, dass es mitschreiben kann?)

        dedlfix.

        1. Hi dedlfix,

          Es kann auch sein, dass die Abarbeitung endete, bevor $test1 deklariert wurde. Was sagt das Error-Log? (Ist doch nun hoffentlich so konfiguriert, dass es mitschreiben kann?)

          Asche über mein Haupt, Errorlog habe ich noch nicht nachkonfiguriert, wird gleich erledigt.

          Es kann auch sein, dass die Abarbeitung endete, bevor $test1 deklariert wurde.

          Stimmt, so weit hatte ich noch nicht gedacht. Aber es ist unwahrscheinlich, weil ganz am Anfang der Datei steht. Ich vermute, dass das include_once verhindert, dass die Datei inkludiert wird, denn die Datei war ganz sicher zuvor bereits inkludiert. Bleibt aber dann immer noch die Frage, warum das System den Inhalt dieser Datei "vergessen" hat.

          Ich habe das Include_once jetzt mal gegen ein include ausgetauscht, nachdem ich mir nochmal genau den Unetrschied angeschaut habe.

          Lukas

          1. Tach!

            Ich vermute, dass das include_once verhindert, dass die Datei inkludiert wird, denn die Datei war ganz sicher zuvor bereits inkludiert. Bleibt aber dann immer noch die Frage, warum das System den Inhalt dieser Datei "vergessen" hat.

            Falls das Inkludieren zum vorherigen Zeitpunkt geklappt hat, dann wird da wohl auf dem Weg von dort bis zur aktuellen Problemstelle jemand das $test1 überschrieben haben. Auch dabei verspreche ich mir vom Error-Log einen potentiellen Hinweis.

            dedlfix.

            1. Tach!

              Ich vermute, dass das include_once verhindert, dass die Datei inkludiert wird, denn die Datei war ganz sicher zuvor bereits inkludiert. Bleibt aber dann immer noch die Frage, warum das System den Inhalt dieser Datei "vergessen" hat.

              Falls das Inkludieren zum vorherigen Zeitpunkt geklappt hat, dann wird da wohl auf dem Weg von dort bis zur aktuellen Problemstelle jemand das $test1 überschrieben haben. Auch dabei verspreche ich mir vom Error-Log einen potentiellen Hinweis.

              Hi dedlfix,

              genau das dachte ioch auch. "Vergessen" heißt nix anderes als "überschreiben". Aber das ist (nach meinem jetztigen Verständnis) unmöglich. Ich deklariere und setze die Variable ausschließlich in meiner Konfigurationsdatei. Zudem, man kann ja im Editor seiner Wahl ggf. ein Verzeichnis komplatt nach dem Vorkommen eines Strings untersuchen lassen, da ist leicht festzustellen, dass $test1= oder auch $test1 = nicht bzw. nur in einer Datei vorkommt.

              Warten wir morgen die ersten kompletten Error-Log Einträge ab, nachdem ich diesbzgl. nachgebessert habe.

              Übrigens, per iclude (also ohne _once) kennt das Script auch $test1 wieder beim Versenden der Mail.

              Es ist ja geradezu verlockend, einen Workaround zu stricken, der den Fehler abfängt und ihn dergestalt korrigiert, dass er dann die Konfiguration neu einläd und alles wieder kennt, was zuvor verloren ging.

              Aber sowas macht man doch nicht, hm? :-/

              Lukas

            2. Falls das Inkludieren zum vorherigen Zeitpunkt geklappt hat, dann wird da wohl auf dem Weg von dort bis zur aktuellen Problemstelle jemand das $test1 überschrieben haben. Auch dabei verspreche ich mir vom Error-Log einen potentiellen Hinweis.

              Hi dedlfix.

              Fehler und Errorlog vorhanden. Was bedeutet "undefined index" genau? Weil, der inhalt von "undefined index" entspricht exakt dem Inhalt von $test1.

              Lukas

              1. Tach!

                Was bedeutet "undefined index" genau?

                Du greifst lesend auf ein Feld in einem Array zu, und dieses Feld existiert nicht. Du müsstest also auch mal das Array in die Debugausgabe schreiben, um das zu prüfen - falls du das noch nicht hast.

                dedlfix.

                1. Du greifst lesend auf ein Feld in einem Array zu, und dieses Feld existiert nicht. Du müsstest also auch mal das Array in die Debugausgabe schreiben, um das zu prüfen - falls du das noch nicht hast.

                  Hi dedlfix.

                  Na, ich dreh mich im Kreis. Lesend auf ein nicht vorhandenes Feld zuzugreifen, ist die Wirkung, nicht die Ursache :-( Ich sagte ja, mein Session-Array ist mehrdimensional. Eine Arrayebene wird per Variable aus der Konfiguration gesetzt. Bedeutet also, wenn dieser Wert flöten geht, wird der undefined index error erzeugt.

                  Sag mal, es wäre doch wirklich easy zu "übertünchen", indem ich bei jedem Seitenaufruf prüfe, ob die Konfigurationsdaten verloren gingen und falls ja, sie nochmal einzulesen. Aber darf man das?

                  Lukas

                  1. Tach!

                    Na, ich dreh mich im Kreis. Lesend auf ein nicht vorhandenes Feld zuzugreifen, ist die Wirkung, nicht die Ursache :-( Ich sagte ja, mein Session-Array ist mehrdimensional. Eine Arrayebene wird per Variable aus der Konfiguration gesetzt. Bedeutet also, wenn dieser Wert flöten geht, wird der undefined index error erzeugt.

                    Es ist im Prinzip egal, wie komplex dein Array ist. Du hast da jedenfalls entweder einen Key nicht drin, den du erwartest oder dein in einer Variable abgelegter Wert ist kein Key. Was auch immer es ist, das kannst du nur anhand des Debuggings in deinem Code herausfinden. Dass PHP etwas von sich aus vergisst, ist nicht sehr wahrscheinlich.

                    Sag mal, es wäre doch wirklich easy zu "übertünchen", indem ich bei jedem Seitenaufruf prüfe, ob die Konfigurationsdaten verloren gingen und falls ja, sie nochmal einzulesen. Aber darf man das?

                    Es gibt kein Gesetz dagegen. Natürlich kannst du das so machen, aber mich würde das nicht beruhigen, wenn da irgendwo Code ist, der Daten verliert.

                    dedlfix.

                    1. Hi dedlfix,

                      Es gibt kein Gesetz dagegen. Natürlich kannst du das so machen, aber mich würde das nicht beruhigen, wenn da irgendwo Code ist, der Daten verliert.

                      dedlfix.

                      Ich habe jetzte einen Kompromiss gemacht: Ich habes übertüncht und lasse mich dennoch inforieren, wann es passiert. So kann ich weiter am Problem arbeiten, ohne das der User immer seine Session verliert.

                      Zudem habe ich 2 Funktionen gefunden, in denen ich die Variable $test1 nutze, ohne sie am Anfang global gesetzt zu haben. Ggf. könnte hier ein Fehler gewesen sein, aber so richtig daran glauben tu ich nicht. Das Auswerten des Errorlogs fällt mir schwer, zudem habe ich bisher nichts gefunden, was mich im Errorlog weitergebracht hätte.

                      Lukas

                      1. Tach!

                        Zudem habe ich 2 Funktionen gefunden, in denen ich die Variable $test1 nutze, ohne sie am Anfang global gesetzt zu haben. Ggf. könnte hier ein Fehler gewesen sein, aber so richtig daran glauben tu ich nicht.

                        Wenn man mit global arbeiten muss, um sein Ziel zu erreichen, hat man eine Anwendung mit Verbesserungspotential.

                        Jedenfalls, eigene Variablen ohne global in Fuktionen sind stets lokal und beeinflussen eventuelle gleichnamige Variablen im globalen Scope nicht.

                        dedlfix.

          2. Ich vermute, dass das include_once verhindert, dass die Datei inkludiert wird, denn die Datei war ganz sicher zuvor bereits inkludiert.

            Was steht denn drin?

            Wenn Dein Include so aussieht

            <?php
            $foo = tuDies();
            

            also Schritte einfach ungekapselt abgearbeitet werden, dann ist include_once() falsch und include() bzw. require() richtig, weil diese Datei an der Stelle aufgerufen werden muss damit $foo = tuDies(); erneut abgearbeitet wird. Wenn in Deinem Include aber

            • Funktionen,
            • Klassen oder
            • Konstanten

            definiert werden, dann musst Du include_once(), in vielen Fällen besser: require_once() nehmen weil der auf das include() bzw. require() folgende Versuch, Funktionen, Klassen und Konstanten neu zu definieren, zu einem Fehler führt.

            (Das fällt übrigens unter den vierten und fünften Punkt der Liste der "Baustellen".)

            1. Hallo Rechtsstaatsvermisser,

              Punkt 1: Dein Name ist klasse. Ich bin in diesem Punkt ganz bei Dir!

              Wenn in Deinem Include aber

              • Funktionen,
              • Klassen oder
              • Konstanten

              definiert werden, dann musst Du include_once(), in vielen Fällen besser: require_once() nehmen weil der auf das include() bzw. require() folgende Versuch, Funktionen, Klassen und Konstanten neu zu definieren, zu einem Fehler führt.

              Punkt 2: Ich habe mein "include" gerade nciht vor mir (falscher Rechner), aber ich vermute, dass sowohl Funktionen als auch Konstanten als auch Variablen darin stehen.

              Lukas