Question

I am developing for Joomla! 2.5.6 and this code used to work fine with Joomla 1.5

Page 1

JFactory::getSession()->clear('domain_name', 'dominiForm');

Page 2

$session = JFactory::getSession();
$session->set('domain_name', $domain_name, 'dominiForm');

Page 3

$session = JFactory::getSession();
$domain_name = $session->get('domain_name', null, 'dominiForm');

The problem is page 3 sometimes returns null, sometimes it returns the saved value. It works ok on my development machine, but not on production server, I don't know what to do.

Here is some of the phpinfo() on the server

PHP Version 5.3.3-7+squeeze14
session
Session Support     enabled
Registered save handlers    files user sqlite
Registered serializer handlers  php php_binary wddx

Directive   Local Value Master Value
session.auto_start  Off Off
session.bug_compat_42   Off Off
session.bug_compat_warn Off Off
session.cache_expire    180 180
session.cache_limiter   none    nocache
session.cookie_domain   no value    no value
session.cookie_httponly Off Off
session.cookie_lifetime 0   0
session.cookie_path /   /
session.cookie_secure   Off Off
session.entropy_file    no value    no value
session.entropy_length  0   0
session.gc_divisor  1000    1000
session.gc_maxlifetime  2700    1440
session.gc_probability  0   0
session.hash_bits_per_character 5   5
session.hash_function   0   0
session.name    a6252c638b628a21b4b4b1cf3338a103    PHPSESSID
session.referer_check   no value    no value
session.save_handler    user    files
session.save_path   /var/lib/php5   /var/lib/php5
session.serialize_handler   php php
session.use_cookies On  On
session.use_only_cookies    On  On
session.use_trans_sid   0   0
Was it helpful?

Solution

You are using a custom session.save_handler on your production server. Probably you don't on your development machine.

Please be aware that Joomla does get the session locking wrong - there is none. Essentially this means that you are the victim of a race condition.

If you take a look at the documentaion for session_set_save_handler(), you will see that there are callbacks for open, close, read, write, destroy and gc (garbage collection).

open should "initialize" stuff, but most importanty should aquire a write lock to the ressource used for storage.

read does the usual reading, write does the writing.

close should release the write lock.

If a session save handler does not aquire the lock, multiple parallel requests with the same session id can overwrite each other!

There is a simple test you should execute on your server to see if you have this problem:

<?php

// initialize alternate session save handler here.
//include_once "session-handler.php";

if (isset($_GET['subrequest'])) {
    $starttime = time();
    $subrequest = intval($_GET['subrequest']);

    session_start(); // should wait until lock is released

    echo "<html><pre>";
    echo "Request started on ". date("Y-m-d H:i:s", $starttime)."\n";
    echo "Session locked for this request on ". date("Y-m-d H:i:s"). "\n";
    echo "Executing subrequest ". $subrequest."\n";
    $_SESSION["subrequest"][] = 'collected subrequest #'.$subrequest;
    echo "All subrequests collected:\n";
    var_dump($_SESSION["subrequest"]);
    echo "\nWaiting 1 second\n";

    sleep(1);
    echo "Releasing session lock on ". date("Y-m-d H:i:s"). "\n";
    echo "</pre></html>";
    exit();
}

session_start();

$_SESSION['subrequest'] = array('master request');

?>
<html>
<iframe src="?subrequest=1" width="90%" height="100"></iframe>
<hr>
<iframe src="?subrequest=2" width="90%" height="100"></iframe>
<hr>
<iframe src="?subrequest=3" width="90%" height="100"></iframe>
</html>

This PHP file will initialize the session and emit three iframes on screen that almost instantly make three requests to the server again.

If the session is proberly locked, then each of the iframes will be filled serially one after another the following seconds. Additionally, in order of appearance, the control output of $_SESSION['subrequest'] should include ALL subrequests on the one that returned last.

If the session is NOT locked properly, all three iframes will fill almost instantly one second after the main page was loaded, and the will all report only their own subrequest together with the master request in the debug output.

If I use this implementation for filesystem storage I got from the php.net documentation (Example #2) page, proper saving to the session fails!

<?php
class FileSessionHandler
{
    private $savePath;

    function open($savePath, $sessionName)
    {
        $this->savePath = $savePath;
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    function close()
    {
        return true;
    }

    function read($id)
    {
        return (string)@file_get_contents("$this->savePath/sess_$id");
    }

    function write($id, $data)
    {
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
    }

    function destroy($id)
    {
        $file = "$this->savePath/sess_$id";
        if (file_exists($file)) {
            unlink($file);
        }

        return true;
    }

    function gc($maxlifetime)
    {
        foreach (glob("$this->savePath/sess_*") as $file) {
            if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
                unlink($file);
            }
        }

        return true;
    }
}

$handler = new FileSessionHandler();
session_set_save_handler(
    array($handler, 'open'),
    array($handler, 'close'),
    array($handler, 'read'),
    array($handler, 'write'),
    array($handler, 'destroy'),
    array($handler, 'gc')
);

// the following prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');

If I take a look at some Joomla session classes, I'd predict that storing to APC, databases and XCache will fail this test, because they use custom functions without implementing open or close properly.

I am not fluent with Joomla, so you will have to implement the Joomla way of using sessions into this test script yourself.

One final note: If locking is not possible on a single dataset in the database (e.g. you are using MyISAM tables), then effectively you cannot use this table for storing session data. Aquiring a lock on the table will stop ALL other USERS sessions.

OTHER TIPS

Do you use a caching mechanism on your production maschine, like varnish? Because caching is always a mess when dealing with sessions and joomla, got a lot of problems related to caching myself when I used caches (that's why i currently don't use one, just APC without user cache).

I think you can use this script In the first or second page use following script

 $session =& JFactory::getSession();
    $session->set('name', "value");

*name is your session variable and value is your value

then in the 3rd page use this

$session =& JFactory::getSession();

echo $session->get('name'); *name is your session variable

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top