www.webdeveloper.com
Results 1 to 6 of 6

Thread: [RESOLVED] Session Variables Disappear

Hybrid View

  1. #1
    Join Date
    Jul 2010
    Location
    Cobalt, Ontario, Canada
    Posts
    15

    resolved [RESOLVED] Session Variables Disappear

    I access my session variable and it's fine. I access it again a few lines later and it's gone.

    I worked around this problem by saving the session variable into $temp the very first time I accessed it, then I used $temp in its place and didn't access the session variable again until it was time to set its value. It works fine now, but the question still remains: Why does $_SESSION['directory'] return a value the first time and not the second?

    First the code, then a short explanation of it, then the output:

    Code:
    <?php
    
    session_start();
    debugMsg('session_id() = ' . session_id());
    $headersSent = false;
    
    define (DEBUG, 1);
    
    header ('Content-Language: en');
    header ('Content-Type: text/html; charset=ISO-8859-1');
    header ('Content-Script-Type: text/javascript');
    debugMsg ('_GET[\'directory\']      = ' . $_GET['directory']);
    debugMsg ('_COOKIE[\'directory\']   = ' . $_COOKIE['directory']);
    debugMsg ('_SESSION[\'directory\']  = ' . $_SESSION['directory']);
    
    $directory = decodePlus ($_GET['directory']);
    debugMsg ('After 1st Change: length/directory = ' . strlen($directory) . '/' . $directory);
    if ($directory == '') {
      debugMsg('Entering then clause of 1st if statement to get the directory from the cookie.');
      $directory = decodePlus ($_COOKIE['directory']);
      debugMsg ('After 2nd Change: length/directory = ' . strlen($directory) . '/' . $directory);
    }
    if ($directory == '') {
      debugMsg('Entering then clause of 2nd if statement to get the directory from the session variable.');
      debugMsg ('_SESSION[\'directory\']  = ' . $_SESSION['directory']);
      $directory = decodePlus ($_SESSION['directory']);
      debugMsg ('After 3rd Change: length/directory = ' . strlen($directory) . '/' . $directory);
    }
    if ($directory != '') {
      debugMsg('Entering then clause of 3rd if statement to set the cookie and the session variable for directory.');
      setcookie ('directory', ($directory), time()+86400000, '/', '.friendlyneighbourguide.ca');
      $_SESSION['directory'] = $directory;
    }
    debugMsg ('At end: length/directory = ' . strlen($directory) . '/' . $directory);
    
    $headersSent = true;
    debugMsg(''); //to send all the queued messages
    ?>
    
    <html><head>
    
    <META HTTP-EQUIV="Content-Type"        CONTENT="text/html; charset=ISO-8859-1">
    <META HTTP-EQUIV="Content-Script-Type" CONTENT="text/javascript">
    
    <?php
    
    function debugMsg ($msg) {
      if (DEBUG == TRUE) {
        static $textWaitingForHeaders = "";
        static $waitingTextWasSent = false;
        global $headersSent;
        $fullMsg = "\n<!-- debugMsg: {$msg} -->";
        if ($headersSent) {//headers were sent
          //go ahead and output the waiting messages and the new messages
          if ($waitingTextWasSent) {//we already sent the waiting text
            echo ($fullMsg);
          }else{//headers were sent, but waiting text was not sent
            //we can send the waiting text now
            echo ($textWaitingForHeaders . $fullMsg);
            $waitingTextWasSent = true;
          }//end if ($waitingTextWasSent)
        }else{//headers have not been sent yet
          //we cannot output text yet, so save it for later
          $textWaitingForHeaders .= $fullMsg;
        }//end if ($headersSent)
      }//end if (DEBUG)
    }//end function debugMsg ($msg)
    
    
    function encodePlus ($str) {
      if ($str) { $s = $str; }else{ $s = ''; };
      $s = str_replace ("\\", "", $s); //We do not want backslashes anywhere.
      $s = str_replace ("+", "%2b", $s); //Preseve the plus sign so it doesn't get changed to a space in unescape().
      $s = rawurlencode ($s); //use rfc 1738 - spaces become $20, not plus signs
      return $s;
    }
    
    function decodePlus ($str) {
      $s = $str;
      if ($str) { $s = $str; }else{ $s = ''; };
      $s = str_replace ("\\", "", $s); //We do not want backslashes anywhere.
      $s = str_replace ("+", " ", $s); //Real plus signs were preserved, so this one is really a space.
      $s = urldecode ($s); //Don't use rfc1738 because the server puts plus signs in the cookies.
      debugMsg("Leaving decodePlus():  return value is '{$s}'");
      return $s;
    }
    
    ?>
    </head>
    <body>
    <pre>
    <?php
    print_r($_SESSION);
    ?>
    </pre>
    </body>
    </html>
    DebugMsg() is a function I wrote to allow me to see debug output without disrupting the web page. I can view its output with View Source in either FireFox or IE. Because I want to use DebugMsg() before all the headers have been written, it queues the output until I set $headersSent to true. Then it outputs all the queued messages the next time it's called.

    The mainline routine sets $directory to the URL argument if it is present. If not, it sets it to the cookie if it is present. If not, it sets it to the session variable. If, after that process, $directory received a value, then both the cookie and the session variable are updated.

    Here's the output from the above code. To get this output, I first ran the code and got the session id. Then I ran the code again with ?PHPSESSID=7eb02a9e918dd8bec560feffe7dfc4b8f tacked onto the end of the URL. Then I ran it again with &directory=xyz tacked onto the end of that. After that run, the session variable was set. Then I ran it again, but this time, I removed &directory=xyz from the URL. That's what gave me the following output:

    Code:
    <!-- debugMsg: session_id() = 7eb02a9e918dd8bec560feffe7dfc4b8f -->
    <!-- debugMsg: _GET['directory']      =  -->
    <!-- debugMsg: _COOKIE['directory']   =  -->
    <!-- debugMsg: _SESSION['directory']  = xyz -->
    <!-- debugMsg: Leaving decodePlus():  return value is '' -->
    <!-- debugMsg: After 1st Change: length/directory = 0/ -->
    <!-- debugMsg: Entering then clause of 1st if statement to get the directory from the cookie. -->
    <!-- debugMsg: Leaving decodePlus():  return value is '' -->
    <!-- debugMsg: After 2nd Change: length/directory = 0/ -->
    <!-- debugMsg: Entering then clause of 2nd if statement to get the directory from the session variable. -->
    <!-- debugMsg: _SESSION['directory']  =  -->
    <!-- debugMsg: Leaving decodePlus():  return value is '' -->
    <!-- debugMsg: After 3rd Change: length/directory = 0/ -->
    <!-- debugMsg: At end: length/directory = 0/ -->
    <!-- debugMsg:  -->
    <html><head>
    The reason the cookie never has a value is because I disabled cookies in my browser.

    Notice in the fourth line that the session variable DOES have a value. Notice also in the eleventh line that the session variable no longer has a value.

    Copied from the code above, here are the lines of code that executed between the output shown in lines 4 and 11:

    Code:
    $directory = decodePlus ($_GET['directory']);
    debugMsg ('After 1st Change: length/directory = ' . strlen($directory) . '/' . $directory);
    if ($directory == '') {
      debugMsg('Entering then clause of 1st if statement to get the directory from the cookie.');
      $directory = decodePlus ($_COOKIE['directory']);
      debugMsg ('After 2nd Change: length/directory = ' . strlen($directory) . '/' . $directory);
    }
    if ($directory == '') {
      debugMsg('Entering then clause of 2nd if statement to get the directory from the session variable.');
    So the question is: What did I do wrong?

  2. #2
    Join Date
    Sep 2010
    Posts
    160
    I must say I can't see it either, but try adding more debug messages and print the session variable multiple times. Before and after and in the if-statements above where it currently disappears.

    Archie

  3. #3
    Join Date
    Jul 2010
    Location
    Cobalt, Ontario, Canada
    Posts
    15

    resolved It Still Doesn't Work, But Now I Know Why!

    I was just going to go on my merry way with my workaround, but it kept bugging at me. I couldn't get away from your suggestion to add more debugMsg() statements. After all, it should only take a few minutes, right?

    Well, believe it or not, that was right. I had my answer in less than five minutes.

    Here's the code rewrite. I shortened it by deleting all the lines that had nothing to do with this problem. I added a whole bunch of debugMsg()s as you suggested, but in the code below I removed all the debugMsg()s that didn't reveal anything new:

    Code:
    <?php
    session_start();
    debugMsg('session_id() = ' . session_id());
    $headersSent = false;
    define (DEBUG, 1);
    debugMsg ('1_SESSION[\'directory\']  = ' . $_SESSION['directory']);
    $directory = decodePlus ($_GET['directory']);
    debugMsg ('2_SESSION[\'directory\']  = ' . $_SESSION['directory']);
    if ($directory == '') {
      $directory = decodePlus ($_COOKIE['directory']);
    }
    if ($directory == '') {
      $directory = decodePlus ($_SESSION['directory']);
    }
    if ($directory != '') {
      setcookie ('directory', ($directory), time()+86400000, '/', '.friendlyneighbourguide.ca');
      $_SESSION['directory'] = $directory;
    }
    $headersSent = true;
    debugMsg(''); //to send all the queued messages
    ?>
    <html><head>
    <?php
    
    function debugMsg ($msg) {
      if (DEBUG == TRUE) {
        static $textWaitingForHeaders = "";
        static $waitingTextWasSent = false;
        global $headersSent;
        $fullMsg = "\n<!-- debugMsg: {$msg} -->";
        if ($headersSent) {//headers were sent
          //go ahead and output the waiting messages and the new messages
          if ($waitingTextWasSent) {//we already sent the waiting text
            echo ($fullMsg);
          }else{//headers were sent, but waiting text was not sent
            //we can send the waiting text now
            echo ($textWaitingForHeaders . $fullMsg);
            $waitingTextWasSent = true;
          }//end if ($waitingTextWasSent)
        }else{//headers have not been sent yet
          //we cannot output text yet, so save it for later
          $textWaitingForHeaders .= $fullMsg;
        }//end if ($headersSent)
      }//end if (DEBUG)
    }//end function debugMsg ($msg)
    
    
    function decodePlus ($str) {
      debugMsg ('31_SESSION[\'directory\']  = ' . $_SESSION['directory']);
      $s = $str;
      if ($str) { $s = $str; }else{ $s = ''; };
      $s = str_replace ("\\", "", $s); //We do not want backslashes anywhere.
      $s = str_replace ("+", " ", $s); //Real plus signs were preserved, so this one is really a space.
      $s = urldecode ($s); //Don't use rfc1738 because the server puts plus signs in the cookies.
      debugMsg ('37_SESSION[\'directory\']  = ' . $_SESSION['directory']);
      return $s;
    }
    
    ?>
    </head>
    <body>
    <pre>
    <?php
    print_r($_SESSION);
    ?>
    </pre>
    </body>
    </html>
    Once again, I ran the code to get the PHPSESSID, then I ran it again with "&directory=xyz" to set the cookie. Then I ran it again without the "&directory=xyz". This is the output.

    Code:
    <!-- debugMsg: session_id() = 392cad87cc3bf14d67093a0b01300ffb -->
    <!-- debugMsg: 1_SESSION['directory']  = xyz -->
    <!-- debugMsg: 31_SESSION['directory']  = xyz -->
    <!-- debugMsg: 37_SESSION['directory']  = xyz -->
    <!-- debugMsg: 2_SESSION['directory']  =  -->
    The debugMsg()'s show that the culprit line (between 37 and 2) is the assignment operator in:

    Code:
    $directory = decodePlus ($_GET['directory']);
    And that's when the light bulb appeared above my head! $directory is a reference to $_SESSION['directory']! They both refer to the same variable. When I set $directory to "", I am also setting $_SESSION['directory'] to "". Problem Solved!

    I ought to have suspected this. I knew that $x refers to $_COOKIE['x'], and in fact relied on that fact in an earlier version of my code.

    I wonder what else $x is a reference for. I know it is a reference for $_COOKIE['x'] and $_SESSION['x']. Is it also a reference for $_POST['x'] or $_GET['x'] or $_REQUEST['x'] or anything else I haven't thought of yet? And also, what if they all exist and have all been set to unique values. Which one would $x be a reference for? It can't refer to all of them.

    Unfortunately, time constraints won't let me delve into it any further at this time. Perhaps later? We'll see.

  4. #4
    Join Date
    Jul 2010
    Location
    Cobalt, Ontario, Canada
    Posts
    15

    resolved I Can't Deny My Compulsions

    Well, it figures! I said I wouldn't go any further, but once again I couldn't let it go. So here are the official answers to the final questions I raised above.

    www.php.net/manual/en/security.globals.php explains why the default for register_globals was changed from ON to OFF in v4.2.0. When register_globals is on, env, get, post, cookie, and server variables can be referenced by simple $x variables so that $x could refer to $_ENV['x'], $_GET['x'], $_POST['x'], $_COOKIE['x'], or $_SERVER['x'], whichever one was set.

    That still leaves the question, "What if more than one is set? Which one will $x refer to?" The page at www.php.net/manual/en/ini.core.php#ini.variables-order tells us that variables_order determines which takes precedence over which. It says:

    If the deprecated register_globals directive is on, then variables_order also configures the order the ENV, GET, POST, COOKIE and SERVER variables are populated in global scope. So for example if variables_order is set to "EGPCS", register_globals is enabled, and both $_GET['action'] and $_POST['action'] are set, then $action will contain the value of $_POST['action'] as P comes after G in our example directive value.
    And so, *finally*, I am satisfied. I hope someone else gets some value from this thread. That will make it all worthwhile.

  5. #5
    Join Date
    Oct 2010
    Location
    Ohio
    Posts
    233
    Very good information! I'm glad you satisfied your curiousity!

  6. #6
    Join Date
    Sep 2010
    Posts
    160
    Congratulations.

    Archie

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles