Php loses part of a session randomly

I am developing for Joomla! 2.5.6, and this code was used to work 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 on page 3 sometimes returns null, sometimes it returns a stored value. It works fine on my development machine, but not on the production server, I don't know what to do.

Here are some of 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 
+4
source share
3 answers

You are using custom session.save_handler on your production server. You are probably not on your development machine.

Remember that Joomla really does block the session incorrectly - no. In essence, this means that you are a victim of a race condition.

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

open should “initialize” the material, but most importantly, it must provide write locks for the source used for storage.

read regular reading is done, write .

close should release the write lock.

If the session persistence handler does not use locking, multiple concurrent requests with the same session identifier can overwrite each other!

A simple test that you should run on your server to find out 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("Ymd H:i:s", $starttime)."\n"; echo "Session locked for this request on ". date("Ymd 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("Ymd 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 initializes the session and selects three frames on the screen, which almost immediately make three requests to the server again.

If the session is blocked, then each of the frames will be filled sequentially one after another in the following seconds. Also, in order of appearance, the control output of $_SESSION['subrequest'] should include ALL subqueries on the one that returned last.

If the session is NOT properly locked, all three frames will fill up almost instantly one second after loading the main page, and all will report only their own subquery along with the main request for debugging output.

If I use this implementation to store the file system, I got on the php.net documentation page (example No. 2) , the correct 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 look at some classes of Joomla sessions, I would predict that storing in APC, database, and XCache will not be able to run this test because they use user-defined functions without the proper open or close implementation.

I don’t own Joomla, so you have to implement Joomla way to use sessions in this test script yourself.

One final note: if locking is not possible in one data set in the database (for example, you use MyISAM tables), then effectively you cannot use this table to store session data. Starting a lock on the table will stop ALL other USERS sessions.

+4
source

Do you use caching mechanism on your production machine, for example, varnish? Since caching is always a mess when working with sessions and joomla, I had a lot of problems related to caching myself when I used caches (why I don’t currently use it, just APC without user cache).

0
source

I think you can use this script. On the first or second page, use the following script

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

* name is your session variable, and value is your value

then on the third page use this

 $session =& JFactory::getSession(); 

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

0
source

Source: https://habr.com/ru/post/1437339/


All Articles