In an internship I’m following along in a really nice tutorial on making advanced PHP secure sessions for a shopping cart that will give users pricing on the individual level (well that’s the goal anyway.)
This is the tutorial:
http://tutorial-resource.com/2011/10/a-secure-session-management-class-in-php/
First I created a primitive login that checks for already existing customers based on a Quickbooks customer ID for the purposes of testing this session. The real deal with use a registration, login and password. Then I made a login checker that find the user in a mysql database, and when found, retrieves the user data columns that need to stay with the user page by page. (I PROMISE I will further prevent SQL injection after I get this working.) I added a few additional fields to be stored in SessionData.
<?php
include "class.session.php";
if(empty($_POST['customer_id']))
{
$this->HandleError("Customer ID is empty!");
return false;
}
$customer_id = trim($_POST['customer_id']);
$dbuser = "CENSORED";
$dbpass = "CENSORED";
$host = "localhost";
$dbname = "CENSORED";
// database connection
mysql_connect("localhost", $dbuser, $dbpass) or die(mysql_error());
mysql_select_db($dbname) or die("Unable to select database");
//This query grabs all the puchases going back up to three months
//This debug line displays the query
$query = "SELECT * FROM customers";
echo $query."<br>";
$found = 0;
$result = mysql_query($query);
while($row=mysql_fetch_array($result))
{
//Grab the database pieces the customer will need throughout the page.
echo "Checking customer number ".$row['customer_id']."<br>";
if ($row['customer_id'] == $customer_id)
{
$found = 1;
break;
}
}
//-create while loop and loop through result set
if ($found == 0)
{
echo 'Wrong customer number';
}
while($row=mysql_fetch_array($result))
{
//Grab the database pieces the customer will need throughout the page.
$customer_id = $row['customer_id'];
$first_name = $row['first_name'];
$last_name = $row['last_name'];
$first_name = $row['price_level'];
}
//Give the user a session.
$sessions = new sessionsClass;
$sessions->_sessionStart();
$sessionInfo = $sessions->sessionCheck();
if( $sessionInfo = false )
{
# This session is invalid. Tell the user.
}
else
{
# Update the name.
$sessionInfo->sessionData['customer_id'] = $customer_id;
$sessionInfo->sessionData['company_name'] = $company_name;
$sessionInfo->sessionData['first_name'] = $first_name;
$sessionInfo->sessionData['last_name'] = $last_name;
$sessionInfo->sessionData['price_level'] = $price_level;
$sessionInfo->setSessionData();
# Session is valid, can use the data.
echo "Your name is ".$sessionInfo->sessionData['first_name']." ".$sessionInfo->sessionData['last_name']."<br>";
}
?>
After a successful login, I see an error in the error_log that says
“Call to undefined method stdClass::setSessionData()” regarding this line when clearly the function exists, straight out of the tutorial:
$sessionInfo->setSessionData();
Why would the login not recognize setSessionData as an undefined Method and not a function?
A clue that I don’t fully understand is that it’s referring to setSessionData as an ” undefined method stdClass” rather than an “undefined function.” The function is very similar to the tutorial, except that it connects to my db:
public function setSessionData()
{
$dbuser = "CENSORED";
$dbpass = "CENSORED";
$host = "localhost";
$dbname = "CENSORED";
// database connection
mysql_connect("localhost", $dbuser, $dbpass) or die(mysql_error());
mysql_select_db($dbname) or die("Unable to select database");
//Encrypt the data.
$serialiseData = serialize( $this->sessionData );
//Update the session data.
mysql_query( "UPDATE sessions SET sessionData = '{$serialiseData}' WHERE sessionHash = '{$this->sessionHash}'" );
}
My last question is, what does each individual page require to safely differentiate between an ordinary user and a logged in user no matter what page? Is it something like this?
if (sessionCheck == false)
{show ordinary stuff}
else if (sessionCheck == return true)
{show personalized stuff}
EDIT This tutorial seems to have some problems after all. For example, near the end of the tutorial.
# Session is valid, can use the data.
echo "Your name is " . $sessionInfo->sessionData['fullname'];
# Update the name.
$sessionInfo->sessionData['fullname'] = "My New name";
$sessionInfo->setSessionData();
}
This is wrong because sessionInfo is a boolean meant to return true for false. Instead I replaced this with
$sessions->sessionData['customer_id'] = $customer_id;
$sessions->sessionData['company_name'] = $company_name;
$sessions->sessionData['first_name'] = $first_name;
$sessions->sessionData['last_name'] = $last_name;
$sessions->sessionData['price_level'] = $price_level;
$sessions->setSessionData();
But that still didn’t do the trick. Also, the tutorial has people create an entire MySQL database but not a single INSERT happens anywhere in the class or in the tutorial. The functionality for UPDATE queries to already existing sessions is there, but nothing for creating new ones. What can I add to get the database successfully creating sessions?
A serialized object will be converted to
stdClassif the class cannot be found during unserialization. My guess is that when you read the session information from the database and attempt to put it back to asessionClassobject, you have not included the file that defines that class. Make sure the class is defined before you unserialize.Since
stdClasshas no method calledsetSessionData, you get the “Call to undefined method” error. A method is the term generally used to refer to a function within a class, while a function is just a standalone function definition.To differentiate on each page a logged in user from an ordinary user, you generally need to start the session and check for an application specific value that indicates to you that the user is authenticated. This could be as simple as setting a
loggedInflag in the session, or storing a more complex type and checking its value. But basically you need to do it on each page that is required to know a regular user from a logged in user.Hope that helps.
As an aside, where you are calling
$this->HandleError("Customer ID is empty!");at the beginning of your code, if that block executes, you will get an error saying$thisis not defined. Since that code is not being called within a class, there is no instance of$thisso you will have to figure out the correct way to handle that error.