User tests: Successful: Unsuccessful:

avatar JonahBraun
14 Mar 2012

This is the vendor neutral fix, I have another pull request open with a preferred mysql specific fix.


A bug exists in JSessionStorageDatabase::write() (libraries/joomla/session/storage/database.php:94). The logic assumes that an update will have one affected row if a session exists. However, this is not true. The timestamp is only granular in seconds and may be the same with multiple ajax requests, refreshes on different tabs, etc. When the timestamp is the same the entry is exactly the same and the update will not affect any rows. With the current logic an insert will be attempted and this results in a 500.

The fix

This fix uses a SELECT COUNT to determine a session row currently exists and should be updated.

Example Error

500 - JDatabaseMySQLi::query: 1062 - Duplicate entry 'e33c3ab2b05a9dc97dc25187a823b8e6' for key 'PRIMARY' SQL=INSERT INTO `jos_session` (`session_id`, `data`, `time`) VALUES ('e33c3ab2b05a9dc97dc25187a823b8e6', '__default|a:8:{s:22:\"session.client.browser\";s:119:\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.54 Safari/535.19\";s:15:\"session.counter\";i:43;s:8:\"registry\";O:9:\"JRegistry\":1:{s:7:\"\0*\0data\";O:8:\"stdClass\":0:{}}s:4:\"user\";O:5:\"JUser\":23:{s:9:\"\0*\0isRoot\";b:0;s:2:\"id\";i:0;s:4:\"name\";N;s:8:\"username\";N;s:5:\"email\";N;s:8:\"password\";N;s:14:\"password_clear\";s:0:\"\";s:8:\"usertype\";N;s:5:\"block\";N;s:9:\"sendEmail\";i:0;s:12:\"registerDate\";N;s:13:\"lastvisitDate\";N;s:10:\"activation\";N;s:6:\"params\";N;s:6:\"groups\";a:0:{}s:5:\"guest\";i:1;s:10:\"\0*\0_params\";O:9:\"JRegistry\":1:{s:7:\"\0*\0data\";O:8:\"stdClass\":0:{}}s:14:\"\0*\0_authGroups\";a:1:{i:0;i:1;}s:14:\"\0*\0_authLevels\";a:2:{i:0;i:1;i:1;i:1;}s:15:\"\0*\0_authActions\";N;s:12:\"\0*\0_errorMsg\";N;s:10:\"\0*\0_errors\";a:0:{}s:3:\"aid\";i:0;}s:13:\"session.token\";s:32:\"cc3f66462deb72a899115b2ea51f8608\";s:19:\"session.timer.start\";i:1331743210;s:18:\"session.timer.last\";i:1331744856;s:17:\"\";i:1331744857;}', '1331744857')
avatar JonahBraun JonahBraun - open - 14 Mar 2012
avatar elinw
elinw - comment - 15 Mar 2012

I will be so happy never to have a bug report or forum discussion on that again.

avatar pollen8
pollen8 - comment - 16 Mar 2012

me 2 +1 LOL

avatar oc666
oc666 - comment - 18 Mar 2012

see my comment in the tracker about microtime

avatar ercanozkaya
ercanozkaya - comment - 18 Apr 2012

Those who need to work this around can use something like this:
JFactory::getSession()->set('com_docman.fix.the.session.bug', microtime(true));

avatar oc666
oc666 - comment - 18 Apr 2012

@ercanozkaya don't forget to update you session table to be able to contain all the microtime:
ALTER TABLE #__jos_session MODIFY COLUMN time varchar(15) DEFAULT '';

avatar ercanozkaya
ercanozkaya - comment - 18 Apr 2012

@oc666 Not needed for the workaround. This just changes something in the session data so that the database query will return an affected row.

avatar SvenRtbg
SvenRtbg - comment - 1 Dec 2012

The point everyone misses is this: Using a session in more than one concurrent request requires proper locking. Otherwise, a situation like this destroys data: Two requests both read the session data first, then both change different things in the session, and after a different runtime, both try to save to the storage. The request saving last wins.

This problem is included in ALL Joomla session storage modules with the exception of the "None" module, because neither acquires an exclusive lock on the session data when executing "open()" and releases it when executing "close()".

avatar coolbung coolbung - reference | 7753bf4 - 30 Aug 13
avatar phproberto
phproberto - comment - 3 Oct 2013

I'm closing this as it's not mergeable and 2 years old. Feel free to open if you update it and are still interested in get it merged.

Thanks for contributing.

avatar phproberto phproberto - close - 3 Oct 2013

Add a Comment

Login with GitHub to post a comment