Rolf B: Umgang mit zerstörter Session

Hallo,

ich spiele im Moment ein bisschen mit PHP herum und bin auf eine blöde Situation gestoßen.

Die letzte Aktion auf der Seite war heute nachmittag. Dann habe ich den Computer stehen gelassen, Wintersport geguckt, Essen gemacht, etc, und kam eben wieder.

Ein Klick auf einen Button der noch offenen Seite führte zu

session_start(): Failed to decode session object. Session has been destroyed in ....php on line ...

Autostart von Sessions ist aus, und session_start ist so ziemlich das erste, was ich mache. Der Rückgabewert von session_start war false. Okay - mehr als session_start() gibt's an dieser Stelle noch nicht und die Reaktion auf's false ist einfach nur ein exit. Frage ist nun, wie geh ich damit um und wie teste ich das.

In der Developer-PHP.INI hatte ich Defaultwerte, session.cookie_lifetime = 0 und session.gc_maxlifetime = 1440. Die gc_probability ist 1/1000. session.save_handler ist files, und session.save_path ist absolut und ohne Nesting-Level angegeben.

Irgendwo bei SO stehen Hinweise auf Themen mit CodeIgniter, den hab ich nicht. Nackiger files Sessionhandler. Und der save_path ist absolut angegeben.

Um nun den korrekten Umgang mit dieser Situation testen zu können, müsste ich aber erstmal ihre Entstehung verstehen und sie vor allem reproduzieren können. Und das schaffe ich nicht. Wenn ich gc_maxlifetime auf 10 setze und etwas warte, oder die Session-Datei lösche, oder ihr Dateidatum ein paar Stunden in die Vergangenheit schicke, startet PHP einfach kommentarlos eine neue Session und gibt aus session_start ein true zurück.

Wer hat ein paar Joule von der Energie des Verstehens für mich? Wie reproduziere ich diesen session-start Fehler?

Rolf

