On occasions, it has proved difficult to amend the configuration of a zone in SmartOS using –

vmadm update <uuid>

SmartOS zone configuration may be accessed and amended directly using the zonecfg command as follows –

zonecfg -z <uuid>
zonecfg:uuid> select attr name="dns-domain"
zonecfg:uuid:attr> set value="example.net"
zonecfg:uuid:attr> end
zonecfg:uuid> verify
zonecfg:uuid> commit
zonecfg:uuid> exit

Joomla 3 Session management

JSession - libraries/joomla/session/session.php

JSessionStorage (abstract) - libraries/joomla/session/storage.php

JSessionStorageDatabase - libraries/joomla/session/storage/database.php

Overview

Session handler - [ database | memcache | memcached | wincache | xcache | apc ]

Provides for the production of form tokens to prevent spoofing of variable names (JSession::getFormToken()).

getToken - form processing invalidate post request if token is not present or not correct.

hasToken

Psuedo code

Session lifecycle
Session instantiation
  1. JSession::getInstance() which entails –
    1. create session handler of the specified type using JSessionStorage::getInstance;
    2. call JSessionStorage::register() to register the open, close, read, write, destroy and garbage collection functions of the relevant JSessionStorage object with the PHP session persistence manager using the PHP function session_set_save_handler;
  2. JSession::initialise($input, $dispatcher);
  3. JSession::start() which –
    1. processes the cookie received from the user agent to determine the session name;
    2. registers the PHP function session_write_close() as the shutdown function;
    3. calls the PHP session management function session_start() which, in turn –
      1. makes a call to the 'open' session persistence function set, above; and
      2. makes a call to the 'read' session persistence function.
Session application
JView::display
JController::<action>
  1. JSession::has(), JSession::get(), JSession::set();
  2. JSession::getFormToken(), JSession::checkToken($type ['request'])
Session destruction

The JSession object is not formally destroyed at any point by the Joomla framework. Instead, the Joomla framework uses JSession as a form of shim layer for PHP session management provision wherein JSession::get and JSession::set operations access and update the global variable $_SESSION which is created, read, updated and deleted by PHP session management through the save handlers. Accordingly, any changes to the data associated with the session are written to the persistent store indirectly through a call to session_write_close(), itself invoked on a call to the PHP function exit() by virtue of the registration of session_write_close as the shutdown function. In turn, the session_write_close function executes the JStorageSession::write() and JStorageSession::close() functions by virtue of the call to session_set_save_handler() function made by the JSession constructor.

Psuedo code

 Accepts a session handler, and an array of options.

JSession

JSession::getInstance, JSession::__construct

