tags:

views:

467

answers:

4

Alright, I'm confused as hell. I have an object that I store in a session. I can add items to this object. Pretty simple so far. I initialize the object like this:

$template = new Template($mysqli);
$_SESSION['template'] = serialize($template);

Now this should create a brand spanking new object and assign it to the session. I then have some code that adds items through an AJAX request. That code is as follows:

$template = unserialize($_SESSION['template']);
$prodid = $_GET['product_id'];
$template->addItem($prodid);
echo var_dump($template->getItems());
$_SESSION['template'] = serialize($template);

Again, should be simple. Now here's the issue, that first bit of code is not resetting $_SESSION['template'] while it should, so I get all the items I've added so far, reloading the page doesn't fix it.

I found the file that's causing the mischief but I don't know what I can do about this. It's an include and it's required for different portions of the site to function. I'm adding functionality to the site, I don't think the owners would be please if I removed functionality. Here's the file:

<?php

include_once( 'DBE.class.php' ) ;

################################################
# Function: Sessions_open
# Parameters: $path (string), $name (string)
# Returns: bool
# Description: This is an over-ride function call
#  that we need to create so that the php internal
#  session manager doesn't store our session in the
#  file system, since we are storing it in the
#  db. Storing a session in a file system on the
#  server inhibits scalability for two reasons:
#  1: A large number of users may be hitting the site
#   and clog the space on the hard-drive of the server
#   due to the sheer amount of session files stored
#  2: The website may be behind a load-balancer and
#   therefore the server handling the page request
#   may not have the session stored on its file system
################################################
function Sessions_open ( $path, $name ) {
 return TRUE ;
}


################################################
# Function: Sessions_close
# Parameters: N/A
# Returns: bool
# Description: This is an over-ride function call
#  that we need to create so that the php internal
#  session manager doesn't store our session in the
#  file system, since we are storing it in the
#  db. Storing a session in a file system on the
#  server inhibits scalability for two reasons:
#  1: A large number of users may be hitting the site
#   and clog the space on the hard-drive of the server
#   due to the sheer amount of session files stored
#  2: The website may be behind a load-balancer and
#   therefore the server handling the page request
#   may not have the session stored on its file system
################################################
function Sessions_close () {
 return TRUE ;
}


################################################
# Function: Sessions_read
# Parameters: $SessionID (string)
# Returns: (string) or (false) on error
# Description: This function is used at startup to read
#   the contents of the session. 
#   If no sess data, the empty string ("") is returned.
#   Otherwise, the serialized sess data is returned.
#   On error, false is returned.
################################################
function Sessions_read ( $SessionID ) {

 include_once( 'DBE.class.php' ) ;
 $dbe = new DBE() ;

 //default return value to false
 $returnVal = FALSE ;

 $query = "SELECT DataValue
       FROM Sessions 
      WHERE SessionID = '$SessionID' " ;

 $result = $dbe->Select( $query ) ;

 if( count( $result ) == 1 ) {
  $returnVal = $result[0]['DataValue'] ;

  //update the session so that we don't time-out after creating
  $query = "UPDATE Sessions
       SET LastUpdated = NOW()
       WHERE SessionID = '$SessionID'" ;
  $dbe->Update( $query ) ;

 } else {
  //Insert here to simplify the write function
  $query = "INSERT INTO Sessions (SessionID, DataValue) VALUES ( '$SessionID', '' )" ;

  $dbe->Insert( $query ) ;   //pass the insert stmt

  //set returnVal to '' being that we didn't find the SessionID
  $returnVal = '' ;
 }

 return( $returnVal ) ;
}

################################################
# Function: Sessions_write
# Parameters: $SessionID (string), $Data
# Returns: bool
# Description: This function is used at startup to read
#   the contents of the session. 
#   If no sess data, the empty string ("") is returned.
#   Otherwise, the serialized sess data is returned.
#   On error, false is returned.
################################################
function Sessions_write( $SessionID, $Data ) {

 include_once( 'DBE.class.php' ) ;
 $dbe = new DBE() ;

 //default to true
 $returnVal = TRUE ;

 //update the session
 $query = "UPDATE Sessions 
       SET DataValue = '$Data'
      WHERE SessionID = '$SessionID'" ;

 $result = $dbe->Update( $query ) ; //pass the update stmt to the dbEngine..

 //test for success
 if( $result == -1 )
  $returnVal = FALSE ;

 //return the return value
 return( $returnVal ) ;
}


################################################
# Function: Sessions_delete
# Parameters: $SessionID (string)
# Returns: bool
# Description: This function is used to delete the session
################################################
function Sessions_destroy( $SessionID ) {

 include_once( 'DBE.class.php' ) ;
 $dbe = new DBE() ;

 $query = "DELETE FROM Sessions WHERE SessionID = '$SessionID' " ;

 $dbe->Delete( $query ) ;

 return( TRUE ) ;
}

