Page 1 of 1

$_SESSION sanity check

Posted: Wed Nov 11, 2009 11:40 pm
by felipe
Ok ladies and gents, I've been battling with this login/session code for a few days now and I'm beginning to think there's a short circuit... somewhere in my head. No matter what I've tried I can't maintain persistent session across pages.

Can someone please give me a second/third/fourth set of eyes and let me know where it's broken? I have a simple 2-page example working so I know my browser and environment are ok, but that means my code is broken!

Here's the login page:

Code: Select all

 
<?php
session_start();
echo '<?xml version="1.0" encoding="utf-8"?>';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title></title>
 
<body>
<div id="container">
 
<div id="header">
<?php
 include('header.php');
?>
</div>
 
<div id="content">
<div class='topleft'></div>
<div class='topright'></div>
<div class='bottomleft'></div>
<div class='bottomright'></div>
<br/>
<h3>DHP Administrative Login</h3>
<p>(Must have cookies enabled)</p>
<div id="loginform">
<?php
  if (isset($message))
  {
    echo "$message";
  }
?>
<form action="processlogin.php" method="POST">
<table border="0">
<tr>
<td><label for="fusername">Username</label></td>
<td><input type="text" name="fusername" size="20" maxsize="20"></td>
</tr>
<tr>
<td><label for="fpassword">Password</label></td>
<td><input type="text" name="fpassword" size="20" maxsize="20"></td>
</tr>
<input type="hidden" name="do" value="login">
</table>
<input type="submit" name="log" value="Submit">
</form>
</div>
</div>
 
<div id="footer">
<?php
include('footer.php');
?>
</div>
 
</div>
</body>
</html>
 
login script:

Code: Select all

 
<?php
/* Program: processlogin.php
 * Desc:    Processes input from login.php and will either
 *          1) Validate the login and set appropriate session
 *          variables, or
 *          2) Re-display the page.
 */
 
 switch (@$_POST['do'])
 {
   case 'login':
     $cxn = mysql_connect($host, $user, $password);
 
     if (!cxn)
       {
         die('Could not connect: ' . mysql_error());
       }
       
     mysql_select_db($database, $cxn);
     
     $sql = "SELECT loginName FROM Member WHERE loginName='philtest'";
     
     $result = mysql_query($sql)
       or die("Could not execute query 1.");
       
     $num = mysql_num_rows($result);
     
     if ($num > 0) //login found
     {
       $sql = "SELECT loginName FROM Member WHERE
               loginName='$_POST[fusername]'
               AND password=md5('$_POST[fpassword]')";
       $result2 = mysql_query($sql)
         or die("Could not execute query 2.");
       $num2 = mysql_num_rows($result2);
     }
     if ($num2 > 0) //password matched
     {
       $_SESSION['auth'] = 'admin';
       $logname=$_POST['fusername'];
       $_SESSION['logname'] = $logname;
       $today = date("Y-m-d h:i:s");
       $sql = "INSERT INTO Login (loginName,loginTime)
               VALUES ('$logname','$today')";
       $result = mysql_query($sql)
         or die("Can't execute insert query.");
       session_write_close();
       header("Location: admin.php");
     }
     else
     {
       $message = "Incorrect login credentials.  Please try again!";
       include("login.php");
     }
     break;
   
   default:
   {
     include("login.php");
   }
  }
?>
 
Here's a sample page (that isn't recognizing session info):

Code: Select all

 
<?php
session_start();
/* if ( $_SESSION('auth') != 'admin' )
{
   header("Location: login.php");
} */
echo '<?xml version="1.0" encoding="utf-8"?>';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title></title>
 
</head>
<body>
<div id="container">
 
<div id="header">
<?php
 include('header.php');
?>
</div>
 
<div id="content">
<div class='topleft'></div>
<div class='topright'></div>
<div class='bottomleft'></div>
<div class='bottomright'></div>
<br/>
<h3>DHP Administrative Page</h3>
<p>Under construction.</p>
<?php
  echo $_SESSION['auth'];
