How to prevent race conditions when writing/ reading joomla session variables from an external php script?
Asked Answered
P

2

9

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.

Potation answered 24/10, 2012 at 15:31 Comment(2)
With Joomla don't use isset use getvar $change = JRequest::getVar("change",'value if change doesn't exist'); Anyway that was my first thought.Allanadale
Good point. I will use this from now on.Niersteiner
P
2

Finally it looks like I've found a solution!

I happened to check the error logs in apache_error.log (wamp/logs/apache_error.log) There were a tonne of session related errors such as

PHP Warning:  session_start(): Cannot send session cache limiter - headers already sent (output started at Z:\\libraries\\joomla\\session\\session.php:96) in Z:\\libraries\\joomla\\session\\session.php on line 532, referer: http://localhost/cq
PHP Warning:  Cannot modify header information - headers already sent by (output started at Z:\\libraries\\joomla\\session\\session.php:96) in Z:\\cometchat\\cometchatcss.php on line 68, referer: http://localhost/cq
PHP Warning:  session_destroy(): Session object destruction failed in Z:\\libraries\\joomla\\session\\session.php on line 96, referer: http://localhost/cq

After turning off cometchat and rebooting the server I found that the intermittent session data loss seemed to stop. After the change there were no more errors appearing under apache_error.log

Since the problem is intermittent I’m not 100% sure that it's solved, but I’m confident enough that I’ve written this up as the solution. I was using

cometchat version 3.0.1

I'm gonna keep testing it. If the solution holds up I will try an updated version of cometchat and post the results.

UPDATE: It does seem to be related to cometchat. I've installed the latest version 4.6.0, but the session loss is still occurring. I can work around this by excluding cometchat on the pages containing my script.

USEFUL INFO: Just in case someone else finds themselves struggling with Joomla session-I found this website quite useful http://tutsforu.com/joomla-module-tutorial/8-joomla-tutorial/75-using-session-in-joomla.html

Specifically

$session->getId();
$session->get('session.counter');
$session->isNew();
$session->getName();
$session->getState();
$session->getExpire();
Potation answered 24/10, 2012 at 15:31 Comment(0)
N
3

While I haven't found a solution to the problem, I have found a work around. It's not a good one, but it works. Whenever the session variable is updated store the information in a cookie as a backup. Later in the script, check whether there is missing information and update from the cookie as necessary.

I'd rather not do it this way, but it doesn't look like I have a choice.

Niersteiner answered 4/11, 2012 at 6:59 Comment(0)
P
2

Finally it looks like I've found a solution!

I happened to check the error logs in apache_error.log (wamp/logs/apache_error.log) There were a tonne of session related errors such as

PHP Warning:  session_start(): Cannot send session cache limiter - headers already sent (output started at Z:\\libraries\\joomla\\session\\session.php:96) in Z:\\libraries\\joomla\\session\\session.php on line 532, referer: http://localhost/cq
PHP Warning:  Cannot modify header information - headers already sent by (output started at Z:\\libraries\\joomla\\session\\session.php:96) in Z:\\cometchat\\cometchatcss.php on line 68, referer: http://localhost/cq
PHP Warning:  session_destroy(): Session object destruction failed in Z:\\libraries\\joomla\\session\\session.php on line 96, referer: http://localhost/cq

After turning off cometchat and rebooting the server I found that the intermittent session data loss seemed to stop. After the change there were no more errors appearing under apache_error.log

Since the problem is intermittent I’m not 100% sure that it's solved, but I’m confident enough that I’ve written this up as the solution. I was using

cometchat version 3.0.1

I'm gonna keep testing it. If the solution holds up I will try an updated version of cometchat and post the results.

UPDATE: It does seem to be related to cometchat. I've installed the latest version 4.6.0, but the session loss is still occurring. I can work around this by excluding cometchat on the pages containing my script.

USEFUL INFO: Just in case someone else finds themselves struggling with Joomla session-I found this website quite useful http://tutsforu.com/joomla-module-tutorial/8-joomla-tutorial/75-using-session-in-joomla.html

Specifically

$session->getId();
$session->get('session.counter');
$session->isNew();
$session->getName();
$session->getState();
$session->getExpire();
Potation answered 24/10, 2012 at 15:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.