Psuedo code

  1. if a PHP session has been identified automatically by the PHP environment according to the php.ini configuration parameter, session.auto_start, call session_unset() to unset the variables associated with the global session variable $_SESSION followed by session_destroy() to destroy the session data stored in the persistent store;
  2. disable PHP transparent session identifier support (session.use_trans_sid);
  3. require PHP session management to rely upon the use of cookies only (session.use_only_cookies);
  4. create a session handler of the specified type using JSessionStorage::getInstance($session_handler ['database'], $options) which, on instantiation, registers functions associated with the JSessionStorage object as PHP session save handlers;
  5. set certain global PHP variables and JSession members according to the values provided by $options using JSession::_setOptions($options) as follows –
    1. session_name : md5($options['name']);
    2. session_id : $options['id'];
    3. JSession::$_expire : $options['expire'];
    4. JSession::$_security : $options['security'];
    5. JSession::$_force_ssl : $options['force_ssl'];
    6. session.gc_maxlifetime : $options['expire'];
  6. JSession::_setCookieParams() as follows –
    1. session_get_cookie_params();
    2. if $JSession::_force_ssl is true, set $cookie['secure'] to true;
    3. $cookie['domain'] = <configuration>('cookie_domain')
    4. $cookie['path'] = <configuration>('cookie_path')
    5. session_set_cookie_params($cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'], true)
  7. mark JSession object as being in an 'inactive' state.

JSession::checkToken($method [post])

Psuedo code

  1. obtain the value associated with the form token given by JSession::getFormToken from the JInput object associated with the relevant JApplication object;
  2. if there is no associated value
  3. if the JSession object is 'new' in the sense the session activity counter is equal to 1, redirect the client browser to the index page with a message to the effect that the session has expired;
  4. otherwise, return false;
  5. if there is an associated value, return true.

JSession::getFormToken($forceNew [false]) [static]

Psuedo code

  1. if JApplication::getHash method exists, call JApplication::getHash on the catenated user identifier, and session token provided by JSession::getToken($forceNew);
  2. otherwise, generate an MD5 hash value from the catenated values of the application 'secret value', the user identifier and the session token provided by JSession::getToken($forceNew).

JSession::initialise($input, $dispatcher)

Psuedo code

  1. assign the object reference of $input to JSession::$_input;
  2. assign the object reference of $dispatcher to JSession::$_dispatcher.

JSession::start()

Psuedo code

  1. if the JSession object is not 'active' –
  2. activate the JSession object using JSession::_start() which –
  3. mark the JSession object as 'active';
  4. increment the session activity counter using JSession::_setCounter();
  5. update the session timers to reflect the time the session was created, when it was last used and the time now using JSession::_setTimers() to enable JSession to detect a lapsed or expired session;
  6. perform security checks on the session information recovered using JSession::_validate() as follows –
    1. check if the session has expired;
    2. record the identity of the intermediate proxy provided by HTTP_X_FORWARDED_FOR;
    3. record or check the client address is the same as that previously used for the session;
    4. record or check the client browser provided by HTTP_USER_AGENT;
  7. trigger the 'onAfterSessionStart' event.

JSessionStorage

JSessionStorage is an abstract class that provides a framework for a variety of approaches to session state management.

JSessionStorage::close()

Purpose

JSessionStorage::close is responsible for closing the persistent store.

JSessionStorage::open($save_path, $session_name)

Purpose

JSessionStorage::open is responsible for opening the persistent store ready for the relevant read, write, destroy and garbage collection operations.

JSessionStorage::read($id)

Purpose

JSessionStorage::read is responsible for reading the serialized session data from the persistent store.

JSessionStorage::write($id, $session_data)

Purpose

JSessionStorage::write is responsible for writing the serialized session data to the persistent store.

JSessionStorage::destroy($id)

Purpose

JSessionStorage::destroy is responsible for deleting the relevant session from the persistent store.

JSessionStorage::gc($maxlifetime [null])

Purpose

JSessionStorage::gc is responsible for identifying [and deleting / destroying] sessions that have expired.

JSessionStorageDatabase

JSessionStorageDatabase::read($id)

Psuedo code

  1. obtain the global database object using JFactory::getDbo();
  2. construct SQL statement of the form 'SELECT data FROM #__session WHERE session_id = $id';
  3. execute SQL statement against the global database object; and
  4. post-process the returned result.

JSessionStorageDatabase::write($id, $data)

Psuedo code

  1. obtain the global database object using JFactory::getDbo();
  2. construct SQL statement of the form 'UPDATE #__session SET data = $data, time = <current time> WHERE session_id = $id';
  3. execute the SQL statement against the global database object;
  4. return true if the update was successful, or false if an exception was raised or the execute operation failed to update any rows of the #__session table.

JSessionStorageDatabase::destroy($id)

Psuedo code

  1. obtain the global database object using JFactory::getDbo();
  2. construct SQL statement of the form 'DELETE FROM #__session WHERE session_id = $id;
  3. execute the SQL statement against the global database object;
  4. return true if the delete operation was successful, or false if the operation resulted in an exception being raised or the operation failed to delete any of the rows of the #__session table.

JSessionStorageDatabase::gc($lifetime [1440])

Psuedo code

  1. obtain the global database object using JFactory::getDbo();
  2. determine the timestamp threshold before which the relevant sessions ought to be deleted;
  3. construct SQL statement of the form 'DELETE FROM #__session WHERE time < <timestamp threshold>';
  4. execute the SQL statement against the global database object;
  5. return true if the delete operation was successful, or false if the operation resulted in an exception being raised or the operation failed to delete any of the rows of the #__session table.

Application control flow

This article provides a structured breakdown of the application control flow for the administrative interface provided by Joomla 3 to assist in tracing problems involving the Joomla 3 application framework and third party components, modules and plug-ins. It is a work in progress reverse engineered from the source code for Joomla 3.2 and, accordingly: (1) this article may not reflect the current or subsequent state of of the Joomla 3 code base; and (2) this article is liable to change at any time without necessarily being brought fully up to date according to the then current version of Joomla 3.

Modules and classes

JFactory - libraries/joomla/factory.php

JApplicationBase - libraries/joomla/application/base.php

JApplicationWeb - libraries/joomla/application/web.php

JApplicationCms - libraries/cms/application/cms.php

JApplicationAdministrator - libraries/cms/application/administrator.php

JAdministrationHelper - administrator/includes/helper.php

JUri - libraries/joomla/uri/uri.php

JSession - libraries/session/session.php

JSessionStorage - libraries/session/storage.php

JPluginHelper - libraries/cms/plugin/helper.php

Overview

PSUEDO CODE

  1. create JApplicationAdministrator<JApplicationCms<JApplicationWeb<JApplicationBase object using JFactory::getApplication();
    1. load JEventDispatcher object → JApplicationAdministrator<JApplicationCms<JApplicationWeb<JApplicationBase::$dispatcher;
    2. load JSession object using JApplicationAdministrator<JApplicationCms::loadSession($session) and JFactory::getSession() → JApplicationAdministrator<JApplicationCms<JApplicationWeb::$session;
    3. start the PHP session using JSession::initialise($input, $dispatcher), and JSession::start();
    4. load JRegistry object containing the Joomla 3 framework configuration → JApplicationAdministrator<JApplicationCms<JApplicationWeb::$config;
    5. trigger the 'onAfterSessionStart' event;
  2. call the JApplicationAdministrator<JApplicationCms<JApplicationWeb<JApplicationBase::execute() object;
    1. call JApplicationAdministrator::doExecute();
    2. call JApplicationAdministrator::initialiseApp($options [array()]);
    3. sub- call JApplicationAdministrator<JApplicationCms::initialiseApp($options [array()]);
    4. sub- set JApplicationAdministrator<JApplicationCms<JApplicationWeb::$config, calling JFactory::getConfig();
    5. import the system plugins using JPluginHelper::importPlugin('system');
    6. trigger the 'onAfterInitialise' event;
    7. call JApplicationAdministrator::route();
    8. import the system plugins using JPluginHelper::importPlugin('system');
    9. trigger the 'onAfterRoute' event;
    10. call JApplicationAdministrator::dispatch();
    11. import the system plugins using JPluginHelper::importPlugin('system');
    12. trigger the 'onAfterDispatch' event;
    13. call JApplicationAdministrator::render();
    14. sub- call JApplicationAdministrator<JApplicationCms::render();
    15. trigger the 'onBeforeRender' event;
    16. trigger the 'onAfterRender' event;
    17. trigger the 'onAfterCompress' event;
    18. trigger the 'onAfterRespond' event;

Detailed control flow

index.php → JFactory::getApplication('administrator') → JApplicationBase::JApplicationWeb::JApplicationCms::getInstance('administrator') →

Create the JApplicationAdministrator object

new JApplicationAdministrator : JApplicationCms : JApplicationWeb : JApplicationBase

Load the JEventDispatcher object

JApplicationAdministration[JApplicationBase]::loadDispatcher() { loads the event dispatcher }

Get the JSession object

JConfig::get('session') → ::getSession()

Load the application configuration

JApplicationAdministrator[JApplicationWeb]::fetchConfigurationData() { load JPATH_ROOT / configuration.php }

JLoader::register( 'JConfig', JPATH_ROOT / configuration.php );

new JConfig();

JApplicationAdministrator[JApplicationWeb]::$config { JRegistry } → JRegistry::loadArray | JRegistry::loadObject { enumerate array elements / object attributes and insert them into the JRegistry object }

JApplicationAdministrator[JApplicationWeb]::loadConfiguration();

JApplicationAdministrator[JApplicationCms::loadSession()

{

generate session name using JApplicationHelper::getHash($session_name ['administrator'])

calculate session lifetime (per configuration) * 60 or 900 seconds

JFactory::getSession($options) → JSession::initialise($input, $dispatcher) → JSession::start()

JEventDispatcher::trigger('onAfterSessionStart')

if session is new, or [expired?] JApplicationAdministrator[JApplicationCms]::checkSession() { initialise session object in the database using the session id }

}

Execute the application

JApplicationAdministrator[JApplicationCms]::execute()

JApplicationAdministrator::doExecute()

JApplicationAdministrator::initialiseApp($options [array('language' => JApplicationAdministrator::getUserState('application.lang')])

{

JFactory::getUser()

JApplicationAdministrator<JApplicationCms::initialiseApp($options)

{

JFactory::getConfig()

JFactory::getUser()

[ select default editor for the user ]

JPluginHelper::importPlugin($type ['system'], $plugin [null], $autocreate [true], $dispatcher [null])

{

JPluginHelper::load() { loads the array of plugins from #__extensions according the the relevant user's authority provided by the value of the column 'access'. }

for each identified plugin, JPluginHelper::getPlugin($type, $name), new Plg<$type><$name>($dispatcher, array('type' => $type, 'name' => $name))

}

}

JApplicationAdministrator::loadLanguage()

}

Route

JApplicationAdministrator::route();

JApplicationAdministrator::$uri → JUri::getInstance('SERVER') → JUri::construct($uri) → JUri::parse($uri) → JString::parse_url($uri) → parse_url($encoded_uri)

JUri::$scheme ('http' | 'https')

JUri::$user ('')

JUri::$pass ('')

JUri::$port ('')

JUri::$path ('')

JUri::$query ('') [after the question mark - ?]

JUri::$fragment ('') [after the hash mark - #]

JUri::$vars () [output of parse_str(JUri::$query) - in the form of an associative array]

JApplicationAdministrator[JApplicationBase]::triggerEvent('onAfterRoute')

Dispatch

JApplicationAdministrator::dispatch();

JAdministrationHelper::findOption() → JApplicationAdministrator[JApplicationBase]::loadIdentity()

JFactory::getUser() → JFactory::getSession() → JFactory::createSession($options [array()]) → JFactory::getConfig() → JFactory::createConfig(JPATH_FLATFORM.'/config.php', 'PHP', '') → JRegistry::loadObject($config)

JSession::getInstance($handler ['database' from JConfig], $options [array( 'expire' => 15 * 60 seconds or 900 seconds )]) →

new JSession($handler, $options) → JSessionStorage::getInstance($store [$handler], $options)

JFilterInput::clean($store, 'word') [normalises the input]

[import storage/<$store ['database']>.php]

new JSessionStorageDatabase($options)

JSession::_setOptions($options) → session_id( { name, id, expire, security, force_ssl } ) →

JSession::_setCookieParams() → session_get_cookie_params() → session_set_cookie_params( { secure, domain, path, lifetime } )

 

→ JApplicationAdministrator[JApplicationBase]::getIdentity()

JApplicationAdministrator[JApplicationBase]::triggerEvent('onAfterDispatch')

Render

JApplicationAdministrator::render();

JInput::getCmd('option', 'com_login') { get 'option', default to com_login }

Get the JInput object ($this->input), the component (JInput::getCmd('option', 'com_login')), (JInput::getCmd('tmpl', 'index'))

JApplicationCms::render();

JApplicationCms::triggerEvent('onBeforeRender');

JDocument::render($caching, $options);

JApplicationCms::triggerEvent('onAfterRender');

Compress

JApplicationAdministrator[JApplicationWeb]::compress();

JApplicationAdministrator[JApplicationBase]::triggerEvent('onAfterCompress');

Respond

JApplicationAdministrator[JApplicationWeb]::respond();

JApplicationAdministrator[JApplicationBase]::triggerEvent('onAfterRespond');