Enrico: Notice: Undefined index bei Session-Variablen

Hallo,

Session-Variablen soll(t)en doch datei- und auch funktionsübergreifend gültig sein, oder?

Ich habe nun folgenden Aufbau:

Datei "standard.php":

require ("standardFunktionen.php");

function seiteAufbauen()
{
   initialisieren();
   sprachauswahlKonfigurieren();
}

Datei "standardFunktionen.php":

function initialisieren()
{
   if (!isset ($_SESSION["seite"]) || !preg_match ("/^(home|band|...)$/", $_SESSION["seite"]))
   {
      $_SESSION["seite"] = "home";
   }

   if (!isset ($_SESSION["sprache"]) || !preg_match ("/^(d|e)$/", $_SESSION["sprache"]))
   {
      spracheKonfigurieren();
   }
}

function spracheKonfigurieren()
{
   if (!isset ($_SERVER["HTTP_ACCEPT_LANGUAGE"]) || empty ($_SERVER["HTTP_ACCEPT_LANGUAGE"]))
   {
      $_SESSION["sprache"] = "d";
   }
   else
   {
      $unterstuetzteSprachen = preg_split("{,\s*}", $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
      $qualitaet = 0;

      if (is_array ($unterstuetzteSprachen) && (count ($unterstuetzteSprachen) > 0))
      {
         foreach ($unterstuetzteSprachen as $schluessel => $wert)
         {
            if (!preg_match ("{^([a-z]{1,8}(?:-[a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$}i", $wert, $treffer))
            {
               continue;
            }

            $details = explode ("-", $treffer[1]);

            if (isset ($treffer[2]))
            {
               $prioritaet = floatval ($treffer[2]);
            }
            else
            {
               $prioritaet = 1.0;
            }

            while (count ($details) > 0)
            {
               if ($prioritaet > $qualitaet)
               {
                  $sprache = strtolower (substr ($details[0], 0, 1));
                  $qualitaet = $prioritaet;

                  break;
               }

               break;
            }
         }
      }

      if ($sprache == "de")
      {
         $_SESSION["sprache"] = "d";
      }
      else
      {
         $_SESSION["sprache"] = "e";
      }
   }
}

function sprachauswahlKonfigurieren()
{
   if ($_SESSION["sprache"] == "d") <=== [1]
   {
      $klasse = "englisch";
      $auswahl = "e";
   }
   else
   {
      $klasse = "deutsch";
      $auswahl = "d";
   }

   $onclick = 'seiteAufrufen("' . $_SESSION["seite"] . '", ' . (isset ($_SESSION["unterseite"]) ? $_SESSION["unterseite"] : "") . '")'; <=== [2]

   echo '<div id="sprachauswahl" class="' . $klasse . '" onclick=' . $onclick . '></div>';
}

Ich bekomme allerdings folgende Mitteilungen:

Notice: Undefined index: sprache in C:\XAMPP\htdocs\homepage\php\standardFunktionen.php on line 75 (markiert mit [1])
Notice: Undefined index: seite   in C:\XAMPP\htdocs\homepage\php\standardFunktionen.php on line 86 (markiert mit [2])

Was habe ich im Code falsch gemacht?

Danke und Gruß Enrico

  1. Hi,

    Session-Variablen soll(t)en doch datei- und auch funktionsübergreifend gültig sein, oder?

    so ist es gedacht, ja. Und wenn das nicht hinhaut, dann ist sehr wahrscheinlich beim Erzeugen oder Wiederaufnehmen der Session etwas schiegegagnen. Klassischer Fehler ist hier eine Ausgabe an den Client, bevor session_start() aufgerufen wird (und wenn's nur 'ne Leerzeile oder 'ne BOM ist). Dann kann nämlich das Session-Cookie nicht mehr gesetzt werden.
    Allerdings sollte dir auch das mit einer Notice mitgeteilt werden.

    Aus deinem Codeauszug kann man das leider nicht erkennen, weil gerade das entscheidende Stück, nämlich der Script- oder Dateianfang nicht dabei ist. Ich sehe auch weit und breit kein session_start().

    So long,
     Martin

    1. Hallo Martin,

      danke für Deine Antwort.

      Hier die relevante php-Datei, die die Datei "standard.php" einbindet:

      <?php
      
         session_start();
      
      ?>
      <!DOCTYPE html>
      <html>
         <head>
            <link rel="stylesheet" href="css/standardHead.css" type="text/css" media="only screen"/>
            <script src="javascript/standardHead.js"></script>
         </head>
         <body>
      
            <div id="ueberlagerung">
               <img id="ladeanzeige">
            </div>
      
            <script>ladeanzeige()</script>
      
            <?php
      
               require ("php/standard.php");
      
            ?>
      
            ...
      
         </body>
      </html>
      

      Ich habe eine Vermutung:

      Muss ich "session_start()" auch bei den inkludierten Dateien, die mit Session-Variablen zu tun haben, einbinden?

      Gruß Enrico

      1. Hallo Martin,

        Muss ich "session_start()" auch bei den inkludierten Dateien, die mit Session-Variablen zu tun haben, einbinden?

        Das war es nicht.

        Baue ich session_start() auch in die inkludierten Dateien ein, dann wirft er mir den Hinweis, dass bereits eine Sitzung gestartet wurde, nämlich in der einbindenden php-Datei.

        Gruß Enrico

      2. Muss ich "session_start()" auch bei den inkludierten Dateien, die mit Session-Variablen zu tun haben, einbinden?

        Nein. PHP pappt alles, was du mit include(), require() & Co. einbindest, stumpfsinnig zu einer großen Textdatei zusammen.

        Du musst lediglich darauf achten, dass eine Funktion wie session_start() in diesem Textklumpen "ganz oben" aufgerufen wird.

        1. Moin!

          PHP pappt alles, was du mit include(), require() & Co. einbindest, stumpfsinnig zu einer großen Textdatei zusammen.

          Das ist falsch. Du suggerierst, dass beim Parsen zuerst mal alle includes/requires gefunden und damit ein großer Quelltext zusammengebaut wird, den PHP dann ausführt.

          Include oder Require setzen die Codeausführung in der angegebenen Datei fort, und auch nur, wenn sie selbst ausgeführt werden. Das beinhaltet zu Beginn das Parsen des neu erwähnten Quellcodes bzw. das Auslesen der Opcodes für diese Datei aus dem Cache. Der Code hat dann zwei mögliche Effekte: Entweder definiert er globale Symbole (Funktionen-, Klassen- oder Konstantendefinitionen), oder er ändert etwas am globalen Zustand des laufenden Requests (alles, was keine Funktionen, Klassen oder Konstanten definiert, sondern "ausführt").

          Man kann wie bei gewöhnlichen Funktionen auch Rückgabewerte haben - das ist toll für Konfigurationsdaten:

          # a.php
          $result = include('b.php');
          var_dump($result)
          
          # b.php
          return ['foo'=>'bar'];
          
          # Ausgabe
          array(1) {
            ["foo"]=>
            string(3) "bar"
          }
          

          Du musst lediglich darauf achten, dass eine Funktion wie session_start() in diesem Textklumpen "ganz oben" aufgerufen wird.

          Vor der ersten Ausgabe von Inhalt an den Ausgabekanal, also den Browser, reicht.

          Wenn man sich an Konventionen hält, dann tut man in Include-Dateien entweder nur Definitionen von globalen Symbolen rein (die kann man einbinden, ohne dass irgendeine Textausgabe passiert), oder alternativ "Nebenwirkungen", aber nie beides gleichzeitig. Das erleichtert auch das Autoloading.

          Grüße Sven

          1. PHP pappt alles, was du mit include(), require() & Co. einbindest, stumpfsinnig zu einer großen Textdatei zusammen.

            Das ist falsch. Du suggerierst, dass beim Parsen zuerst mal alle includes/requires gefunden und damit ein großer Quelltext zusammengebaut wird, den PHP dann ausführt.

            Include oder Require setzen die Codeausführung in der angegebenen Datei fort, und auch nur, wenn sie selbst ausgeführt werden.

            Es ist im Endeffekt unerheblich, wann die Dateien zusammengepappt werden, es bleibt eine große zusammengepappte Masse. Oder möchtest du behaupten,

            if ($bla == 1) {
               echo "bla";
            }
            

            wäre etwas anderes (im Sinne von: würde ein anderes Ergebnis erzeugen) als

            if ($bla == 1) {
               echo "bla"; // tatsächlich mittels include("bla.php") eingebunden
            }
            

            Um das grundlegende Prinzip zu verstehen, reicht die Vorstellung, dass include() & Co. durch den jeweiligen Dateiinhalt ersetzt werden. Es ging hier konkret um die Fehlinterpretation, dass die Dateien eine Art eigenständige Module wären und session_start() deshalb in jeder einzubindenden Datei aufgerufen werden müsse.

            1. Moin!

              Es ist im Endeffekt unerheblich, wann die Dateien zusammengepappt werden, es bleibt eine große zusammengepappte Masse. Oder möchtest du behaupten,

              if ($bla == 1) {
                 echo "bla";
              }
              

              wäre etwas anderes (im Sinne von: würde ein anderes Ergebnis erzeugen) als

              if ($bla == 1) {
                 echo "bla"; // tatsächlich mittels include("bla.php") eingebunden
              }
              

              Das Ergebnis ist dasselbe - die Erzeugung unterschiedlich. Oder würdest du behaupten, dass

              if ($bla == 1) {
                 printf("bla");
              }
              

              dasselbe ist.

              Include/require pappen eben nicht nur Quelltext zusammen - deshalb darf man sie auch nicht überall benutzen, um Quelltext reinzupappen, sondern nur dort, wo Funktionen gewöhnlicherweise aufrufbar sind.

              Um das grundlegende Prinzip zu verstehen, reicht die Vorstellung, dass include() & Co. durch den jeweiligen Dateiinhalt ersetzt werden. Es ging hier konkret um die Fehlinterpretation, dass die Dateien eine Art eigenständige Module wären und session_start() deshalb in jeder einzubindenden Datei aufgerufen werden müsse.

              Es ist in Ordnung, diese näherungsweise Annahme zu verwenden, wenn sie als solche gekennzeichnet wird. Ansonsten wird das als Funktionsbeschreibung der Realität mißverstanden.

              Grüße Sven

  2. Setze …

    require ("standardFunktionen.php");
    
    function seiteAufbauen()
    {
    

    var_dump($_SESSION);

    initialisieren();

    var_dump($_SESSION);

    sprachauswahlKonfigurieren(); }

    function initialisieren()
    {
    

    var_dump($_SESSION);

    if (!isset ($_SESSION["seite"]) || !preg_match ("/^(home|band|...)$/", $_SESSION["seite"])) { $_SESSION["seite"] = "home"; }

    var_dump($_SESSION);

    if (!isset ($_SESSION["sprache"]) || !preg_match ("/^(d|e)$/", $_SESSION["sprache"])) { spracheKonfigurieren(); }

    var_dump($_SESSION);

    }

    function sprachauswahlKonfigurieren() {

    var_dump($_SESSION);

    if ($_SESSION["sprache"] == "d") <=== [1] { $klasse = "englisch"; $auswahl = "e"; } else { $klasse = "deutsch"; $auswahl = "d"; }

    $onclick = 'seiteAufrufen("' . $_SESSION["seite"] . '", ' . (isset ($_SESSION["unterseite"]) ? $_SESSION["unterseite"] : "") . '")'; <=== [2]

    echo '<div id="sprachauswahl" class="' . $klasse . '" onclick=' . $onclick . '></div>'; }

    … um das Problem einzugrenzen.

    Es kann eigentlich nicht sein, dass du in initialisieren() $_SESSION["seite"] belegst und in dem gleich in der nächsten Zeile folgenden Funktionsaufruf von sprachauswahlKonfigurieren() eben dieser gerade gesetzte Wert nicht mehr existieren soll.

    Der exzessive Gebrauch von Debug-Ausgaben sollte gerade für solche Unmöglichkeiten der Weg der Wahl sein.

    1. Hallo Suppengrün,

      danke für Deine Antwort.

      Ich bekomme nur bei var_dump unmittelbar nach Funktionseintritt in sprachauswahlKonfigurieren() eine Ausgabe und zwar dass Session leer ist, bei allen anderen Stellen erhalte ich keinerlei var_dump-Ausgaben im Browser.

      An den Abfragen kann ich keine(n) Fehler entdecken.

      ^^

      Gruß Enrico

      1. Hallo,

        Ich bekomme nur bei var_dump unmittelbar nach Funktionseintritt in sprachauswahlKonfigurieren() eine Ausgabe und zwar dass Session leer ist

        und das, obwohl du gerade eben etwas hineingeschrieben hast?! Da ist doch etwas oberfaul.

        bei allen anderen Stellen erhalte ich keinerlei var_dump-Ausgaben im Browser.

        Keine?! Auch das ist theoretisch nicht möglich. Das Array $_SESSION wird von PHP in jedem Fall angelegt, also muss var_dump() zumindest ein leeres Array anzeigen. Wobei auch leer nicht ganz okay ist, siehe oben. Da läuft irgendwas grundsätzlich verkehrt.

        So long,
         Martin

        1. Hallo,

          Ich bekomme nur bei var_dump unmittelbar nach Funktionseintritt in sprachauswahlKonfigurieren() eine Ausgabe und zwar dass Session leer ist

          und das, obwohl du gerade eben etwas hineingeschrieben hast?! Da ist doch etwas oberfaul.

          Das kann nur bedeuten, dass die Hauptfunktion seiteAufbauen() gar nicht aufgerufen wird und sprachauswahlKonfigurieren() von irgendwo anders.

          Auch wenn's auf den ersten Blick vielleicht merkwürdig erscheint, ist das gar nicht so abwegig. Wo seiteAufbauen() aufgerufen werden soll, steht nicht im zitierten Code, und vor allem würde es erklären, warum $_SESSION leer ist – $_SESSION wird schließlich in seiteAufbauen() bzw. seiner Unterfunktion initialisieren() belegt: Kein seiteAufbauen(), kein $_SESSION-Inhalt.

          Nächster Schritt: Verfolgen des Skriptlaufs bis zum Aufruf von seiteAufbau(). Dazu nochmals der Tipp, das Skript ruhig mit einer Unzahl an Testausgaben (echo "1", echo "2", etc) vollzupflastern.

          1. Hallo Suppengrün,

            wie ich Martin eben geschrieben habe, packe ich jetzt alles - ohne einzelne Funktionen - in einen "großen" Code ohne Funktionsaufrufe und schaue mal, ob das dann klappt und dann lagere ich alles Schritt für Schritt in eigene Funktionen aus. Dann wird sich hoffentlich zeigen, woran's lag.

            Gruß

            Enrico

            1. Tach!

              wie ich Martin eben geschrieben habe, packe ich jetzt alles - ohne einzelne Funktionen - in einen "großen" Code ohne Funktionsaufrufe und schaue mal, ob das dann klappt und dann lagere ich alles Schritt für Schritt in eigene Funktionen aus. Dann wird sich hoffentlich zeigen, woran's lag.

              Ganz schlechte Strategie. Wie wäre es, die Fehlerursache zu suchen und nicht einfach nur den Code hin- und her zu schubsen? Das wichtigste Werkzeug wurde dir bereits mehrfach genannt: var_dump()

              Durchlaufe deinen Code so wie PHP es tun würde, oder besser gesagt tun soll. Überall da, wo Variablen eine Rolle spielen, schau dir ihren Inhalt mit var_dump() an. Auch ganze Ausdrücke kann man an var_dump() verfüttern, beispielsweise die Bedingungen in if-Anweisungen. Irgendwo stimmt Wunsch und Wirklichkeit nicht überein. Das musst du finden. Code unverändert umkopieren bringt vielleicht rein zufällig den Fehler zu Fall, es kommt aber eher darauf an, den Fehler zu finden, ihn zu verstehen und die Ursache nachhaltig zu beseitigen.

              dedlfix.

              1. Hallo dedlfix,

                Wie wäre es, die Fehlerursache zu suchen und nicht einfach nur den Code hin- und her zu schubsen? Das wichtigste Werkzeug wurde dir bereits mehrfach genannt: var_dump()

                Bin schon dabei :-)

                Ich hatte den Code zunächst in eine komplette Datei gepackt und bin, da es so funktioniert, nun dabei, den Code Schritt für Schritt wieder auszulagern, in einzelne Funktionen zu packen und mir mittels var_dump() die Werte ausgeben zu lassen.

                Gruß

                Enrico

        2. Hallo Martin,

          sorry, bin grad erst von einem Dartspiel zurückgekommen.

          und das, obwohl du gerade eben etwas hineingeschrieben hast?! Da ist doch etwas oberfaul. Keine?!

          Ja, so ist es.

          Ich packe jetzt alles - ohne einzelne Funktionen - in einen "großen" Code ohne Funktionsaufrufe und schaue mal, ob das dann klappt und dann lagere ich alles Schritt für Schritt in eigene Funktionen aus. Dann wird sich hoffentlich zeigen, woran's lag.

          Gruß

          Enrico