################################################
# Function: Sessions_delete
# Parameters: $SessionID (string)
# Returns: bool
# Description: This function is used to delete the session
################################################
function Sessions_gc( $aMaxLifetime ) {

 include_once( 'DBE.class.php' ) ;
 $dbe = new DBE() ;

 $query = "DELETE FROM Sessions WHERE (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP( LastUpdated )) > $aMaxLifetime " ;

 $dbe->Delete( $query ) ;

 return( TRUE ) ;
}

 session_set_save_handler( "Sessions_open", "Sessions_close",
                                 "Sessions_read", "Sessions_write",
                                 "Sessions_destroy", "Sessions_gc" ) ;

?>

I think that this is changing the basic functionality of sessions, but I'm not quite sure. And that's causing my trouble with resetting the template in the session. Anyone have any ideas or know what I can do to fix this problem. I'm totally stumped so any help is greatly appreciated.

A: 

Well, you should be able to check the database to see how your data is getting stored (if at all). That's certainly where I would start.

Eric Petroelje
+1  A: 

Looks like they're overriding the standard session handler to store session data in the DB.

Have a look in the Sessions table and check that your serialised object is being stored correctly.

Visage
+2  A: 

I'm not sure if that's the issue, but this is what jumps out when i read your code:

Your serialized object relies on a mysql connection

$template = new Template($mysqli);

while your object (maybe) can be serialized and un-serialized without problems, the mysql connection can't, so your un-serialized $template tries to operate on an invalid connection/file handle.

You can try re-attaching your un-serialized object to a valid db connection.

Without knowing what's inside your Template class (and what resources it uses and how) it's hard to guess what's wrong but I hope this is a good enough clue on where to start looking.

To give you a better idea of what I'm talking about, consider this:

template.php

<?php

class Template {
 function __construct($c) {
   $this->conn = $c;
   $this->foo = "bar";
 }
 function get_data() {
  $result = mysql_query("select 1234 as test", $this->conn);
  $data = mysql_fetch_array($result);
  return $data;
 }

 function attach_db($c) {
   $this->conn = $c;
 }
}

?>

first.php

<?php
session_start();
require('template.php');

$conn = mysql_connect('localhost', 'root', '');
$template = new Template($conn);
?>
<pre>

Your $template var, freshly created:
<?php var_dump($template); ?>

Accessing the resources:
<?php var_dump($template->get_data()); ?>

<?php
$_SESSION['template'] = serialize($template);
?>

</pre>

other.php

<?php
session_start();
require('template.php');

$template = unserialize($_SESSION['template']);
?>
<pre>

Unserialized $template:
<?php var_dump($template); ?>
(notice that $template->foo === "bar" so your session un/serialization is working correctly)

Accessing the (now invalid) mysql resources:
<?php var_dump($template->get_data()); ?>

</pre>

Calling first.php should give you this:

Your $template var, freshly created:
object(Template)#1 (2) {
["conn"]=>
resource(3) of type (mysql link)
["foo"]=>
string(3) "bar"
}

Accessing the resources:
array(2) {
[0]=>
string(4) "1234"
["test"]=>
string(4) "1234"
}

Calling others.php should result in:

Unserialized $template:
object(Template)#1 (2) {
["conn"]=>
int(0)
["foo"]=>
string(3) "bar"
}
(notice that $template->foo === "bar" so your session un/serialization is working correctly)

Accessing the (now invalid) mysql resources:

Warning: mysql_query(): supplied argument is not a valid MySQL-Link resource in template.php on line 9

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in template.php on line 10

bool(false)

To solve that you can re-create the resources that cannot be un/serialized.
Like this:

solution.php

<?php
session_start();
require('template.php');

$template = unserialize($_SESSION['template']);
?>
<pre>

Unserialized $template:
<?php var_dump($template); ?>

Attaching a valid db connection:
<?php
$conn = mysql_connect('localhost', 'root', '');
$template->attach_db($conn);
var_dump($template);
?>

Accessing the resources:
<?php var_dump($template->get_data()); ?>

</pre>

Now, calling solution.php after having called first.php should give you this:

Unserialized $template:
object(Template)#1 (2) {
["conn"]=>
int(0)
["foo"]=>
string(3) "bar"
}

Attaching a valid db connection:
object(Template)#1 (2) {
["conn"]=>
resource(3) of type (mysql link)
["foo"]=>
string(3) "bar"
}

Accessing the resources:
array(2) {
[0]=>
string(4) "1234"
["test"]=>
string(4) "1234"
}

As I said, without knowing what your template class does, it's not possible to say for sure what's happening.. this is just one possibility ;)

Good luck!

Carlos Lima
A: 

It's possible your AJAX call does not contain the session cookie data, and is writing to a different session.

Can you use Fiddler and determine the exact request being sent?

John Rasch