--
sumpsi - posui - obstruxi
  1. Hallo Rolf,

    ach Mist - das ist kein Zeitproblem, sondern passiert, wenn die Deserialisierung der Session-Datei fehlschlägt.

    Reproduzieren geligt durch einfaches Hineineditieren von Müll in die Session-Datei.

    Aber wieso da Müll drinstand, tja. Das weiß ich immer noch nicht, und dabei könnt ihr mir wohl auch nicht helfen. Meine Session-Werte sind Int, String und Objekte mit int und string drin. Da sind zwar auch Umlaute in UTF-8 dabei, aber das sollte ihn doch nicht stören...

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Ist das OS ein Debian? Da löscht ein Cronjob die Session-Dateien.

      https://www.stetic.com/developer/php-session-garbage-collection-in-anderen-verzeichnissen-unter-ubuntu-und-debian/

      1. Hallo Raketenwilli,

        nee, Windows 10. IIS mit PHP 8.0.2 als FastCGI.

        Sessionfiles abräumen passiert damit über den files Sessionmanager, an Hand der gc_probability und gc_maxlifetime, würde ich annehmen. Zumindest sehe ich im Sessionfiles-Verzeichnis keine Altlasten, das funktioniert also auch ohne automatisierten Task.

        Aber wie beschrieben - der Fehler taucht auf wenn im Sessionfile nicht das steht, womit er umgehen kann und die Deserialisierung schiefgeht.

        Die Problemherkunft ist mir nach wie vor unklar. Ich habe in dem Moment, wo das passierte, für VS Code die PHP Version umgestellt, weil die irrtümlich auf 7.4 stand, aber das PHP, das VS Code und Intelliphense für Syntaxcheck und LINT verwenden, sollte wohl mit dem PHP für den IIS nix am Bein haben. Das sind verschiedene Prozesse. Glaube ich 😉. Aber selbst wenn - im VS Code wird er keine Session aufmachen, und wenn doch, nicht mit der Session-ID aus der Webanwendung. Ein integriertes Debugging vom VS Code in den IIS hinein hab ich noch nicht hinbekommen, auf dem Weg kann also auch keine falsche PHP Version oder Session-ID hineinleaken und Sessionformate grillen.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hm. Da hab ich wohl alles, was ich für den Testcase brauche.

          1. Testcase:

            <?php
            error_reporting(E_ALL);
            ini_set( "display_errors", 1 );
            
            
            
            ini_set( "session.save_handler", "files" );
            ini_set( "session.save_path", "/var/www/local/session_test/sessions" );
            ini_set( "session.gc_maxlifetime", "30" );
            ini_set( "session.cache_limiter", "nocache" );
            
            
            $refresh = 65;
            
            $session_options=[
                'cookie_lifetime' => 86400,
            ];
            
            session_start( $session_options );
                
            if ( ! empty( $_SESSION['last_call'] ) ) {
            	$_SESSION['really_last_call'] = $_SESSION['last_call'];
            }
            $_SESSION['last_call'] = date( "Y-m-d H:i:s" )
            ?>
            <html>
            <head>
            <meta http-equiv="refresh" content="<?=$refresh;?>" />
            <title>Session-Test</title>
            </head>
            <body>
            <pre>
            <?php var_dump( $_SESSION ); ?>
            </pre>
            </body>
            </html>
            

            Also. Wenn ich das Sessionfile lösche bekomme ich keinen Fehler, es wird eiskalt eine neue gebaut.

            Aber wenn ich darin herumschreibe (Führendes Leerzeichen genügt) kommt diese Fehlermeldung:

            PHP Warning: session_start(): Failed to decode session object. Session has been destroyed in /var/www/local/session_test/test.php on line 19

            Jetzt muss man nur noch herausfinden, was bei Dir von wem in das Session-File geschrieben wird. Normalerweise ist das lediglich die serialisierte Variable:

            last_call|s:19:"2021-12-13 17:34:46";really_last_call|s:19:"2021-12-13 17:33:41"
            

            Kann ich mal sehen, was Dein Skript so treibt?

            b.t.w:

            nee, Windows 10. IIS mit PHP 8.0.2 als FastCGI.

            Naja. Das ist eine mir weitgehend unbekannte Umgebung... könnte ein Rechtskonflikt vorliegen?

            1. Naja. Das ist eine mir weitgehend unbekannte Umgebung... könnte ein Rechtskonflikt vorliegen?

              Auch nicht. Dann gibt es eine eindeutige Fehlermeldung...

              Was ich noch nicht probiert habe, was aber im Hinblick auf die Entwicklungsumgebung und erwähnte Umlaute nicht ganz unmöglich erscheint:

              Könnte es sein, dass Dir irgendwie eine BOM in das Session-File hineineditiert wurde?

              War ein Kind, eine Katze oder gar ein Wellensittich am Computer?

              1. kein weiterer Text

            2. Hallo Raketenwilli,

              Jetzt muss man nur noch herausfinden, was bei Dir von wem in das Session-File geschrieben wird.

              Die einzige Sessionmanipulation ist Lesen und Schreiben von $_SESSION-Einträgen. Da kommen Zahlen, Strings, Objekte und Arrays rein, was halt so nötig ist, um den Spielerfortschritt festzuhalten und bei einer Schlägerei die Gesundheit der Gegner zu tracken. Das Sessionfile wird vom PHP files Sessionmanager gelesen und geschrieben, da mach ich selbst nichts dran.

              Natürlich kann Unicode in der Session landen, als Teil eines Strings. Aber das ist eigentlich kein Problem.

              Kann ich mal sehen, was Dein Skript so treibt?

              Sind bereits einige 100 Zeilen Krimskrams. Ein Browserspielchen, zum Spaß (ich möchte ein Abenteuerspielebuch abbilden). Den Source poste ich jetzt eher nicht 😉. Wärest Du noch registriert, könnte ich Dir eine Post schicken. So schick ich Dir jetzt eine Mail an deine Kontaktadresse bei f…x.org

              Es kann höchstens sein, dass PHP die Session nicht sauber geschlossen hat und dann, als ich ein paar Stunden weg war, der IIS den FastCGI Prozess beendet hat, so dass die Datei nur teilweise gespeichert wurde. Das wäre dann ein PHP Bug, es sollte auch bei fatal errors die Session am Ende des Scripts immer committen und die Datei freigeben. Ein File Lock auf die Datei sollte es nur geben, solange der Request läuft.

              Ohne die Datei zu editieren (ein deutlich anormaler Usecase) bekomme ich den Fehler nicht mehr reproduziert. Aber ich kann ihn jetzt triggern und einen sauberen Restart ausführen.

              Rolf

              --
              sumpsi - posui - obstruxi