?>
<p></p>
</div>
 
<div id="footer">
<?php
include('footer.php');
?>
</div>
 
</div>
</body>
</html>
 
And last, here's the header with some (failing) checks against the $_SESSION['auth'] variable:

Code: Select all

 
<?php
/*   Program name: header.php
 *   Description:  Provides the header content (title, navigation) to each of the DHP pages.
 */
 
echo
"
<div class='topleft'></div>
<div class='topright'></div>
<div class='bottomleft'></div>
<div class='bottomright'></div>
<div id='DHPTitle'>
<img src='images/dhp_logo.jpg' alt='DHP Logo' />
</div>
<div id='DHPSubtitle'>
<img src='images/dhp_sublogo.jpg' alt='DHP Sublogo' />
</div>
<div id='DHPMascot'>
";
if ( empty( $_SESSION['auth'] ) )
{  
  echo "<a href='login.php'>";
}
else
{
  echo "<a href='admin.php'>";
}
echo
"
<img src='images/dhp_mascot.jpg' alt='DHP Mascot' />
</a>
</div>
<div id='navigation'>
<ul>
<li>
<a href='index.php' title='Dutch Home Painting - The Best Painters in Town - Cincinnati, OH'>Home</a></li>
<li><a href='samples.php' title='Dutch Home Painting - Sample Pictures'>Sample Work</a></li>
<li><a href='about.php' title='Dutch Home Painting - About Us'>About Us</a></li>
<li><a href='estimate.php' title='Dutch Home Painting - Free Estimate'>Free Estimate</a></li>
";
if ( empty( $_SESSION['auth'] ) )
{  
  echo "<li>513-555-1212</li>";
}
else
{
  echo "<a href='logout.php'><li>Logout</a></li>";
}
echo "auth variable is ".$_SESSION['auth'];
"
</ul>
</div>
";
?>
 


Sorry for the long post but I wanted to make sure you guys had all the pieces. Any help would be MUCH appreciated!!!

As an aside, when I try to access admin.php without logging in it's even letting me do that so somewhere my $_SESSION tests are just failing all over the place...

Re: $_SESSION sanity check

Posted: Thu Nov 12, 2009 2:00 am
by cpetercarter
Your admin page does not recognise the $_SESSION variables because you closed the session with session_write_close() at the end of the login script. This - as the name suggests - closes the session; and then session_start() at the top of the admin page starts a new session.

