Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The One Right Session Management Configuration For Joomla! 3 #19687

Merged
merged 8 commits into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INSERT INTO `#__extensions` (`extension_id`, `package_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES
(480, 0, 'plg_system_sessiongc', 'plugin', 'sessiongc', 'system', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INSERT INTO "#__extensions" ("extension_id", "package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES
(480, 0, 'plg_system_sessiongc', 'plugin', 'sessiongc', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INSERT INTO "#__extensions" ("extension_id", "package_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES
(480, 0, 'plg_system_sessiongc', 'plugin', 'sessiongc', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0);
15 changes: 15 additions & 0 deletions administrator/language/en-GB/en-GB.plg_system_sessiongc.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; Joomla! Project
; Copyright (C) 2005 - 2018 Open Source Matters. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

PLG_SYSTEM_SESSIONGC="System - Session Garbage Collection"
PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_GC_DESC="When enabled, this plugin will attempt to perform session garbage collection based on the odds calculated by the probability and divisor."
PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_GC_LABEL="Enable Session Garbage Collection"
PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_METADATA_GC_DESC="When enabled, this plugin will clean optional session metadata from the database. Note that this operation will not run when the database handler is in use as that data is cleared as part of the garbage collection operation."
PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_METADATA_GC_LABEL="Enable Session Metadata Cleanup"
PLG_SYSTEM_SESSIONGC_GC_DIVISOR_DESC="In combination with the probability field, these two fields are used to determine the odds of the garbage collection operation being triggered on a request. The probability is calculated by using probability/divisor, e.g. 1/100 means there is a 1% chance that the process runs on each request."
PLG_SYSTEM_SESSIONGC_GC_DIVISOR_LABEL="Divisor"
PLG_SYSTEM_SESSIONGC_GC_PROBABILITY_DESC="In combination with the divisor field, these two fields are used to determine the odds of the garbage collection operation being triggered on a request."
PLG_SYSTEM_SESSIONGC_GC_PROBABILITY_LABEL="Probability"
PLG_SYSTEM_SESSIONGC_XML_DESCRIPTION="System Plugin that handles session garbage collection tasks."
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
; Joomla! Project
; Copyright (C) 2005 - 2018 Open Source Matters. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

PLG_SYSTEM_SESSIONGC="System - Session Garbage Collection"
PLG_SYSTEM_SESSIONGC_XML_DESCRIPTION="System Plugin that handles session garbage collection tasks."
59 changes: 59 additions & 0 deletions cli/sessionMetadataGc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
/**
* @package Joomla.Cli
*
* @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

/**
* This is a CRON script to delete expired optional session metadata which should be called from the command-line, not the
* web. For example something like:
* /usr/bin/php /path/to/site/cli/sessionMetadataGc.php
*/

// Initialize Joomla framework
const _JEXEC = 1;

// Load system defines
if (file_exists(dirname(__DIR__) . '/defines.php'))
{
require_once dirname(__DIR__) . '/defines.php';
}

if (!defined('_JDEFINES'))
{
define('JPATH_BASE', dirname(__DIR__));
require_once JPATH_BASE . '/includes/defines.php';
}

// Get the framework.
require_once JPATH_LIBRARIES . '/import.legacy.php';

// Bootstrap the CMS libraries.
require_once JPATH_LIBRARIES . '/cms.php';

/**
* Cron job to trash expired session metadata.
*
* @since __DEPLOY_VERSION__
*/
class SessionMetadataGc extends JApplicationCli
{
/**
* Entry point for the script
*
* @return void
*
* @since __DEPLOY_VERSION__
*/
public function doExecute()
{
$metadataManager = new \Joomla\CMS\Session\MetadataManager($this, \Joomla\CMS\Factory::getDbo());
$sessionExpire = \Joomla\CMS\Factory::getSession()->getExpire();

$metadataManager->deletePriorTo(time() - $sessionExpire);
}
}

JApplicationCli::getInstance('SessionMetadataGc')->execute();
1 change: 1 addition & 0 deletions installation/sql/mysql/joomla.sql
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ INSERT INTO `#__extensions` (`extension_id`, `package_id`, `name`, `type`, `elem
(477, 0, 'plg_content_fields', 'plugin', 'fields', 'content', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(478, 0, 'plg_editors-xtd_fields', 'plugin', 'fields', 'editors-xtd', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(479, 0, 'plg_sampledata_blog', 'plugin', 'blog', 'sampledata', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(480, 0, 'plg_system_sessiongc', 'plugin', 'sessiongc', 'system', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(503, 0, 'beez3', 'template', 'beez3', '', 0, 1, 1, 0, '', '{"wrapperSmall":"53","wrapperLarge":"72","sitetitle":"","sitedescription":"","navposition":"center","templatecolor":"nature"}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(504, 0, 'hathor', 'template', 'hathor', '', 1, 1, 1, 0, '', '{"showSiteName":"0","colourChoice":"0","boldText":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
(506, 0, 'protostar', 'template', 'protostar', '', 0, 1, 1, 0, '', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0),
Expand Down
1 change: 1 addition & 0 deletions installation/sql/postgresql/joomla.sql
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ INSERT INTO "#__extensions" ("extension_id", "package_id", "name", "type", "elem
(477, 0, 'plg_content_fields', 'plugin', 'fields', 'content', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(478, 0, 'plg_editors-xtd_fields', 'plugin', 'fields', 'editors-xtd', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(479, 0, 'plg_sampledata_blog', 'plugin', 'blog', 'sampledata', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(480, 0, 'plg_system_sessiongc', 'plugin', 'sessiongc', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(503, 0, 'beez3', 'template', 'beez3', '', 0, 1, 1, 0, '', '{"wrapperSmall":"53","wrapperLarge":"72","sitetitle":"","sitedescription":"","navposition":"center","templatecolor":"nature"}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(504, 0, 'hathor', 'template', 'hathor', '', 1, 1, 1, 0, '', '{"showSiteName":"0","colourChoice":"0","boldText":"0"}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
(506, 0, 'protostar', 'template', 'protostar', '', 0, 1, 1, 0, '', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}', '', '', 0, '1970-01-01 00:00:00', 0, 0),
Expand Down
1 change: 1 addition & 0 deletions installation/sql/sqlazure/joomla.sql
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,7 @@ INSERT INTO "#__extensions" ("extension_id", "package_id", "name", "type", "elem
(477, 0, 'plg_content_fields', 'plugin', 'fields', 'content', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0),
(478, 0, 'plg_editors-xtd_fields', 'plugin', 'fields', 'editors-xtd', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0),
(479, 0, 'plg_sampledata_blog', 'plugin', 'blog', 'sampledata', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0),
(480, 0, 'plg_system_sessiongc', 'plugin', 'sessiongc', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0),
(503, 0, 'beez3', 'template', 'beez3', '', 0, 1, 1, 0, '', '{"wrapperSmall":"53","wrapperLarge":"72","sitetitle":"","sitedescription":"","navposition":"center","templatecolor":"nature"}', '', '', 0, '1900-01-01 00:00:00', 0, 0),
(504, 0, 'hathor', 'template', 'hathor', '', 1, 1, 1, 0, '', '{"showSiteName":"0","colourChoice":"0","boldText":"0"}', '', '', 0, '1900-01-01 00:00:00', 0, 0),
(506, 0, 'protostar', 'template', 'protostar', '', 0, 1, 1, 0, '', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}', '', '', 0, '1900-01-01 00:00:00', 0, 0),
Expand Down
123 changes: 12 additions & 111 deletions libraries/src/Application/CMSApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Input\Input;
use Joomla\CMS\Session\MetadataManager;
use Joomla\Registry\Registry;

/**
Expand Down Expand Up @@ -62,6 +63,14 @@ class CMSApplication extends WebApplication
*/
protected $_messageQueue = array();

/**
* The session metadata manager
*
* @var MetadataManager
* @since __DEPLOY_VERSION__
*/
protected $metadataManager = null;

/**
* The name of the application.
*
Expand Down Expand Up @@ -106,6 +115,8 @@ public function __construct(Input $input = null, Registry $config = null, \JAppl
{
parent::__construct($input, $config, $client);

$this->metadataManager = new MetadataManager($this, \JFactory::getDbo());

// Load and set the dispatcher
$this->loadDispatcher();

Expand Down Expand Up @@ -134,60 +145,6 @@ public function __construct(Input $input = null, Registry $config = null, \JAppl
}
}

/**
* After the session has been started we need to populate it with some default values.
*
* @return void
*
* @since 3.2
*/
public function afterSessionStart()
{
$session = \JFactory::getSession();

if ($session->isNew())
{
$session->set('registry', new Registry);
$session->set('user', new \JUser);
}

// Get the session handler from the configuration.
$handler = $this->get('session_handler', 'none');

$time = time();

// If the database session handler is not in use and the current time is a divisor of 5, purge session metadata after the response is sent
if ($handler !== 'database' && $time % 5 === 0)
{
$this->registerEvent(
'onAfterRespond',
function () use ($session, $time)
{
// TODO: At some point we need to get away from having session data always in the db.
$db = \JFactory::getDbo();

$query = $db->getQuery(true)
->delete($db->quoteName('#__session'))
->where($db->quoteName('time') . ' < ' . $db->quote((int) ($time - $session->getExpire())));

$db->setQuery($query);

try
{
$db->execute();
}
catch (\JDatabaseExceptionExecuting $exception)
{
/*
* The database API logs errors on failures so we don't need to add any error handling mechanisms here.
* Since garbage collection does not result in a fatal error when run in the session API, we don't allow it here either.
*/
}
}
);
}
}

/**
* Checks the user session.
*
Expand All @@ -201,63 +158,7 @@ function () use ($session, $time)
*/
public function checkSession()
{
$db = \JFactory::getDbo();
$session = \JFactory::getSession();
$user = \JFactory::getUser();

$query = $db->getQuery(true)
->select($db->quoteName('session_id'))
->from($db->quoteName('#__session'))
->where($db->quoteName('session_id') . ' = ' . $db->quote($session->getId()));

$db->setQuery($query, 0, 1);
$exists = $db->loadResult();

// If the session record doesn't exist initialise it.
if (!$exists)
{
$query->clear();

$time = $session->isNew() ? time() : $session->get('session.timer.start');

$columns = array(
$db->quoteName('session_id'),
$db->quoteName('guest'),
$db->quoteName('time'),
$db->quoteName('userid'),
$db->quoteName('username'),
);

$values = array(
$db->quote($session->getId()),
(int) $user->guest,
$db->quote((int) $time),
(int) $user->id,
$db->quote($user->username),
);

if (!$this->get('shared_session', '0'))
{
$columns[] = $db->quoteName('client_id');
$values[] = (int) $this->getClientId();
}

$query->insert($db->quoteName('#__session'))
->columns($columns)
->values(implode(', ', $values));

$db->setQuery($query);

// If the insert failed, exit the application.
try
{
$db->execute();
}
catch (\RuntimeException $e)
{
throw new \RuntimeException(\JText::_('JERROR_SESSION_STARTUP'), $e->getCode(), $e);
}
}
$this->metadataManager->createRecordIfNonExisting(\JFactory::getSession(), \JFactory::getUser());
}

/**
Expand Down
Loading