Page 1 of 1

$_SESSION variable madness [rev title]

Posted: Sat May 02, 2009 9:44 am
by Bill H
The session variable is created in a menu script, conditionally the first time that the menu is executed.

Code: Select all

if (isset($_GET['Owner']))        // coming from main menu
{    $_SESSION['ListFor'] = 0 + $_GET['Owner'];
     $_SESSION['DispStat'] = 4; 
} 
 
This being a menu, it calls a bunch of other scripts, many of which use the $_SESSION vars, and one of which may alter the display var.
All of the "Cyr" and subsequent vars exist long before the menu script can be executed.

Code: Select all

if (isset($_SESSION['DispStat']))
{    if ($_SESSION['Cyr'] < $_SESSION['Lyr'] || ($_SESSION['Cyr'] == $_SESSION['Lyr'] && $_SESSION['Cmth'] <= $_SESSION['Lmth']))
          $_SESSION['DispStat'] = 4;
     else $_SESSION['DispStat'] = 5;              // the status to display ("if Stat > $_SESSION['DispStat']")
}
 
If the user calls any other script first, then the alteration of $_SESSION['DispStat'] occurs perfectly. If, however, the user calls the script which alters that variable immediately upon landing on that menu, that is the same execution of the script which initially sets that variable, then the alteration does not occur. The menu script is correctly using the $_SESSION['ListFor'] in that initial execution, but the $_SESSION['DispStat'] is used only in scripts called by the menu script.

Yes, session_start() is called at the beginning of all scripts. I have run them with error reporting set at E_ALL and gotten no errors. The call of the script that alters the variable is after the code that sets it. I thought of flushing right after it and tried that but, as expected really, no joy because the rest of the script had to have flushed or the menu would not be on the user's screen.

So, when does a $_SESSION variable actually exist? And why does the display variable not get altered if called immediately upon the menu creation, but successfully get altered at any other time?

Re: Delayed creation of $_SESSION variable?

Posted: Sat May 02, 2009 12:22 pm
by Benjamin

Code: Select all

 
session_start();
$_SESSION['foo'] = 'test';
echo $_SESSION['foo'];
 
Session variables are set immediately and there should be no delay. The variable should be available for use after it is set in any code that follows.

I can't really find an issue with what you have posted so far. I would do a dump of the session data and verify what the values are. I believe there is a logic error someplace else that is causing a bug that is confusing.

Code: Select all

 
echo '<pre>' . print_r($_SESSION, true) . '</pre>';
 

Re: Delayed creation of $_SESSION variable?

