QUESTIONS
- Is the intermittent loss of session data likely to be due to a race condition?If no, what is likely to be the problem?
- How can I prevent race conditions when writing/ reading joomla session variables from an external php script?
DETAILS
I'm using
- Joomla 2.5
- PHP 5.4.3
- apache 2.2.22
- mysql 5.5.24
- wampserver 2 on localhost.
- My script is external to Joomla.
- (cometchat version 3.0.1)
The script is using asynchronous ajax requests to get and set joomla variables multiple times. The data I'm storing in session is an array. Intermittently some of the array data goes missing. It seems to happen much more consistently once the user logs in and uses the script.
To be honest, I'm not really sure what the problem is, but I'm starting to think that my code is suffering from a race condition. I think Joomla might be trying to read the session information before it has finished being written or it just isn't getting set. The information that goes missing seems to be chosen at random and the loss of data occurs intermittently.
SCRIPT1
Script 1 is using an asynchronous ajax request to get/set Joomla session variables. This will be called multiple times. Due to design, script 1 cannot be called again until the ajax response is successful.
$.ajax(
{ cache:false,
url: 'script2.php',
data: { 'change': change},
dataType: 'json',
success: function(data)
{
//do something
}
});
This is a rough idea of the code I'm using in script 2 to access Joomla and get/set session data.
SCRIPT2
<?php
//some code omitted for brevity
$app = &JFactory::getApplication('site');/
$app->initialise();
$nottimedout=false;
$session = JFactory::getSession();
$jquizstart = date( 'Y-m-d H:i:s', time() ); //<<-- time of access
$nottimedout = $session->has('jtimedout');
if ($nottimedout==true)
{
$jqid = $session->get('jqid'); //<<-- get array from session
if (isset($_GET['change']))
{
$qnumber=$_GET['change'];
$firephp->log($qnumber, 'qnumber');
$jqid[$qnumber][3]=$jquizstart; //<<-- add time of access to array
$firephp->log($jqid[$qnumber][3], '$jqid[$qnumber][3]');
$session->set('jqid', $jqid); //<<-- store array in Joomla with updated data
}
else
{
$firephp->log('CHANGE NOT SET');
}
echo json_encode(
array("nottimedout" => $nottimedout)
);
}
else
{
//Do something
}
?>
TEST FOR RACE CONDITIONS
I thought the data might be getting overwritten, so I did a quick test using the code below. Each time I update the session array I create a new session variable with just the updated data.
$qnum[$qnumber]=$jquizstart;
$session->set('var'.$qnumber, $qnum);
In another script when the website completed updating I checked each of the individual sessions to see if they had been set.
//Test for race condition in Joomla session
for ($counter=0; $counter<=$totalnumber-1; $counter++)
{
$racecondition=$session->get('var'.$counter);
$firephp->log($racecondition, 'var'.$counter.'=');
}
RESULTS OF TEST
The array information missing from jqid was also missing from the corresponding individual session (the session with just the updated data), so it seems that it isn't a problem of the data being overwritten. I'm not sure if this disproves a race condition though.
Any suggestions as to what you think might be going on and how to fix this would be most welcome.
EDIT
Even generalized answers on how to prevent race conditions in Joomla are welcome. Thanks
EDIT2
I'm starting to wonder if it isn't a problem with php5.4 and Joomla. I've heard that they don't play well together and I can't remember having this problem before I updated from php5.3. I could be wrong though.
EDIT3
I'm at wits end. I installed the website on a different server with php 5.3.10. I tried it ten or more times as an unlogged-in user. There was no loss of data. I then logged into Joomla and data was lost nearly every time I accessed the page. If only I didn't have to use Joomla sessions! GRRRrrrrr
EDIT4
Getting desperate now and just trying anything. JRequest didn't work, although I should be using it anyway.
Since the problem occurs more frequently when logged in, I figured it must be because there is a lot more content stored in the session than when the user is a guest. Jqid is a large array, so rather than updating it all the time, I tried making several smaller arrays and updating each when appropriate. It had absolutely no effect. Again, I probably should be doing this anyway.
EDIT5B
While trying to find a makeshift solution, I tried to test whether the session had successfully updated or not (this was done in the same script that updated the session).
Here is the code I used to check jstart.
//jstart updated
$session->close('jstart');
$try_again_session = JFactory::getSession();
$newjstart=$try_again_session->get('jstart');
$firephp->log($newjstart[$qnumber], 'confirm_jstart_set=');
The interesting thing I found was that, jstart contained the updated information during the check, but at completion it was missing.
I'm not really sure what that means, but I guess if we treated JFactory::getSession()
as a variable then the variable was updated only for this script (kind of like a local variable?), the database value for JFactory::getSession()
for whatever reason was not written to the database. Thus later, when this script fired again it retrieved the old value of JFactory::getSession()
that was saved in the database.
Still have no idea what is causing the session not to be written to the database.