The easiest way to implement what you want is have a single webpage (eg http://www.yoursite.com/index.php) which shows the login stuff if the user is not logged in and the admin stuff if she/he is logged in. To maintain clarity, use includes or functions for the alternative content and logic. Like this:

Code: Select all

 
<?php
session_start();
$access = accesscheck();
if(!$access) {
       include 'page_login.php'; //show the login page
       }
else
      {
       include 'page_admin.php'; //show the admin page
       }
 
function accesscheck()  {
if (isset($_SESSION['auth']) && $_SESSION['auth'] == true)  {
     return true;
     }
elseif (isset($_POST['name']) && isset($_POST['password'])){
     //check the submitted name and password against the database
      if ($OK) {
                $_SESSION['auth'] = true;
                return true;
                 } else {
                return false;
              }
      }
else // ie there is no $_SESSION['auth'] and no posted name and password
     {
     return false;
     }
}
?>
 
Before you go live with your script, PLEASE remember to escape (mysql_real_escape_string()) all user-generated values like the posted username and password before putting them anywhere near your database. In its present form your script is wide open to SQL injection attacks.

Re: $_SESSION sanity check

Posted: Thu Nov 12, 2009 6:06 pm
by felipe
I removed session_write_close() but it's still broken :(

Re: $_SESSION sanity check

Posted: Thu Nov 12, 2009 9:51 pm
by felipe
Why might this sample code (below) work when my own code (above) doesn't? Aren't I doing the same thing???

Code: Select all

 
<?php
// page1.php
 
session_start();
 
echo 'Welcome to page #1';
 
$_SESSION['favcolor'] = 'green';
$_SESSION['animal']   = 'cat';
$_SESSION['time']     = time();
 
// Works if session cookie was accepted
echo '<br /><a href="php2.php">page 2</a>';
 
?>
 

Code: Select all

 
<?php
// page2.php
 
session_start();
 
echo 'Welcome to page #2<br />';
 
echo $_SESSION['favcolor']; // green
echo $_SESSION['animal'];   // cat
echo date('Y m d H:i:s', $_SESSION['time']);
 
// You may want to use SID here, like we did in page1.php
echo '<br /><a href="php1.php">page 1</a>';
?>
 

Re: $_SESSION sanity check

Posted: Thu Nov 12, 2009 10:26 pm
by superdezign
cpetercarter wrote:Your admin page does not recognise the $_SESSION variables because you closed the session with session_write_close() at the end of the login script. This - as the name suggests - closes the session; and then session_start() at the top of the admin page starts a new session.
session_write_close() does NOT "end" the session. It saves the session and removes access to the session for the rest of the script (until session_start() is called again).
session_start() only starts a new session if the current user does not already have an active session. This is determined by checking the cookies and then the SID in the URL, if no cookie is found. Otherwise, it loads the current session.

@felipe: The problem is that you are missing session_start() in your files. Your processlogin.php file is creating a random array named $_SESSION, adding data into it, and invoking the session_write_close() function, which operates on the current session. Since you have not invoked session_start(), there is no current session, so this essentially does nothing.

Every file that needs access to the session should have session_start() invoked before the session is needed and before any output has been made to the screen.

Re: $_SESSION sanity check

Posted: Thu Nov 12, 2009 10:33 pm
by felipe
Uhoh... I was ASSuming that by including a file it essentially just inserted code from an external file wherever the include statement was. I figured it was mainly for cleaning up code and stuff - didn't realize it would need session_start(), too!

Let's see how it goes...

PS What about session_write_close()? Is that necessary anywhere?

Re: $_SESSION sanity check

Posted: Thu Nov 12, 2009 11:47 pm
by felipe
Got it, thanks!!! Now just to nail down proper logout and make sure protected pages are actually protected :)

Re: $_SESSION sanity check

Posted: Fri Nov 13, 2009 1:03 am
by cpetercarter
session_write_close() does NOT "end" the session. It saves the session and removes access to the session for the rest of the script (until session_start() is called again).
The php manual however says:
End the current session and store session data.

Re: $_SESSION sanity check

Posted: Fri Nov 13, 2009 9:39 am
by felipe
So it's like an additional safety mechanism so you don't/can't access $_SESSION variables outside of the code blocks where you intended to access them? All that means is you'd need another session_start() to access them, right?

Re: $_SESSION sanity check

Posted: Fri Nov 13, 2009 8:44 pm
by superdezign
cpetercarter wrote:The php manual however says:
End the current session and store session data.
I know what it says. :P
That's why I put "end" in quotation marks, because I noticed that the manual is unclear. "End" and "destroy" are different. Ending the session ends the access to the session for the current script. Destroying the session destroys the data in the session.

Re: $_SESSION sanity check

Posted: Fri Nov 13, 2009 8:46 pm
by superdezign
felipe wrote:So it's like an additional safety mechanism so you don't/can't access $_SESSION variables outside of the code blocks where you intended to access them? All that means is you'd need another session_start() to access them, right?
Right. Though, I wouldn't say that it's a safety mechanism. I'd say that session_start() is required as not to add extra overhead to pages that don't need it. Session access has to check cookies and URL variables to determine the session to look at, and then access the session data via the file system or database (depending on your set up).