Posted: Sat May 02, 2009 1:06 pm
by Bill H
Thought I had covered everything I had done, but I forgot that. Good point but, yep, did that too. (I don't bother with the <pre> thing but...) The display var is there, but it doesn't get changed when the "sub" script is called after the initial menu call. Only on subsequent calls. Your statement agrees with my previous knowledge, so... Yeah, it's something in the logic that I'm missing, for sure. Still digging.

I have not done a $_SESSION dump in the "sub" script, since it has no screen output. I'm going to try that and see what it does.

Re: Delayed creation of $_SESSION variable?

Posted: Sat May 02, 2009 1:44 pm
by Bill H
Typical $_SESSION var dump, and it is consistent no matter where I dump it.

Code: Select all

Array ( [regownr] => 81 [Lyr] => 2009 [Lmth] => 3 [Cyr] => 2009 [Cmth] => 3 [ListFor] => 81 [DispStat] => 4 )
Here is the script in its entirety: creset.php

Code: Select all

 
session_cache_limiter("private,must-revalidate");
session_start();
 
if (isset($_POST['Plus_x']))                      // wants to advance a month
{    $_SESSION['Cmth']++;
     if ($_SESSION['Cmth'] > 12)                  // bumped to next year
     {    $_SESSION['Cmth'] = 1;                  // January
          $_SESSION['Cyr']++;                     // of next year
     }
}
else if (isset($_POST['Minus_x']))                // wants to back up a month
{    $_SESSION['Cmth']--;
     if ($_SESSION['Cmth'] == 0)                  // bumped to last year
     {    $_SESSION['Cmth'] = 12;                 // December
          $_SESSION['Cyr']--;                     // of last year
     }
}
else                                              // only use the dropdowns
{    $_SESSION['Cmth'] = $_POST['Mth'];           // when the +/- buttons are
     $_SESSION['Cyr'] = $_POST['Yr'];             // neither one clicked
}
if (isset($_SESSION['DispStat']))
{    if ($_SESSION['Cyr'] < $_SESSION['Lyr'] || ($_SESSION['Cyr'] == $_SESSION['Lyr'] && $_SESSION['Cmth'] <= $_SESSION['Lmth']))
          $_SESSION['DispStat'] = 4;
     else $_SESSION['DispStat'] = 5;              // the status to display ("if Stat > $_SESSION['DispStat']")
}
$S = "Location:" . $_SERVER['HTTP_REFERER'];      // allows use of cal_head() function when conditional date change is required
header($S);
 
This is called by two scripts, n_brchmenu.php and n_brchrev.php. When the user logs in he lands on brchmenu and one of the menu selections is brchrev. If creset.php (above) is called on the initial menu landing, no matter how many times, all of the session vars change as expected, except $_SESSION['DispStat'] which does not change. If the user goes to brchrev and does nothing while there but merely returns to brchmenu, then when creset.php is called all session vars change as expected including $_SESSION['DispStat']. Going to brchrev does not change any session vars; the only thing that changes any session vars is creset.php.

Here is the cal_head() function call, same in both scripts:

Code: Select all

 
          echo "<div class='cleft' style='width:175px; background:transparent; margin-right:-3px'>\n";
               cal_head();
          echo "</div>\n";
 
And here is the function:

Code: Select all

function cal_head()
{
     $Mths = array("", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
 
     print("<form method=post action='incl/creset.php'>\n");
     print("<input type=image src='../../cimage/c_plus.gif' ");
     print("style='vertical-align:bottom; margin-right:4px; border:0; margin-bottom:1px;' name='Plus'>");
 
     print("<select name=Mth style='font-size:14px; font-family: Arial; font-weight: bold; ");
     print("color: #0000B0; width:55px; vertical-align:bottom; margin-right:3px;'");
     print(" onchange='this.form.submit();'>\n");
     for ($i = 1; $i < 13; $i++)
     {    print("<option value=$i");
          if ($i == $_SESSION['Cmth']) print(" selected");
          print(">" . $Mths[$i] . "</option>\n");
     }
     print("</select>");
 
     $ye = 2 + date("Y");;      // display one greater than the current year as end point for selection
     $yb = $ye - 6;             // always show six years
     print("<select name=Yr style='font-size:14px; font-family: Arial; font-weight: bold; ");
     print("color: #0000B0; width:60px; vertical-align:bottom; margin-right:3px;'");
     print(" onchange='this.form.submit();'>\n");
     for ($i = $yb; $i < $ye; $i++)
     {    print("<option value=$i");
          if ($i == $_SESSION['Cyr']) print(" selected");
          print(">" . $i . "</option>\n");
     }
     print("</select>");
     print("<input type=image src='../../cimage/c_minus.gif' ");
     print("style='vertical-align:bottom; border:0; margin-bottom:1px;' name='Minus'>");
     print("</form>");
}
 
I'm getting crosseyed. What am I missing? Side-effects would be more of a suspect, except that creset.php contains nothing other than the $_SESSION vars, so...

Re: Delayed creation of $_SESSION variable?

Posted: Sat May 02, 2009 2:29 pm
by Benjamin

Code: Select all

 
if (isset($_SESSION['DispStat']))
{    if ($_SESSION['Cyr'] < $_SESSION['Lyr'] || ($_SESSION['Cyr'] == $_SESSION['Lyr'] && $_SESSION['Cmth'] <= $_SESSION['Lmth']))
          $_SESSION['DispStat'] = 4;
     else $_SESSION['DispStat'] = 5;              // the status to display ("if Stat > $_SESSION['DispStat']")
}
 
It would never be set, unless it already has been set, according to the logic in that file. We'll I guess you are saying it's set in menu.php. Is this page an include or a new http request?

I'd change that code to this, so you can see what is executing..

Code: Select all

 
if (isset($_SESSION['DispStat'])) {
    if ($_SESSION['Cyr'] < $_SESSION['Lyr'] || ($_SESSION['Cyr'] == $_SESSION['Lyr'] && $_SESSION['Cmth'] <= $_SESSION['Lmth'])) {
        $_SESSION['DispStat'] = 4;
        echo "TRUE";
    } else {
        $_SESSION['DispStat'] = 5;              // the status to display ("if Stat > $_SESSION['DispStat']")
        echo "FALSE";
    }
}
 

Re: Delayed creation of $_SESSION variable?

Posted: Sat May 02, 2009 2:48 pm
by Bill H
in my original post the n_brchmenu.php (which I did not identify in that post, referring to it only as "the menu script") is originally called with $_GET['Owner'] set, which will initialize the $_SESSION['DispStat'] variable. And it does do so, as evidenced by my $_SESSION dumps.

Can't echo the result in creset.php, as I am using a header() call to return to the calling script. But the change (or lack thereof) is being affirmed by my temporary $_SESSION dumps in the calling scripts.

creset.php is a new http request, see the form in the function cal_head().

Appreciate your looking at this, don't give up on me, cause I'm fubared.

Re: Delayed creation of $_SESSION variable?

Posted: Sat May 02, 2009 2:55 pm
by Benjamin
So lets step through this at a higher level. Write down how the logic works in the following format:

1. A web request is received.
2. If $_GET['Owner'] is set to a value, n_brchmenu.php is included.
3. n_brchmenu.php sets $_SESSION['DispStat'] to a value.
4. creset.php is included and....

Re: Delayed creation of $_SESSION variable?

Posted: Sat May 02, 2009 3:31 pm
by Bill H
Not quite. n_brchmenu.php is invoked which contains the following:

Code: Select all

if (isset($_GET['Owner']))
{    $_SESSION['ListFor'] = 0 + $_GET['Owner'];
     $_SESSION['DispStat'] = 4;              // (this will display reports)
}                                            // set here to permit entry from Admin menu
and then presents the menu page.
The menu page contains (among other things) a <form> which will call creset.php, and a link which will call n_brchrev.php.
n_brchrev.php also contains the <form> which will call creset.php.
creset is the only script which can change any $_SESSION variables
it does so as expected, except when called by the intitial iteration of n_brchmenu.php

If the $_GET var is not set, then $_SESSION['DispStat'] is not referenced in n_brchmenu.php at all.

Changing the code in n_brchmenu.php to this

Code: Select all

if (isset($_GET['Owner']))
{    $_SESSION['ListFor'] = 0 + $_GET['Owner'];
     $_SESSION['DispStat'] = 4;              // (this will display reports)
     header("Location:n_brchmenu.php");
}                                            // set here to permit entry from Admin menu
solves the problem, but why? :banghead:

Here's interesting additional data. If you reiterate the menu with any functionality at all, it causes the change in $_SESSION['DispStat'] to work properly. However, on the initial iteration of the menu, you can reset the date any number of times and the $_SESSION['DispStat'] will not change, despite the fact that the creset.php is sending back to the menu script with a header() call. So the header() call in the $_GET code does cause functionality, while the header() call in creset.php does not.

Re: $_SESSION variable madness [rev title]

Posted: Sun May 03, 2009 7:13 pm
by Bill H
I'm going to bump this up; I think 24 hours is acceptable. If not my apologies. The issue has sort of morphed from my original problem, so there is a temptation to start a new thread, but I'm inclined to think that would be rude. So let me restate the issue as it now stands.

I have this utility script which is called by several other scripts to alter the session variables which determine the current month and year being viewed. There is a "last permissable" month and year which apply only to some users, in which case a session variable, $_SESSION['DispStat'], also needs to be set to control the status of the records which will be displayed. Nothing very sophisticated, and here is the script in its entirety. creset.php

Code: Select all

// Routine for bumping a standard session period                                  June 5, 2004
// added the $_SESSION['DispStat'] routine for displaying records                 Apr 29, 2009
 
session_cache_limiter("private,must-revalidate");
session_start();
 
if (isset($_POST['Plus_x']))                      // wants to advance a month
{    $_SESSION['Cmth']++;
     if ($_SESSION['Cmth'] > 12)                  // bumped to next year
     {    $_SESSION['Cmth'] = 1;                  // January
          $_SESSION['Cyr']++;                     // of next year
     }
}
else if (isset($_POST['Minus_x']))                // wants to back up a month
{    $_SESSION['Cmth']--;
     if ($_SESSION['Cmth'] == 0)                  // bumped to last year
     {    $_SESSION['Cmth'] = 12;                 // December
          $_SESSION['Cyr']--;                     // of last year
     }
}
else                                              // only use the dropdowns
{    $_SESSION['Cmth'] = $_POST['Mth'];           // when the +/- buttons are
     $_SESSION['Cyr'] = $_POST['Yr'];             // neither one clicked
}
if (isset($_SESSION['DispStat']))
{    if ($_SESSION['Cyr'] < $_SESSION['Lyr'] || ($_SESSION['Cyr'] == $_SESSION['Lyr'] && $_SESSION['Cmth'] <= $_SESSION['Lmth']))
          $_SESSION['DispStat'] = 4;
     else $_SESSION['DispStat'] = 5;              // the status to display ("if Stat > $_SESSION['DispStat']")
}
$S = "Location:" . $_SERVER['HTTP_REFERER'];      // allows use of cal_head() function when conditional date change is required
header($S);
I realize that using $_SERVER['HTTP_REFERER'] is a little risky, but it has presented no problems so far. If it ever does the structure of my code makes it fairly easy to replace it with a session variable taken from $_SERVER['PHP_SELF'] which is more reliable. Anyway, this script works perfectly when called from all of the scripts which call it, except a small glitch when called from one script.

The following script is a menu for users. The user logs in and the login script verifies password and username against the database. It sets the session variables and then sends it to this menu with the $_GET['Owner'] set to the user's number. Just that $_GET is not enough to successfully run the script, the session variables must also be set for security, but the $_GET['Owner'] tells the script that this is the first iteration of the script. The administrator may also come to this menu, in which case the $_GET['Owner'] is also set.

Here's the menu with the relevant code and markup. I left out the styling stuff for clarity. n_brchmenu.php

Code: Select all

session_cache_limiter("private,must-revalidate");
session_start();
 
if (isset($_GET['Owner']))
{    $_SESSION['ListFor'] = 0 + $_GET['Owner'];
     $_SESSION['DispStat'] = 4;              // (this will display reports)
}                                            // set here to permit entry from Admin menu
 
?>
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'>
<html lang='en'>
<head><title>Company of San Diego</title>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
</head>
 
<form method=post action='incl/creset.php'>
<input type=image src='../../cimage/c_plus.gif' name='Plus'>
<select name='Mth' onchange='this.form.submit();'>
<option value=1>Jan</option>
<!--and the rest of the options, current month selected -->
</select>
<select name='Yr' onchange='this.form.submit();'>
<option value=2005>2005</option>
<!--and the rest of the options, current year selected -->
</select>
<input type=image src='../../cimage/c_minus.gif' name='Minus'>
</form>
That $_SESSION['DispStat'] does not appear anywhere in this script, other than in the $_GET['Owner'] condition.

If creset.php is invoked on the initial iteration of this script, including if it is invoked multiple times, $_SESSION['DispStat'] does not get changed. The current month and year do change, but $_SESSION['DispStat'] does not. If the user makes a menu selection, invoking a different script, and then returns to this one, then invoking creset.php changes $_SESSION['DispStat'] as expected.

Why would multiple invocations of creset.php not cause the $_SESSION['DispStat'] to begin changing? I realize that creset.php does not involve an http request, but returning to n_brchmenu.php from that script should do so? Or does the server know not to repeat a request from the same script somehow? Grasping at straws, because what would an http request have to do with it?

If I change the $_GET['Owner'] conditional to this

Code: Select all

if (isset($_GET['Owner']))
{    $_SESSION['ListFor'] = 0 + $_GET['Owner'];
     $_SESSION['DispStat'] = 4;              // (this will display reports)
     header("Location:n_brchmenu.php");
     exit();
}                                            // set here to permit entry from Admin menu
Then invoking creset.php changes the $_SESSION['DispStat'] properly, seemingly because the menu script has been reiterated. But with the exit() function there, only the very first part has been, so the only real difference is that the script has been iterated without the $_GET variable set. But how can that make any difference?

The header() in the above condition clears the problem but, given that the date can be changed repeatedly in the initial menu iteration without $_SESSION['DispStat'] changing, the header() call in creset.php apparently does not clear the problem?

I did a var-dump (print_r($_SESSION) thing) in creset.php, and of course it then gave me a header error, but it did display a value for $_SESSION['DispStat']. It just didn't change it. The month, year and Lmth/Lyr vars were correct as well.

As my grandfather would have said, Was gibst?