PageRenderTime 131ms CodeModel.GetById 40ms app.highlight 45ms RepoModel.GetById 36ms app.codeStats 0ms

/libraries/joomla/application/application.php

https://bitbucket.org/izubizarreta/https-bitbucket.org-bityvip
PHP | 1173 lines | 536 code | 144 blank | 493 comment | 69 complexity | f5cf09edcc6309d9927eadb0821e51cd MD5 | raw file
   1<?php
   2/**
   3 * @package     Joomla.Platform
   4 * @subpackage  Application
   5 *
   6 * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
   7 * @license     GNU General Public License version 2 or later; see LICENSE
   8 */
   9
  10defined('JPATH_PLATFORM') or die;
  11
  12jimport('joomla.application.input');
  13jimport('joomla.event.dispatcher');
  14jimport('joomla.environment.response');
  15
  16/**
  17 * Base class for a Joomla! application.
  18 *
  19 * Acts as a Factory class for application specific objects and provides many
  20 * supporting API functions. Derived clases should supply the route(), dispatch()
  21 * and render() functions.
  22 *
  23 * @package     Joomla.Platform
  24 * @subpackage  Application
  25 * @since       11.1
  26 */
  27class JApplication extends JObject
  28{
  29	/**
  30	 * The client identifier.
  31	 *
  32	 * @var    integer
  33	 * @since  11.1
  34	 */
  35	protected $_clientId = null;
  36
  37	/**
  38	 * The application message queue.
  39	 *
  40	 * @var    array
  41	 * @since  11.1
  42	 */
  43	protected $_messageQueue = array();
  44
  45	/**
  46	 * The name of the application.
  47	 *
  48	 * @var    array
  49	 * @since  11.1
  50	 */
  51	protected $_name = null;
  52
  53	/**
  54	 * The scope of the application.
  55	 *
  56	 * @var    string
  57	 * @since  11.1
  58	 */
  59	public $scope = null;
  60
  61	/**
  62	 * The time the request was made.
  63	 *
  64	 * @var    date
  65	 * @since  11.1
  66	 */
  67	public $requestTime = null;
  68
  69	/**
  70	 * The time the request was made as Unix timestamp.
  71	 *
  72	 * @var    integer
  73	 * @since  11.1
  74	 */
  75	public $startTime = null;
  76
  77	/**
  78	 * The application input object.
  79	 *
  80	 * @var    JInput
  81	 * @since  11.2
  82	 */
  83	public $input = null;
  84
  85	/**
  86	 * @var    array  JApplication instances container.
  87	 * @since  11.3
  88	 */
  89	protected static $instances = array();
  90
  91	/**
  92	 * Class constructor.
  93	 *
  94	 * @param   array  $config  A configuration array including optional elements such as session
  95	 * session_name, clientId and others. This is not exhaustive.
  96	 *
  97	 * @since   11.1
  98	 */
  99	public function __construct($config = array())
 100	{
 101		jimport('joomla.error.profiler');
 102
 103		// Set the view name.
 104		$this->_name = $this->getName();
 105
 106		// Only set the clientId if available.
 107		if (isset($config['clientId']))
 108		{
 109			$this->_clientId = $config['clientId'];
 110		}
 111
 112		// Enable sessions by default.
 113		if (!isset($config['session']))
 114		{
 115			$config['session'] = true;
 116		}
 117
 118		// Create the input object
 119		if (class_exists('JInput'))
 120		{
 121			$this->input = new JInput;
 122		}
 123
 124		// Set the session default name.
 125		if (!isset($config['session_name']))
 126		{
 127			$config['session_name'] = $this->_name;
 128		}
 129
 130		// Set the default configuration file.
 131		if (!isset($config['config_file']))
 132		{
 133			$config['config_file'] = 'configuration.php';
 134		}
 135
 136		// Create the configuration object.
 137		if (file_exists(JPATH_CONFIGURATION . '/' . $config['config_file']))
 138		{
 139			$this->_createConfiguration(JPATH_CONFIGURATION . '/' . $config['config_file']);
 140		}
 141
 142		// Create the session if a session name is passed.
 143		if ($config['session'] !== false)
 144		{
 145			$this->_createSession(self::getHash($config['session_name']));
 146		}
 147
 148		$this->requestTime = gmdate('Y-m-d H:i');
 149
 150		// Used by task system to ensure that the system doesn't go over time.
 151		$this->startTime = JProfiler::getmicrotime();
 152	}
 153
 154	/**
 155	 * Returns the global JApplication object, only creating it if it
 156	 * doesn't already exist.
 157	 *
 158	 * @param   mixed   $client  A client identifier or name.
 159	 * @param   array   $config  An optional associative array of configuration settings.
 160	 * @param   string  $prefix  A prefix for class names
 161	 *
 162	 * @return  JApplication A JApplication object.
 163	 *
 164	 * @since   11.1
 165	 */
 166	public static function getInstance($client, $config = array(), $prefix = 'J')
 167	{
 168		if (empty(self::$instances[$client]))
 169		{
 170			// Load the router object.
 171			$info = JApplicationHelper::getClientInfo($client, true);
 172
 173			$path = $info->path . '/includes/application.php';
 174			if (file_exists($path))
 175			{
 176				include_once $path;
 177
 178				// Create a JRouter object.
 179				$classname = $prefix . ucfirst($client);
 180				$instance = new $classname($config);
 181			}
 182			else
 183			{
 184				$error = JError::raiseError(500, JText::sprintf('JLIB_APPLICATION_ERROR_APPLICATION_LOAD', $client));
 185				return $error;
 186			}
 187
 188			self::$instances[$client] = &$instance;
 189		}
 190
 191		return self::$instances[$client];
 192	}
 193
 194	/**
 195	 * Initialise the application.
 196	 *
 197	 * @param   array  $options  An optional associative array of configuration settings.
 198	 *
 199	 * @return  void
 200	 *
 201	 * @since   11.1
 202	 */
 203	public function initialise($options = array())
 204	{
 205		// Set the language in the class.
 206		$config = JFactory::getConfig();
 207
 208		// Check that we were given a language in the array (since by default may be blank).
 209		if (isset($options['language']))
 210		{
 211			$config->set('language', $options['language']);
 212		}
 213
 214		// Set user specific editor.
 215		$user = JFactory::getUser();
 216		$editor = $user->getParam('editor', $this->getCfg('editor'));
 217		if (!JPluginHelper::isEnabled('editors', $editor))
 218		{
 219			$editor = $this->getCfg('editor');
 220			if (!JPluginHelper::isEnabled('editors', $editor))
 221			{
 222				$editor = 'none';
 223			}
 224		}
 225
 226		$config->set('editor', $editor);
 227
 228		// Trigger the onAfterInitialise event.
 229		JPluginHelper::importPlugin('system');
 230		$this->triggerEvent('onAfterInitialise');
 231	}
 232
 233	/**
 234	 * Route the application.
 235	 *
 236	 * Routing is the process of examining the request environment to determine which
 237	 * component should receive the request. The component optional parameters
 238	 * are then set in the request object to be processed when the application is being
 239	 * dispatched.
 240	 *
 241	 * @return  void
 242	 *
 243	 * @since   11.1
 244	 */
 245	public function route()
 246	{
 247		// Get the full request URI.
 248		$uri = clone JURI::getInstance();
 249
 250		$router = $this->getRouter();
 251		$result = $router->parse($uri);
 252
 253		JRequest::set($result, 'get', false);
 254
 255		// Trigger the onAfterRoute event.
 256		JPluginHelper::importPlugin('system');
 257		$this->triggerEvent('onAfterRoute');
 258	}
 259
 260	/**
 261	 * Dispatch the application.
 262	 *
 263	 * Dispatching is the process of pulling the option from the request object and
 264	 * mapping them to a component. If the component does not exist, it handles
 265	 * determining a default component to dispatch.
 266	 *
 267	 * @param   string  $component  The component to dispatch.
 268	 *
 269	 * @return  void
 270	 *
 271	 * @since   11.1
 272	 */
 273	public function dispatch($component = null)
 274	{
 275		$document = JFactory::getDocument();
 276
 277		$document->setTitle($this->getCfg('sitename') . ' - ' . JText::_('JADMINISTRATION'));
 278		$document->setDescription($this->getCfg('MetaDesc'));
 279
 280		$contents = JComponentHelper::renderComponent($component);
 281		$document->setBuffer($contents, 'component');
 282
 283		// Trigger the onAfterDispatch event.
 284		JPluginHelper::importPlugin('system');
 285		$this->triggerEvent('onAfterDispatch');
 286	}
 287
 288	/**
 289	 * Render the application.
 290	 *
 291	 * Rendering is the process of pushing the document buffers into the template
 292	 * placeholders, retrieving data from the document and pushing it into
 293	 * the JResponse buffer.
 294	 *
 295	 * @return  void
 296	 *
 297	 * @since   11.1
 298	 */
 299	public function render()
 300	{
 301		$params = array('template' => $this->getTemplate(), 'file' => 'index.php', 'directory' => JPATH_THEMES, 'params' => $template->params);
 302
 303		// Parse the document.
 304		$document = JFactory::getDocument();
 305		$document->parse($params);
 306
 307		// Trigger the onBeforeRender event.
 308		JPluginHelper::importPlugin('system');
 309		$this->triggerEvent('onBeforeRender');
 310
 311		// Render the document.
 312		$caching = ($this->getCfg('caching') >= 2) ? true : false;
 313		JResponse::setBody($document->render($caching, $params));
 314
 315		// Trigger the onAfterRender event.
 316		$this->triggerEvent('onAfterRender');
 317	}
 318
 319	/**
 320	 * Exit the application.
 321	 *
 322	 * @param   integer  $code  Exit code
 323	 *
 324	 * @return  void     Exits the application.
 325	 *
 326	 * @since    11.1
 327	 */
 328	public function close($code = 0)
 329	{
 330		exit($code);
 331	}
 332
 333	/**
 334	 * Redirect to another URL.
 335	 *
 336	 * Optionally enqueues a message in the system message queue (which will be displayed
 337	 * the next time a page is loaded) using the enqueueMessage method. If the headers have
 338	 * not been sent the redirect will be accomplished using a "301 Moved Permanently"
 339	 * code in the header pointing to the new location. If the headers have already been
 340	 * sent this will be accomplished using a JavaScript statement.
 341	 *
 342	 * @param   string   $url      The URL to redirect to. Can only be http/https URL
 343	 * @param   string   $msg      An optional message to display on redirect.
 344	 * @param   string   $msgType  An optional message type. Defaults to message.
 345	 * @param   boolean  $moved    True if the page is 301 Permanently Moved, otherwise 303 See Other is assumed.
 346	 *
 347	 * @return  void  Calls exit().
 348	 *
 349	 * @since   11.1
 350	 *
 351	 * @see     JApplication::enqueueMessage()
 352	 */
 353	public function redirect($url, $msg = '', $msgType = 'message', $moved = false)
 354	{
 355		// Check for relative internal links.
 356		if (preg_match('#^index2?\.php#', $url))
 357		{
 358			$url = JURI::base() . $url;
 359		}
 360
 361		// Strip out any line breaks.
 362		$url = preg_split("/[\r\n]/", $url);
 363		$url = $url[0];
 364
 365		// If we don't start with a http we need to fix this before we proceed.
 366		// We could validly start with something else (e.g. ftp), though this would
 367		// be unlikely and isn't supported by this API.
 368		if (!preg_match('#^http#i', $url))
 369		{
 370			$uri = JURI::getInstance();
 371			$prefix = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port'));
 372
 373			if ($url[0] == '/')
 374			{
 375				// We just need the prefix since we have a path relative to the root.
 376				$url = $prefix . $url;
 377			}
 378			else
 379			{
 380				// It's relative to where we are now, so lets add that.
 381				$parts = explode('/', $uri->toString(array('path')));
 382				array_pop($parts);
 383				$path = implode('/', $parts) . '/';
 384				$url = $prefix . $path . $url;
 385			}
 386		}
 387
 388		// If the message exists, enqueue it.
 389		if (trim($msg))
 390		{
 391			$this->enqueueMessage($msg, $msgType);
 392		}
 393
 394		// Persist messages if they exist.
 395		if (count($this->_messageQueue))
 396		{
 397			$session = JFactory::getSession();
 398			$session->set('application.queue', $this->_messageQueue);
 399		}
 400
 401		// If the headers have been sent, then we cannot send an additional location header
 402		// so we will output a javascript redirect statement.
 403		if (headers_sent())
 404		{
 405			echo "<script>document.location.href='" . htmlspecialchars($url) . "';</script>\n";
 406		}
 407		else
 408		{
 409			$document = JFactory::getDocument();
 410			jimport('joomla.environment.browser');
 411			$navigator = JBrowser::getInstance();
 412			jimport('phputf8.utils.ascii');
 413			if ($navigator->isBrowser('msie') && !utf8_is_ascii($url))
 414			{
 415				// MSIE type browser and/or server cause issues when url contains utf8 character,so use a javascript redirect method
 416				echo '<html><head><meta http-equiv="content-type" content="text/html; charset=' . $document->getCharset() . '" />'
 417					. '<script>document.location.href=\'' . htmlspecialchars($url) . '\';</script></head></html>';
 418			}
 419			elseif (!$moved and $navigator->isBrowser('konqueror'))
 420			{
 421				// WebKit browser (identified as konqueror by Joomla!) - Do not use 303, as it causes subresources
 422				// reload (https://bugs.webkit.org/show_bug.cgi?id=38690)
 423				echo '<html><head><meta http-equiv="content-type" content="text/html; charset=' . $document->getCharset() . '" />'
 424					. '<meta http-equiv="refresh" content="0; url=' . htmlspecialchars($url) . '" /></head></html>';
 425			}
 426			else
 427			{
 428				// All other browsers, use the more efficient HTTP header method
 429				header($moved ? 'HTTP/1.1 301 Moved Permanently' : 'HTTP/1.1 303 See other');
 430				header('Location: ' . $url);
 431				header('Content-Type: text/html; charset=' . $document->getCharset());
 432			}
 433		}
 434		$this->close();
 435	}
 436
 437	/**
 438	 * Enqueue a system message.
 439	 *
 440	 * @param   string  $msg   The message to enqueue.
 441	 * @param   string  $type  The message type. Default is message.
 442	 *
 443	 * @return  void
 444	 *
 445	 * @since   11.1
 446	 */
 447	public function enqueueMessage($msg, $type = 'message')
 448	{
 449		// For empty queue, if messages exists in the session, enqueue them first.
 450		if (!count($this->_messageQueue))
 451		{
 452			$session = JFactory::getSession();
 453			$sessionQueue = $session->get('application.queue');
 454
 455			if (count($sessionQueue))
 456			{
 457				$this->_messageQueue = $sessionQueue;
 458				$session->set('application.queue', null);
 459			}
 460		}
 461
 462		// Enqueue the message.
 463		$this->_messageQueue[] = array('message' => $msg, 'type' => strtolower($type));
 464	}
 465
 466	/**
 467	 * Get the system message queue.
 468	 *
 469	 * @return  array  The system message queue.
 470	 *
 471	 * @since   11.1
 472	 */
 473	public function getMessageQueue()
 474	{
 475		// For empty queue, if messages exists in the session, enqueue them.
 476		if (!count($this->_messageQueue))
 477		{
 478			$session = JFactory::getSession();
 479			$sessionQueue = $session->get('application.queue');
 480
 481			if (count($sessionQueue))
 482			{
 483				$this->_messageQueue = $sessionQueue;
 484				$session->set('application.queue', null);
 485			}
 486		}
 487
 488		return $this->_messageQueue;
 489	}
 490
 491	/**
 492	 * Gets a configuration value.
 493	 *
 494	 * An example is in application/japplication-getcfg.php Getting a configuration
 495	 *
 496	 * @param   string  $varname  The name of the value to get.
 497	 * @param   string  $default  Default value to return
 498	 *
 499	 * @return  mixed  The user state.
 500	 *
 501	 * @since   11.1
 502	 */
 503	public function getCfg($varname, $default = null)
 504	{
 505		$config = JFactory::getConfig();
 506		return $config->get('' . $varname, $default);
 507	}
 508
 509	/**
 510	 * Method to get the application name.
 511	 *
 512	 * The dispatcher name is by default parsed using the classname, or it can be set
 513	 * by passing a $config['name'] in the class constructor.
 514	 *
 515	 * @return  string  The name of the dispatcher.
 516	 *
 517	 * @since   11.1
 518	 */
 519	public function getName()
 520	{
 521		$name = $this->_name;
 522
 523		if (empty($name))
 524		{
 525			$r = null;
 526			if (!preg_match('/J(.*)/i', get_class($this), $r))
 527			{
 528				JError::raiseError(500, JText::_('JLIB_APPLICATION_ERROR_APPLICATION_GET_NAME'));
 529			}
 530			$name = strtolower($r[1]);
 531		}
 532
 533		return $name;
 534	}
 535
 536	/**
 537	 * Gets a user state.
 538	 *
 539	 * @param   string  $key      The path of the state.
 540	 * @param   mixed   $default  Optional default value, returned if the internal value is null.
 541	 *
 542	 * @return  mixed  The user state or null.
 543	 *
 544	 * @since   11.1
 545	 */
 546	public function getUserState($key, $default = null)
 547	{
 548		$session = JFactory::getSession();
 549		$registry = $session->get('registry');
 550
 551		if (!is_null($registry))
 552		{
 553			return $registry->get($key, $default);
 554		}
 555
 556		return $default;
 557	}
 558
 559	/**
 560	 * Sets the value of a user state variable.
 561	 *
 562	 * @param   string  $key    The path of the state.
 563	 * @param   string  $value  The value of the variable.
 564	 *
 565	 * @return  mixed  The previous state, if one existed.
 566	 *
 567	 * @since   11.1
 568	 */
 569	public function setUserState($key, $value)
 570	{
 571		$session = JFactory::getSession();
 572		$registry = $session->get('registry');
 573
 574		if (!is_null($registry))
 575		{
 576			return $registry->set($key, $value);
 577		}
 578
 579		return null;
 580	}
 581
 582	/**
 583	 * Gets the value of a user state variable.
 584	 *
 585	 * @param   string  $key      The key of the user state variable.
 586	 * @param   string  $request  The name of the variable passed in a request.
 587	 * @param   string  $default  The default value for the variable if not found. Optional.
 588	 * @param   string  $type     Filter for the variable, for valid values see {@link JFilterInput::clean()}. Optional.
 589	 *
 590	 * @return  The request user state.
 591	 *
 592	 * @since   11.1
 593	 */
 594	public function getUserStateFromRequest($key, $request, $default = null, $type = 'none')
 595	{
 596		$cur_state = $this->getUserState($key, $default);
 597		$new_state = JRequest::getVar($request, null, 'default', $type);
 598
 599		// Save the new value only if it was set in this request.
 600		if ($new_state !== null)
 601		{
 602			$this->setUserState($key, $new_state);
 603		}
 604		else
 605		{
 606			$new_state = $cur_state;
 607		}
 608
 609		return $new_state;
 610	}
 611
 612	/**
 613	 * Registers a handler to a particular event group.
 614	 *
 615	 * @param   string  $event    The event name.
 616	 * @param   mixed   $handler  The handler, a function or an instance of a event object.
 617	 *
 618	 * @return  void
 619	 *
 620	 * @since   11.1
 621	 */
 622	public static function registerEvent($event, $handler)
 623	{
 624		$dispatcher = JDispatcher::getInstance();
 625		$dispatcher->register($event, $handler);
 626	}
 627
 628	/**
 629	 * Calls all handlers associated with an event group.
 630	 *
 631	 * @param   string  $event  The event name.
 632	 * @param   array   $args   An array of arguments.
 633	 *
 634	 * @return  array  An array of results from each function call.
 635	 *
 636	 * @since   11.1
 637	 */
 638	public function triggerEvent($event, $args = null)
 639	{
 640		$dispatcher = JDispatcher::getInstance();
 641
 642		return $dispatcher->trigger($event, $args);
 643	}
 644
 645	/**
 646	 * Login authentication function.
 647	 *
 648	 * Username and encoded password are passed the onUserLogin event which
 649	 * is responsible for the user validation. A successful validation updates
 650	 * the current session record with the user's details.
 651	 *
 652	 * Username and encoded password are sent as credentials (along with other
 653	 * possibilities) to each observer (authentication plugin) for user
 654	 * validation.  Successful validation will update the current session with
 655	 * the user details.
 656	 *
 657	 * @param   array  $credentials  Array('username' => string, 'password' => string)
 658	 * @param   array  $options      Array('remember' => boolean)
 659	 *
 660	 * @return  boolean  True on success.
 661	 *
 662	 * @since   11.1
 663	 */
 664	public function login($credentials, $options = array())
 665	{
 666		// Get the global JAuthentication object.
 667		jimport('joomla.user.authentication');
 668
 669		$authenticate = JAuthentication::getInstance();
 670		$response = $authenticate->authenticate($credentials, $options);
 671
 672		if ($response->status === JAuthentication::STATUS_SUCCESS)
 673		{
 674			// validate that the user should be able to login (different to being authenticated)
 675			// this permits authentication plugins blocking the user
 676			$authorisations = $authenticate->authorise($response, $options);
 677			foreach ($authorisations as $authorisation)
 678			{
 679				$denied_states = array(JAuthentication::STATUS_EXPIRED, JAuthentication::STATUS_DENIED);
 680				if (in_array($authorisation->status, $denied_states))
 681				{
 682					// Trigger onUserAuthorisationFailure Event.
 683					$this->triggerEvent('onUserAuthorisationFailure', array((array) $authorisation));
 684
 685					// If silent is set, just return false.
 686					if (isset($options['silent']) && $options['silent'])
 687					{
 688						return false;
 689					}
 690
 691					// Return the error.
 692					switch ($authorisation->status)
 693					{
 694						case JAuthentication::STATUS_EXPIRED:
 695							return JError::raiseWarning('102002', JText::_('JLIB_LOGIN_EXPIRED'));
 696							break;
 697						case JAuthentication::STATUS_DENIED:
 698							return JError::raiseWarning('102003', JText::_('JLIB_LOGIN_DENIED'));
 699							break;
 700						default:
 701							return JError::raiseWarning('102004', JText::_('JLIB_LOGIN_AUTHORISATION'));
 702							break;
 703					}
 704				}
 705			}
 706
 707			// Import the user plugin group.
 708			JPluginHelper::importPlugin('user');
 709
 710			// OK, the credentials are authenticated and user is authorised.  Lets fire the onLogin event.
 711			$results = $this->triggerEvent('onUserLogin', array((array) $response, $options));
 712
 713			/*
 714			 * If any of the user plugins did not successfully complete the login routine
 715			 * then the whole method fails.
 716			 *
 717			 * Any errors raised should be done in the plugin as this provides the ability
 718			 * to provide much more information about why the routine may have failed.
 719			 */
 720
 721			if (!in_array(false, $results, true))
 722			{
 723				// Set the remember me cookie if enabled.
 724				if (isset($options['remember']) && $options['remember'])
 725				{
 726					// Create the encryption key, apply extra hardening using the user agent string.
 727					$privateKey = self::getHash(@$_SERVER['HTTP_USER_AGENT']);
 728
 729					$key = new JCryptKey('simple', $privateKey, $privateKey);
 730					$crypt = new JCrypt(new JCryptCipherSimple, $key);
 731					$rcookie = $crypt->encrypt(serialize($credentials));
 732					$lifetime = time() + 365 * 24 * 60 * 60;
 733
 734					// Use domain and path set in config for cookie if it exists.
 735					$cookie_domain = $this->getCfg('cookie_domain', '');
 736					$cookie_path = $this->getCfg('cookie_path', '/');
 737					setcookie(self::getHash('JLOGIN_REMEMBER'), $rcookie, $lifetime, $cookie_path, $cookie_domain);
 738				}
 739
 740				return true;
 741			}
 742		}
 743
 744		// Trigger onUserLoginFailure Event.
 745		$this->triggerEvent('onUserLoginFailure', array((array) $response));
 746
 747		// If silent is set, just return false.
 748		if (isset($options['silent']) && $options['silent'])
 749		{
 750			return false;
 751		}
 752
 753		// If status is success, any error will have been raised by the user plugin
 754		if ($response->status !== JAuthentication::STATUS_SUCCESS)
 755		{
 756			JError::raiseWarning('102001', $response->error_message);
 757		}
 758
 759		return false;
 760	}
 761
 762	/**
 763	 * Logout authentication function.
 764	 *
 765	 * Passed the current user information to the onUserLogout event and reverts the current
 766	 * session record back to 'anonymous' parameters.
 767	 * If any of the authentication plugins did not successfully complete
 768	 * the logout routine then the whole method fails. Any errors raised
 769	 * should be done in the plugin as this provides the ability to give
 770	 * much more information about why the routine may have failed.
 771	 *
 772	 * @param   integer  $userid   The user to load - Can be an integer or string - If string, it is converted to ID automatically
 773	 * @param   array    $options  Array('clientid' => array of client id's)
 774	 *
 775	 * @return  boolean  True on success
 776	 *
 777	 * @since   11.1
 778	 */
 779	public function logout($userid = null, $options = array())
 780	{
 781		// Get a user object from the JApplication.
 782		$user = JFactory::getUser($userid);
 783
 784		// Build the credentials array.
 785		$parameters['username'] = $user->get('username');
 786		$parameters['id'] = $user->get('id');
 787
 788		// Set clientid in the options array if it hasn't been set already.
 789		if (!isset($options['clientid']))
 790		{
 791			$options['clientid'] = $this->getClientId();
 792		}
 793
 794		// Import the user plugin group.
 795		JPluginHelper::importPlugin('user');
 796
 797		// OK, the credentials are built. Lets fire the onLogout event.
 798		$results = $this->triggerEvent('onUserLogout', array($parameters, $options));
 799
 800		// Check if any of the plugins failed. If none did, success.
 801
 802		if (!in_array(false, $results, true))
 803		{
 804			// Use domain and path set in config for cookie if it exists.
 805			$cookie_domain = $this->getCfg('cookie_domain', '');
 806			$cookie_path = $this->getCfg('cookie_path', '/');
 807			setcookie(self::getHash('JLOGIN_REMEMBER'), false, time() - 86400, $cookie_path, $cookie_domain);
 808
 809			return true;
 810		}
 811
 812		// Trigger onUserLoginFailure Event.
 813		$this->triggerEvent('onUserLogoutFailure', array($parameters));
 814
 815		return false;
 816	}
 817
 818	/**
 819	 * Gets the name of the current template.
 820	 *
 821	 * @param   array  $params  An optional associative array of configuration settings
 822	 *
 823	 * @return  string  System is the fallback.
 824	 *
 825	 * @since   11.1
 826	 */
 827	public function getTemplate($params = false)
 828	{
 829		return 'system';
 830	}
 831
 832	/**
 833	 * Returns the application JRouter object.
 834	 *
 835	 * @param   string  $name     The name of the application.
 836	 * @param   array   $options  An optional associative array of configuration settings.
 837	 *
 838	 * @return  JRouter  A JRouter object
 839	 *
 840	 * @since   11.1
 841	 */
 842	static public function getRouter($name = null, array $options = array())
 843	{
 844		if (!isset($name))
 845		{
 846			$app = JFactory::getApplication();
 847			$name = $app->getName();
 848		}
 849
 850		jimport('joomla.application.router');
 851		$router = JRouter::getInstance($name, $options);
 852
 853		if ($router instanceof Exception)
 854		{
 855			return null;
 856		}
 857
 858		return $router;
 859	}
 860
 861	/**
 862	 * This method transliterates a string into an URL
 863	 * safe string or returns a URL safe UTF-8 string
 864	 * based on the global configuration
 865	 *
 866	 * @param   string  $string  String to process
 867	 *
 868	 * @return  string  Processed string
 869	 *
 870	 * @since   11.1
 871	 */
 872	static public function stringURLSafe($string)
 873	{
 874		if (JFactory::getConfig()->get('unicodeslugs') == 1)
 875		{
 876			$output = JFilterOutput::stringURLUnicodeSlug($string);
 877		}
 878		else
 879		{
 880			$output = JFilterOutput::stringURLSafe($string);
 881		}
 882
 883		return $output;
 884	}
 885
 886	/**
 887	 * Returns the application JPathway object.
 888	 *
 889	 * @param   string  $name     The name of the application.
 890	 * @param   array   $options  An optional associative array of configuration settings.
 891	 *
 892	 * @return  JPathway  A JPathway object
 893	 *
 894	 * @since   11.1
 895	 */
 896	public function getPathway($name = null, $options = array())
 897	{
 898		if (!isset($name))
 899		{
 900			$name = $this->_name;
 901		}
 902
 903		jimport('joomla.application.pathway');
 904		$pathway = JPathway::getInstance($name, $options);
 905
 906		if ($pathway instanceof Exception)
 907		{
 908			return null;
 909		}
 910
 911		return $pathway;
 912	}
 913
 914	/**
 915	 * Returns the application JPathway object.
 916	 *
 917	 * @param   string  $name     The name of the application/client.
 918	 * @param   array   $options  An optional associative array of configuration settings.
 919	 *
 920	 * @return  JMenu  JMenu object.
 921	 *
 922	 * @since   11.1
 923	 */
 924	public function getMenu($name = null, $options = array())
 925	{
 926		if (!isset($name))
 927		{
 928			$name = $this->_name;
 929		}
 930
 931		jimport('joomla.application.menu');
 932		$menu = JMenu::getInstance($name, $options);
 933
 934		if ($menu instanceof Exception)
 935		{
 936			return null;
 937		}
 938
 939		return $menu;
 940	}
 941
 942	/**
 943	 * Provides a secure hash based on a seed
 944	 *
 945	 * @param   string  $seed  Seed string.
 946	 *
 947	 * @return  string  A secure hash
 948	 *
 949	 * @since   11.1
 950	 */
 951	public static function getHash($seed)
 952	{
 953		return md5(JFactory::getConfig()->get('secret') . $seed);
 954	}
 955
 956	/**
 957	 * Create the configuration registry.
 958	 *
 959	 * @param   string  $file  The path to the configuration file
 960	 *
 961	 * @return   object  A JConfig object
 962	 *
 963	 * @since   11.1
 964	 */
 965	protected function _createConfiguration($file)
 966	{
 967		JLoader::register('JConfig', $file);
 968
 969		// Create the JConfig object.
 970		$config = new JConfig;
 971
 972		// Get the global configuration object.
 973		$registry = JFactory::getConfig();
 974
 975		// Load the configuration values into the registry.
 976		$registry->loadObject($config);
 977
 978		return $config;
 979	}
 980
 981	/**
 982	 * Create the user session.
 983	 *
 984	 * Old sessions are flushed based on the configuration value for the cookie
 985	 * lifetime. If an existing session, then the last access time is updated.
 986	 * If a new session, a session id is generated and a record is created in
 987	 * the #__sessions table.
 988	 *
 989	 * @param   string  $name  The sessions name.
 990	 *
 991	 * @return  JSession  JSession on success. May call exit() on database error.
 992	 *
 993	 * @since   11.1
 994	 */
 995	protected function _createSession($name)
 996	{
 997		$options = array();
 998		$options['name'] = $name;
 999
1000		switch ($this->_clientId)
1001		{
1002			case 0:
1003				if ($this->getCfg('force_ssl') == 2)
1004				{
1005					$options['force_ssl'] = true;
1006				}
1007				break;
1008
1009			case 1:
1010				if ($this->getCfg('force_ssl') >= 1)
1011				{
1012					$options['force_ssl'] = true;
1013				}
1014				break;
1015		}
1016
1017		$session = JFactory::getSession($options);
1018
1019		//TODO: At some point we need to get away from having session data always in the db.
1020
1021		$db = JFactory::getDBO();
1022
1023		// Remove expired sessions from the database.
1024		$time = time();
1025		if ($time % 2)
1026		{
1027			// The modulus introduces a little entropy, making the flushing less accurate
1028			// but fires the query less than half the time.
1029			$query = $db->getQuery(true);
1030			$query->delete($query->qn('#__session'))
1031				->where($query->qn('time') . ' < ' . $query->q((int) ($time - $session->getExpire())));
1032
1033			$db->setQuery($query);
1034			$db->execute();
1035		}
1036
1037		// Check to see the the session already exists.
1038		if (($this->getCfg('session_handler') != 'database' && ($time % 2 || $session->isNew()))
1039			|| ($this->getCfg('session_handler') == 'database' && $session->isNew()))
1040		{
1041			$this->checkSession();
1042		}
1043
1044		return $session;
1045	}
1046
1047	/**
1048	 * Checks the user session.
1049	 *
1050	 * If the session record doesn't exist, initialise it.
1051	 * If session is new, create session variables
1052	 *
1053	 * @return  void
1054	 *
1055	 * @since   11.1
1056	 */
1057	public function checkSession()
1058	{
1059		$db = JFactory::getDBO();
1060		$session = JFactory::getSession();
1061		$user = JFactory::getUser();
1062
1063		$query = $db->getQuery(true);
1064		$query->select($query->qn('session_id'))
1065			->from($query->qn('#__session'))
1066			->where($query->qn('session_id') . ' = ' . $query->q($session->getId()));
1067
1068		$db->setQuery($query, 0, 1);
1069		$exists = $db->loadResult();
1070
1071		// If the session record doesn't exist initialise it.
1072		if (!$exists)
1073		{
1074			$query->clear();
1075			if ($session->isNew())
1076			{
1077				$query->insert($query->qn('#__session'))
1078					->columns($query->qn('session_id') . ', ' . $query->qn('client_id') . ', ' . $query->qn('time'))
1079					->values($query->q($session->getId()) . ', ' . (int) $this->getClientId() . ', ' . $query->q((int) time()));
1080				$db->setQuery($query);
1081			}
1082			else
1083			{
1084				$query->insert($query->qn('#__session'))
1085					->columns(
1086						$query->qn('session_id') . ', ' . $query->qn('client_id') . ', ' . $query->qn('guest') . ', ' .
1087						$query->qn('time') . ', ' . $query->qn('userid') . ', ' . $query->qn('username')
1088					)
1089					->values(
1090						$query->q($session->getId()) . ', ' . (int) $this->getClientId() . ', ' . (int) $user->get('guest') . ', ' .
1091						$query->q((int) $session->get('session.timer.start')) . ', ' . (int) $user->get('id') . ', ' . $query->q($user->get('username'))
1092					);
1093
1094				$db->setQuery($query);
1095			}
1096
1097			// If the insert failed, exit the application.
1098			if (!$db->execute())
1099			{
1100				jexit($db->getErrorMSG());
1101			}
1102
1103			// Session doesn't exist yet, so create session variables
1104			if ($session->isNew())
1105			{
1106				$session->set('registry', new JRegistry('session'));
1107				$session->set('user', new JUser);
1108			}
1109		}
1110	}
1111
1112	/**
1113	 * Gets the client id of the current running application.
1114	 *
1115	 * @return  integer  A client identifier.
1116	 *
1117	 * @since   11.1
1118	 */
1119	public function getClientId()
1120	{
1121		return $this->_clientId;
1122	}
1123
1124	/**
1125	 * Is admin interface?
1126	 *
1127	 * @return  boolean  True if this application is administrator.
1128	 *
1129	 * @since   11.1
1130	 */
1131	public function isAdmin()
1132	{
1133		return ($this->_clientId == 1);
1134	}
1135
1136	/**
1137	 * Is site interface?
1138	 *
1139	 * @return  boolean  True if this application is site.
1140	 *
1141	 * @since   11.1
1142	 */
1143	public function isSite()
1144	{
1145		return ($this->_clientId == 0);
1146	}
1147
1148	/**
1149	 * Method to determine if the host OS is  Windows
1150	 *
1151	 * @return  boolean  True if Windows OS
1152	 *
1153	 * @since   11.1
1154	 */
1155	public static function isWinOS()
1156	{
1157		return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
1158	}
1159
1160	/**
1161	 * Returns the response as a string.
1162	 *
1163	 * @return  string  The response
1164	 *
1165	 * @since   11.1
1166	 */
1167	public function __toString()
1168	{
1169		$compress = $this->getCfg('gzip', false);
1170
1171		return JResponse::toString($compress);
1172	}
1173}