Spade
Mini Shell
| Directory:~$ /home/lmsyaran/public_html/joomla4/ |
| [Home] [System Details] [Kill Me] |
AdministratorApplication.php000064400000031423151160044060012261
0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Application;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Input\Input;
use Joomla\Registry\Registry;
/**
* Joomla! Administrator Application class
*
* @since 3.2
*/
class AdministratorApplication extends CMSApplication
{
/**
* Class constructor.
*
* @param Input $input An optional argument to
provide dependency injection for the application's
* input object. If the
argument is a \JInput object that object will become
* the application's input
object, otherwise a default input object is created.
* @param Registry $config An optional argument to
provide dependency injection for the application's
* config object. If the
argument is a Registry object that object will become
* the application's config
object, otherwise a default config object is created.
* @param \JApplicationWebClient $client An optional argument to
provide dependency injection for the application's
* client object. If the
argument is a \JApplicationWebClient object that object will become
* the application's client
object, otherwise a default client object is created.
*
* @since 3.2
*/
public function __construct(Input $input = null, Registry $config = null,
\JApplicationWebClient $client = null)
{
// Register the application name
$this->_name = 'administrator';
// Register the client ID
$this->_clientId = 1;
// Execute the parent constructor
parent::__construct($input, $config, $client);
// Set the root in the URI based on the application name
\JUri::root(null, rtrim(dirname(\JUri::base(true)), '/\\'));
}
/**
* Dispatch the application
*
* @param string $component The component which is being rendered.
*
* @return void
*
* @since 3.2
*/
public function dispatch($component = null)
{
if ($component === null)
{
$component = \JAdministratorHelper::findOption();
}
// Load the document to the API
$this->loadDocument();
// Set up the params
$document = \JFactory::getDocument();
// Register the document object with \JFactory
\JFactory::$document = $document;
switch ($document->getType())
{
case 'html':
$document->setMetaData('keywords',
$this->get('MetaKeys'));
// Get the template
$template = $this->getTemplate(true);
// Store the template and its params to the config
$this->set('theme', $template->template);
$this->set('themeParams', $template->params);
break;
default:
break;
}
$document->setTitle($this->get('sitename') . ' -
' . \JText::_('JADMINISTRATION'));
$document->setDescription($this->get('MetaDesc'));
$document->setGenerator('Joomla! - Open Source Content
Management');
$contents = ComponentHelper::renderComponent($component);
$document->setBuffer($contents, 'component');
// Trigger the onAfterDispatch event.
\JPluginHelper::importPlugin('system');
$this->triggerEvent('onAfterDispatch');
}
/**
* Method to run the Web application routines.
*
* @return void
*
* @since 3.2
*/
protected function doExecute()
{
// Get the language from the (login) form or user state
$login_lang = ($this->input->get('option') ==
'com_login') ? $this->input->get('lang') :
'';
$options = array('language' => $login_lang ?:
$this->getUserState('application.lang'));
// Initialise the application
$this->initialiseApp($options);
// Test for magic quotes
if (PHP_VERSION_ID < 50400 && get_magic_quotes_gpc())
{
$lang = $this->getLanguage();
if ($lang->hasKey('JERROR_MAGIC_QUOTES'))
{
$this->enqueueMessage(\JText::_('JERROR_MAGIC_QUOTES'),
'error');
}
else
{
$this->enqueueMessage('Your host needs to disable
magic_quotes_gpc to run this version of Joomla!', 'error');
}
}
// Mark afterInitialise in the profiler.
JDEBUG ? $this->profiler->mark('afterInitialise') : null;
// Route the application
$this->route();
// Mark afterRoute in the profiler.
JDEBUG ? $this->profiler->mark('afterRoute') : null;
/*
* Check if the user is required to reset their password
*
* Before $this->route(); "option" and "view"
can't be safely read using:
* $this->input->getCmd('option'); or
$this->input->getCmd('view');
* ex: due of the sef urls
*/
$this->checkUserRequireReset('com_admin',
'profile', 'edit',
'com_admin/profile.save,com_admin/profile.apply,com_login/logout');
// Dispatch the application
$this->dispatch();
// Mark afterDispatch in the profiler.
JDEBUG ? $this->profiler->mark('afterDispatch') : null;
}
/**
* Return a reference to the \JRouter object.
*
* @param string $name The name of the application.
* @param array $options An optional associative array of
configuration settings.
*
* @return \JRouter
*
* @since 3.2
*/
public static function getRouter($name = 'administrator', array
$options = array())
{
return parent::getRouter($name, $options);
}
/**
* Gets the name of the current template.
*
* @param boolean $params True to return the template parameters
*
* @return string The name of the template.
*
* @since 3.2
* @throws \InvalidArgumentException
*/
public function getTemplate($params = false)
{
if (is_object($this->template))
{
if ($params)
{
return $this->template;
}
return $this->template->template;
}
$admin_style =
\JFactory::getUser()->getParam('admin_style');
// Load the template name from the database
$db = \JFactory::getDbo();
$query = $db->getQuery(true)
->select('template, s.params')
->from('#__template_styles as s')
->join('LEFT', '#__extensions as e ON e.type=' .
$db->quote('template') . ' AND e.element=s.template AND
e.client_id=s.client_id');
if ($admin_style)
{
$query->where('s.client_id = 1 AND id = ' . (int)
$admin_style . ' AND e.enabled = 1', 'OR');
}
$query->where('s.client_id = 1 AND home = ' .
$db->quote('1'), 'OR')
->order('home');
$db->setQuery($query);
$template = $db->loadObject();
$template->template =
\JFilterInput::getInstance()->clean($template->template,
'cmd');
$template->params = new Registry($template->params);
if (!file_exists(JPATH_THEMES . '/' . $template->template .
'/index.php'))
{
$this->enqueueMessage(\JText::_('JERROR_ALERTNOTEMPLATE'),
'error');
$template->params = new Registry;
$template->template = 'isis';
}
// Cache the result
$this->template = $template;
if (!file_exists(JPATH_THEMES . '/' . $template->template .
'/index.php'))
{
throw new
\InvalidArgumentException(\JText::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE',
$template->template));
}
if ($params)
{
return $template;
}
return $template->template;
}
/**
* Initialise the application.
*
* @param array $options An optional associative array of
configuration settings.
*
* @return void
*
* @since 3.2
*/
protected function initialiseApp($options = array())
{
$user = \JFactory::getUser();
// If the user is a guest we populate it with the guest user group.
if ($user->guest)
{
$guestUsergroup =
ComponentHelper::getParams('com_users')->get('guest_usergroup',
1);
$user->groups = array($guestUsergroup);
}
// If a language was specified it has priority, otherwise use user or
default language settings
if (empty($options['language']))
{
$lang = $user->getParam('admin_language');
// Make sure that the user's language exists
if ($lang && \JLanguageHelper::exists($lang))
{
$options['language'] = $lang;
}
else
{
$params = ComponentHelper::getParams('com_languages');
$options['language'] =
$params->get('administrator',
$this->get('language', 'en-GB'));
}
}
// One last check to make sure we have something
if (!\JLanguageHelper::exists($options['language']))
{
$lang = $this->get('language', 'en-GB');
if (\JLanguageHelper::exists($lang))
{
$options['language'] = $lang;
}
else
{
// As a last ditch fail to english
$options['language'] = 'en-GB';
}
}
// Finish initialisation
parent::initialiseApp($options);
}
/**
* Login authentication function
*
* @param array $credentials Array('username' => string,
'password' => string)
* @param array $options Array('remember' => boolean)
*
* @return boolean True on success.
*
* @since 3.2
*/
public function login($credentials, $options = array())
{
// The minimum group
$options['group'] = 'Public Backend';
// Make sure users are not auto-registered
$options['autoregister'] = false;
// Set the application login entry point
if (!array_key_exists('entry_url', $options))
{
$options['entry_url'] = \JUri::base() .
'index.php?option=com_users&task=login';
}
// Set the access control action to check.
$options['action'] = 'core.login.admin';
$result = parent::login($credentials, $options);
if (!($result instanceof \Exception))
{
$lang = $this->input->getCmd('lang');
$lang = preg_replace('/[^A-Z-]/i', '', $lang);
if ($lang)
{
$this->setUserState('application.lang', $lang);
}
static::purgeMessages();
}
return $result;
}
/**
* Purge the jos_messages table of old messages
*
* @return void
*
* @since 3.2
*/
public static function purgeMessages()
{
$user = \JFactory::getUser();
$userid = $user->get('id');
$db = \JFactory::getDbo();
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__messages_cfg'))
->where($db->quoteName('user_id') . ' = ' .
(int) $userid, 'AND')
->where($db->quoteName('cfg_name') . ' = ' .
$db->quote('auto_purge'), 'AND');
$db->setQuery($query);
$config = $db->loadObject();
// Check if auto_purge value set
if (is_object($config) && $config->cfg_name ===
'auto_purge')
{
$purge = $config->cfg_value;
}
else
{
// If no value set, default is 7 days
$purge = 7;
}
// If purge value is not 0, then allow purging of old messages
if ($purge > 0)
{
// Purge old messages at day set in message configuration
$past = \JFactory::getDate(time() - $purge * 86400);
$pastStamp = $past->toSql();
$query->clear()
->delete($db->quoteName('#__messages'))
->where($db->quoteName('date_time') . ' <
' . $db->quote($pastStamp), 'AND')
->where($db->quoteName('user_id_to') . ' = '
. (int) $userid, 'AND');
$db->setQuery($query);
$db->execute();
}
}
/**
* Rendering is the process of pushing the document buffers into the
template
* placeholders, retrieving data from the document and pushing it into
* the application response buffer.
*
* @return void
*
* @since 3.2
*/
protected function render()
{
// Get the \JInput object
$input = $this->input;
$component = $input->getCmd('option',
'com_login');
$file = $input->getCmd('tmpl', 'index');
if ($component === 'com_login')
{
$file = 'login';
}
$this->set('themeFile', $file . '.php');
// Safety check for when configuration.php root_user is in use.
$rootUser = $this->get('root_user');
if (property_exists('\JConfig', 'root_user'))
{
if (\JFactory::getUser()->get('username') === $rootUser ||
\JFactory::getUser()->id === (string) $rootUser)
{
$this->enqueueMessage(
\JText::sprintf(
'JWARNING_REMOVE_ROOT_USER',
'index.php?option=com_config&task=config.removeroot&'
. \JSession::getFormToken() . '=1'
),
'error'
);
}
// Show this message to superusers too
elseif (\JFactory::getUser()->authorise('core.admin'))
{
$this->enqueueMessage(
\JText::sprintf(
'JWARNING_REMOVE_ROOT_USER_ADMIN',
$rootUser,
'index.php?option=com_config&task=config.removeroot&'
. \JSession::getFormToken() . '=1'
),
'error'
);
}
}
parent::render();
}
/**
* Route the application.
*
* Routing is the process of examining the request environment to
determine which
* component should receive the request. The component optional parameters
* are then set in the request object to be processed when the application
is being
* dispatched.
*
* @return void
*
* @since 3.2
*/
protected function route()
{
$uri = \JUri::getInstance();
if ($this->get('force_ssl') >= 1 &&
strtolower($uri->getScheme()) !== 'https')
{
// Forward to https
$uri->setScheme('https');
$this->redirect((string) $uri, 301);
}
// Trigger the onAfterRoute event.
\JPluginHelper::importPlugin('system');
$this->triggerEvent('onAfterRoute');
}
}
ApplicationHelper.php000064400000014223151160044060010657 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Application;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\ComponentHelper;
/**
* Application helper functions
*
* @since 1.5
*/
class ApplicationHelper
{
/**
* Client information array
*
* @var array
* @since 1.6
*/
protected static $_clients = array();
/**
* Return the name of the request component [main component]
*
* @param string $default The default option
*
* @return string Option (e.g. com_something)
*
* @since 1.6
*/
public static function getComponentName($default = null)
{
static $option;
if ($option)
{
return $option;
}
$input = \JFactory::getApplication()->input;
$option = strtolower($input->get('option'));
if (empty($option))
{
$option = $default;
}
$input->set('option', $option);
return $option;
}
/**
* Provides a secure hash based on a seed
*
* @param string $seed Seed string.
*
* @return string A secure hash
*
* @since 3.2
*/
public static function getHash($seed)
{
return md5(\JFactory::getConfig()->get('secret') . $seed);
}
/**
* This method transliterates a string into a URL
* safe string or returns a URL safe UTF-8 string
* based on the global configuration
*
* @param string $string String to process
* @param string $language Language to transliterate to if unicode
slugs are disabled
*
* @return string Processed string
*
* @since 3.2
*/
public static function stringURLSafe($string, $language = '')
{
if (\JFactory::getConfig()->get('unicodeslugs') == 1)
{
$output = \JFilterOutput::stringURLUnicodeSlug($string);
}
else
{
if ($language === '*' || $language === '')
{
$languageParams =
ComponentHelper::getParams('com_languages');
$language = $languageParams->get('site');
}
$output = \JFilterOutput::stringURLSafe($string, $language);
}
return $output;
}
/**
* Gets information on a specific client id. This method will be useful
in
* future versions when we start mapping applications in the database.
*
* This method will return a client information array if called
* with no arguments which can be used to add custom application
information.
*
* @param integer $id A client identifier
* @param boolean $byName If True, find the client by its name
*
* @return mixed Object describing the client or false if not known
*
* @since 1.5
*/
public static function getClientInfo($id = null, $byName = false)
{
// Only create the array if it is empty
if (empty(self::$_clients))
{
$obj = new \stdClass;
// Site Client
$obj->id = 0;
$obj->name = 'site';
$obj->path = JPATH_SITE;
self::$_clients[0] = clone $obj;
// Administrator Client
$obj->id = 1;
$obj->name = 'administrator';
$obj->path = JPATH_ADMINISTRATOR;
self::$_clients[1] = clone $obj;
// Installation Client
$obj->id = 2;
$obj->name = 'installation';
$obj->path = JPATH_INSTALLATION;
self::$_clients[2] = clone $obj;
}
// If no client id has been passed return the whole array
if ($id === null)
{
return self::$_clients;
}
// Are we looking for client information by id or by name?
if (!$byName)
{
if (isset(self::$_clients[$id]))
{
return self::$_clients[$id];
}
}
else
{
foreach (self::$_clients as $client)
{
if ($client->name == strtolower($id))
{
return $client;
}
}
}
return;
}
/**
* Adds information for a client.
*
* @param mixed $client A client identifier either an array or object
*
* @return boolean True if the information is added. False on error
*
* @since 1.6
*/
public static function addClientInfo($client)
{
if (is_array($client))
{
$client = (object) $client;
}
if (!is_object($client))
{
return false;
}
$info = self::getClientInfo();
if (!isset($client->id))
{
$client->id = count($info);
}
self::$_clients[$client->id] = clone $client;
return true;
}
/**
* Parse a XML install manifest file.
*
* XML Root tag should be 'install' except for languages which
use meta file.
*
* @param string $path Full path to XML file.
*
* @return array XML metadata.
*
* @since 1.5
* @deprecated 4.0 Use \JInstaller::parseXMLInstallFile instead.
*/
public static function parseXMLInstallFile($path)
{
\JLog::add('ApplicationHelper::parseXMLInstallFile is deprecated.
Use \JInstaller::parseXMLInstallFile instead.', \JLog::WARNING,
'deprecated');
return \JInstaller::parseXMLInstallFile($path);
}
/**
* Parse a XML language meta file.
*
* XML Root tag for languages which is meta file.
*
* @param string $path Full path to XML file.
*
* @return array XML metadata.
*
* @since 1.5
* @deprecated 4.0 Use \JInstaller::parseXMLInstallFile instead.
*/
public static function parseXMLLangMetaFile($path)
{
\JLog::add('ApplicationHelper::parseXMLLangMetaFile is deprecated.
Use \JInstaller::parseXMLInstallFile instead.', \JLog::WARNING,
'deprecated');
// Check if meta file exists.
if (!file_exists($path))
{
return false;
}
// Read the file to see if it's a valid component XML file
$xml = simplexml_load_file($path);
if (!$xml)
{
return false;
}
/*
* Check for a valid XML root tag.
*
* Should be 'metafile'.
*/
if ($xml->getName() !== 'metafile')
{
unset($xml);
return false;
}
$data = array();
$data['name'] = (string) $xml->name;
$data['type'] = $xml->attributes()->type;
$data['creationDate'] = ((string) $xml->creationDate) ?:
\JText::_('JLIB_UNKNOWN');
$data['author'] = ((string) $xml->author) ?:
\JText::_('JLIB_UNKNOWN');
$data['copyright'] = (string) $xml->copyright;
$data['authorEmail'] = (string) $xml->authorEmail;
$data['authorUrl'] = (string) $xml->authorUrl;
$data['version'] = (string) $xml->version;
$data['description'] = (string) $xml->description;
$data['group'] = (string) $xml->group;
return $data;
}
}
BaseApplication.php000064400000011203151160044060010305 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Application;
defined('JPATH_PLATFORM') or die;
use Joomla\Application\AbstractApplication;
use Joomla\CMS\Input\Input;
use Joomla\Registry\Registry;
/**
* Joomla Platform Base Application Class
*
* @property-read \JInput $input The application input object
*
* @since 3.0.0
*/
abstract class BaseApplication extends AbstractApplication
{
/**
* The application dispatcher object.
*
* @var \JEventDispatcher
* @since 3.0.0
*/
protected $dispatcher;
/**
* The application identity object.
*
* @var \JUser
* @since 3.0.0
*/
protected $identity;
/**
* Class constructor.
*
* @param Input $input An optional argument to provide dependency
injection for the application's
* input object. If the argument is a \JInput
object that object will become
* the application's input object,
otherwise a default input object is created.
* @param Registry $config An optional argument to provide dependency
injection for the application's
* config object. If the argument is a
Registry object that object will become
* the application's config object,
otherwise a default config object is created.
*
* @since 3.0.0
*/
public function __construct(Input $input = null, Registry $config = null)
{
$this->input = $input instanceof Input ? $input : new Input;
$this->config = $config instanceof Registry ? $config : new Registry;
$this->initialise();
}
/**
* Get the application identity.
*
* @return mixed A \JUser object or null.
*
* @since 3.0.0
*/
public function getIdentity()
{
return $this->identity;
}
/**
* Registers a handler to a particular event group.
*
* @param string $event The event name.
* @param callable $handler The handler, a function or an instance of
an event object.
*
* @return BaseApplication The application to allow chaining.
*
* @since 3.0.0
*/
public function registerEvent($event, $handler)
{
if ($this->dispatcher instanceof \JEventDispatcher)
{
$this->dispatcher->register($event, $handler);
}
return $this;
}
/**
* Calls all handlers associated with an event group.
*
* @param string $event The event name.
* @param array $args An array of arguments (optional).
*
* @return array An array of results from each function call, or null
if no dispatcher is defined.
*
* @since 3.0.0
*/
public function triggerEvent($event, array $args = null)
{
if ($this->dispatcher instanceof \JEventDispatcher)
{
return $this->dispatcher->trigger($event, $args);
}
return;
}
/**
* Allows the application to load a custom or default dispatcher.
*
* The logic and options for creating this object are adequately generic
for default cases
* but for many applications it will make sense to override this method
and create event
* dispatchers, if required, based on more specific needs.
*
* @param \JEventDispatcher $dispatcher An optional dispatcher object.
If omitted, the factory dispatcher is created.
*
* @return BaseApplication This method is chainable.
*
* @since 3.0.0
*/
public function loadDispatcher(\JEventDispatcher $dispatcher = null)
{
$this->dispatcher = ($dispatcher === null) ?
\JEventDispatcher::getInstance() : $dispatcher;
return $this;
}
/**
* Allows the application to load a custom or default identity.
*
* The logic and options for creating this object are adequately generic
for default cases
* but for many applications it will make sense to override this method
and create an identity,
* if required, based on more specific needs.
*
* @param \JUser $identity An optional identity object. If omitted,
the factory user is created.
*
* @return BaseApplication This method is chainable.
*
* @since 3.0.0
*/
public function loadIdentity(\JUser $identity = null)
{
$this->identity = ($identity === null) ? \JFactory::getUser() :
$identity;
return $this;
}
/**
* Method to run the application routines. Most likely you will want to
instantiate a controller
* and execute it, or perform some sort of task directly.
*
* @return void
*
* @since 3.4 (CMS)
* @deprecated 4.0 The default concrete implementation of doExecute()
will be removed, subclasses will need to provide their own implementation.
*/
protected function doExecute()
{
return;
}
}
CliApplication.php000064400000016461151160044060010155 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Application;
defined('JPATH_PLATFORM') or die;
use Joomla\Application\Cli\CliOutput;
use Joomla\CMS\Input\Cli;
use Joomla\CMS\Input\Input;
use Joomla\Registry\Registry;
/**
* Base class for a Joomla! command line application.
*
* @since 2.5.0
* @note As of 4.0 this class will be abstract
*/
class CliApplication extends BaseApplication
{
/**
* @var CliOutput The output type.
* @since 3.3
*/
protected $output;
/**
* @var CliApplication The application instance.
* @since 1.7.0
*/
protected static $instance;
/**
* Class constructor.
*
* @param Cli $input An optional argument to
provide dependency injection for the application's
* input object. If the argument
is a \JInputCli object that object will become
* the application's input
object, otherwise a default input object is created.
* @param Registry $config An optional argument to
provide dependency injection for the application's
* config object. If the
argument is a Registry object that object will become
* the application's config
object, otherwise a default config object is created.
* @param \JEventDispatcher $dispatcher An optional argument to
provide dependency injection for the application's
* event dispatcher. If the
argument is a \JEventDispatcher object that object will become
* the application's event
dispatcher, if it is null then the default event dispatcher
* will be created based on the
application's loadDispatcher() method.
*
* @see BaseApplication::loadDispatcher()
* @since 1.7.0
*/
public function __construct(Cli $input = null, Registry $config = null,
\JEventDispatcher $dispatcher = null)
{
// Close the application if we are not executed from the command line.
if (!defined('STDOUT') || !defined('STDIN') ||
!isset($_SERVER['argv']))
{
$this->close();
}
// If an input object is given use it.
if ($input instanceof Input)
{
$this->input = $input;
}
// Create the input based on the application logic.
else
{
if (class_exists('\\Joomla\\CMS\\Input\\Cli'))
{
$this->input = new Cli;
}
}
// If a config object is given use it.
if ($config instanceof Registry)
{
$this->config = $config;
}
// Instantiate a new configuration object.
else
{
$this->config = new Registry;
}
$this->loadDispatcher($dispatcher);
// Load the configuration object.
$this->loadConfiguration($this->fetchConfigurationData());
// Set the execution datetime and timestamp;
$this->set('execution.datetime', gmdate('Y-m-d
H:i:s'));
$this->set('execution.timestamp', time());
// Set the current directory.
$this->set('cwd', getcwd());
}
/**
* Returns a reference to the global CliApplication object, only creating
it if it doesn't already exist.
*
* This method must be invoked as: $cli = CliApplication::getInstance();
*
* @param string $name The name (optional) of the JApplicationCli
class to instantiate.
*
* @return CliApplication
*
* @since 1.7.0
*/
public static function getInstance($name = null)
{
// Only create the object if it doesn't exist.
if (empty(self::$instance))
{
if (class_exists($name) && (is_subclass_of($name,
'\\Joomla\\CMS\\Application\\CliApplication')))
{
self::$instance = new $name;
}
else
{
self::$instance = new CliApplication;
}
}
return self::$instance;
}
/**
* Execute the application.
*
* @return void
*
* @since 1.7.0
*/
public function execute()
{
// Trigger the onBeforeExecute event.
$this->triggerEvent('onBeforeExecute');
// Perform application routines.
$this->doExecute();
// Trigger the onAfterExecute event.
$this->triggerEvent('onAfterExecute');
}
/**
* Load an object or array into the application configuration object.
*
* @param mixed $data Either an array or object to be loaded into the
configuration object.
*
* @return CliApplication Instance of $this to allow chaining.
*
* @since 1.7.0
*/
public function loadConfiguration($data)
{
// Load the data into the configuration object.
if (is_array($data))
{
$this->config->loadArray($data);
}
elseif (is_object($data))
{
$this->config->loadObject($data);
}
return $this;
}
/**
* Write a string to standard output.
*
* @param string $text The text to display.
* @param boolean $nl True (default) to append a new line at the end
of the output string.
*
* @return CliApplication Instance of $this to allow chaining.
*
* @codeCoverageIgnore
* @since 1.7.0
*/
public function out($text = '', $nl = true)
{
$output = $this->getOutput();
$output->out($text, $nl);
return $this;
}
/**
* Get an output object.
*
* @return CliOutput
*
* @since 3.3
*/
public function getOutput()
{
if (!$this->output)
{
// In 4.0, this will convert to throwing an exception and you will
expected to
// initialize this in the constructor. Until then set a default.
$default = new \Joomla\Application\Cli\Output\Xml;
$this->setOutput($default);
}
return $this->output;
}
/**
* Set an output object.
*
* @param CliOutput $output CliOutput object
*
* @return CliApplication Instance of $this to allow chaining.
*
* @since 3.3
*/
public function setOutput(CliOutput $output)
{
$this->output = $output;
return $this;
}
/**
* Get a value from standard input.
*
* @return string The input string from standard input.
*
* @codeCoverageIgnore
* @since 1.7.0
*/
public function in()
{
return rtrim(fread(STDIN, 8192), "\n");
}
/**
* Method to load a PHP configuration class file based on convention and
return the instantiated data object. You
* will extend this method in child classes to provide configuration data
from whatever data source is relevant
* for your specific application.
*
* @param string $file The path and filename of the configuration
file. If not provided, configuration.php
* in JPATH_CONFIGURATION will be used.
* @param string $class The class name to instantiate.
*
* @return mixed Either an array or object to be loaded into the
configuration object.
*
* @since 1.7.0
*/
protected function fetchConfigurationData($file = '', $class =
'\JConfig')
{
// Instantiate variables.
$config = array();
if (empty($file))
{
$file = JPATH_CONFIGURATION . '/configuration.php';
// Applications can choose not to have any configuration data by not
implementing this method and not having a config file.
if (!file_exists($file))
{
$file = '';
}
}
if (!empty($file))
{
\JLoader::register($class, $file);
if (class_exists($class))
{
$config = new $class;
}
else
{
throw new \RuntimeException('Configuration class does not
exist.');
}
}
return $config;
}
}
CMSApplication.php000064400000075052151160044060010071 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Application;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Input\Input;
use Joomla\CMS\Session\MetadataManager;
use Joomla\Registry\Registry;
use Joomla\String\StringHelper;
/**
* Joomla! CMS Application class
*
* @since 3.2
*/
class CMSApplication extends WebApplication
{
/**
* Array of options for the \JDocument object
*
* @var array
* @since 3.2
*/
protected $docOptions = array();
/**
* Application instances container.
*
* @var CMSApplication[]
* @since 3.2
*/
protected static $instances = array();
/**
* The scope of the application.
*
* @var string
* @since 3.2
*/
public $scope = null;
/**
* The client identifier.
*
* @var integer
* @since 3.2
* @deprecated 4.0 Will be renamed $clientId
*/
protected $_clientId = null;
/**
* The application message queue.
*
* @var array
* @since 3.2
* @deprecated 4.0 Will be renamed $messageQueue
*/
protected $_messageQueue = array();
/**
* The name of the application.
*
* @var array
* @since 3.2
* @deprecated 4.0 Will be renamed $name
*/
protected $_name = null;
/**
* The profiler instance
*
* @var \JProfiler
* @since 3.2
*/
protected $profiler = null;
/**
* Currently active template
*
* @var object
* @since 3.2
*/
protected $template = null;
/**
* Class constructor.
*
* @param Input $input An optional argument to
provide dependency injection for the application's
* input object. If the
argument is a \JInput object that object will become
* the application's input
object, otherwise a default input object is created.
* @param Registry $config An optional argument to
provide dependency injection for the application's
* config object. If the
argument is a Registry object that object will become
* the application's config
object, otherwise a default config object is created.
* @param \JApplicationWebClient $client An optional argument to
provide dependency injection for the application's
* client object. If the
argument is a \JApplicationWebClient object that object will become
* the application's client
object, otherwise a default client object is created.
*
* @since 3.2
*/
public function __construct(Input $input = null, Registry $config = null,
\JApplicationWebClient $client = null)
{
parent::__construct($input, $config, $client);
// Load and set the dispatcher
$this->loadDispatcher();
// If JDEBUG is defined, load the profiler instance
if (defined('JDEBUG') && JDEBUG)
{
$this->profiler = \JProfiler::getInstance('Application');
}
// Enable sessions by default.
if ($this->config->get('session') === null)
{
$this->config->set('session', true);
}
// Set the session default name.
if ($this->config->get('session_name') === null)
{
$this->config->set('session_name', $this->getName());
}
// Create the session if a session name is passed.
if ($this->config->get('session') !== false)
{
$this->loadSession();
}
}
/**
* Checks the user session.
*
* If the session record doesn't exist, initialise it.
* If session is new, create session variables
*
* @return void
*
* @since 3.2
* @throws \RuntimeException
*/
public function checkSession()
{
$metadataManager = new MetadataManager($this, \JFactory::getDbo());
$metadataManager->createRecordIfNonExisting(\JFactory::getSession(),
\JFactory::getUser());
}
/**
* Enqueue a system message.
*
* @param string $msg The message to enqueue.
* @param string $type The message type. Default is message.
*
* @return void
*
* @since 3.2
*/
public function enqueueMessage($msg, $type = 'message')
{
// Don't add empty messages.
if (trim($msg) === '')
{
return;
}
// For empty queue, if messages exists in the session, enqueue them
first.
$messages = $this->getMessageQueue();
$message = array('message' => $msg, 'type' =>
strtolower($type));
if (!in_array($message, $this->_messageQueue))
{
// Enqueue the message.
$this->_messageQueue[] = $message;
}
}
/**
* Execute the application.
*
* @return void
*
* @since 3.2
*/
public function execute()
{
// Perform application routines.
$this->doExecute();
// If we have an application document object, render it.
if ($this->document instanceof \JDocument)
{
// Render the application output.
$this->render();
}
// If gzip compression is enabled in configuration and the server is
compliant, compress the output.
if ($this->get('gzip') &&
!ini_get('zlib.output_compression') &&
ini_get('output_handler') !== 'ob_gzhandler')
{
$this->compress();
// Trigger the onAfterCompress event.
$this->triggerEvent('onAfterCompress');
}
// Send the application response.
$this->respond();
// Trigger the onAfterRespond event.
$this->triggerEvent('onAfterRespond');
}
/**
* Check if the user is required to reset their password.
*
* If the user is required to reset their password will be redirected to
the page that manage the password reset.
*
* @param string $option The option that manage the password reset
* @param string $view The view that manage the password reset
* @param string $layout The layout of the view that manage the
password reset
* @param string $tasks Permitted tasks
*
* @return void
*/
protected function checkUserRequireReset($option, $view, $layout, $tasks)
{
if (\JFactory::getUser()->get('requireReset', 0))
{
$redirect = false;
/*
* By default user profile edit page is used.
* That page allows you to change more than just the password and might
not be the desired behavior.
* This allows a developer to override the page that manage the password
reset.
* (can be configured using the file: configuration.php, or if extended,
through the global configuration form)
*/
$name = $this->getName();
if ($this->get($name . '_reset_password_override', 0))
{
$option = $this->get($name . '_reset_password_option',
'');
$view = $this->get($name . '_reset_password_view',
'');
$layout = $this->get($name . '_reset_password_layout',
'');
$tasks = $this->get($name . '_reset_password_tasks',
'');
}
$task = $this->input->getCmd('task', '');
// Check task or option/view/layout
if (!empty($task))
{
$tasks = explode(',', $tasks);
// Check full task version "option/task"
if (array_search($this->input->getCmd('option',
'') . '/' . $task, $tasks) === false)
{
// Check short task version, must be on the same option of the view
if ($this->input->getCmd('option', '') !==
$option || array_search($task, $tasks) === false)
{
// Not permitted task
$redirect = true;
}
}
}
else
{
if ($this->input->getCmd('option', '') !==
$option || $this->input->getCmd('view', '') !==
$view
|| $this->input->getCmd('layout', '') !==
$layout)
{
// Requested a different option/view/layout
$redirect = true;
}
}
if ($redirect)
{
// Redirect to the profile edit page
$this->enqueueMessage(\JText::_('JGLOBAL_PASSWORD_RESET_REQUIRED'),
'notice');
$this->redirect(\JRoute::_('index.php?option=' . $option .
'&view=' . $view . '&layout=' . $layout,
false));
}
}
}
/**
* Gets a configuration value.
*
* @param string $varname The name of the value to get.
* @param string $default Default value to return
*
* @return mixed The user state.
*
* @since 3.2
* @deprecated 4.0 Use get() instead
*/
public function getCfg($varname, $default = null)
{
return $this->get($varname, $default);
}
/**
* Gets the client id of the current running application.
*
* @return integer A client identifier.
*
* @since 3.2
*/
public function getClientId()
{
return $this->_clientId;
}
/**
* Returns a reference to the global CMSApplication object, only creating
it if it doesn't already exist.
*
* This method must be invoked as: $web = CMSApplication::getInstance();
*
* @param string $name The name (optional) of the CMSApplication class
to instantiate.
*
* @return CMSApplication
*
* @since 3.2
* @throws \RuntimeException
*/
public static function getInstance($name = null)
{
if (empty(static::$instances[$name]))
{
// Create a CMSApplication object.
$classname = '\JApplication' . ucfirst($name);
if (!class_exists($classname))
{
throw new
\RuntimeException(\JText::sprintf('JLIB_APPLICATION_ERROR_APPLICATION_LOAD',
$name), 500);
}
static::$instances[$name] = new $classname;
}
return static::$instances[$name];
}
/**
* Returns the application \JMenu object.
*
* @param string $name The name of the application/client.
* @param array $options An optional associative array of
configuration settings.
*
* @return \JMenu|null
*
* @since 3.2
*/
public function getMenu($name = null, $options = array())
{
if (!isset($name))
{
$name = $this->getName();
}
// Inject this application object into the \JMenu tree if one isn't
already specified
if (!isset($options['app']))
{
$options['app'] = $this;
}
try
{
$menu = \JMenu::getInstance($name, $options);
}
catch (\Exception $e)
{
return;
}
return $menu;
}
/**
* Get the system message queue.
*
* @param boolean $clear Clear the messages currently attached to the
application object
*
* @return array The system message queue.
*
* @since 3.2
*/
public function getMessageQueue($clear = false)
{
// For empty queue, if messages exists in the session, enqueue them.
if (!$this->_messageQueue)
{
$session = \JFactory::getSession();
$sessionQueue = $session->get('application.queue',
array());
if ($sessionQueue)
{
$this->_messageQueue = $sessionQueue;
$session->set('application.queue', array());
}
}
$messageQueue = $this->_messageQueue;
if ($clear)
{
$this->_messageQueue = array();
}
return $messageQueue;
}
/**
* Gets the name of the current running application.
*
* @return string The name of the application.
*
* @since 3.2
*/
public function getName()
{
return $this->_name;
}
/**
* Returns the application \JPathway object.
*
* @param string $name The name of the application.
* @param array $options An optional associative array of
configuration settings.
*
* @return \JPathway|null
*
* @since 3.2
*/
public function getPathway($name = null, $options = array())
{
if (!isset($name))
{
$name = $this->getName();
}
else
{
// Name should not be used
$this->getLogger()->warning(
'Name attribute is deprecated, in the future fetch the pathway
'
. 'through the respective application.',
array('category' => 'deprecated')
);
}
try
{
$pathway = \JPathway::getInstance($name, $options);
}
catch (\Exception $e)
{
return;
}
return $pathway;
}
/**
* Returns the application \JRouter object.
*
* @param string $name The name of the application.
* @param array $options An optional associative array of
configuration settings.
*
* @return \JRouter|null
*
* @since 3.2
*/
public static function getRouter($name = null, array $options = array())
{
if (!isset($name))
{
$app = \JFactory::getApplication();
$name = $app->getName();
}
$options['mode'] =
\JFactory::getConfig()->get('sef');
try
{
$router = \JRouter::getInstance($name, $options);
}
catch (\Exception $e)
{
return;
}
return $router;
}
/**
* Gets the name of the current template.
*
* @param boolean $params An optional associative array of
configuration settings
*
* @return mixed System is the fallback.
*
* @since 3.2
*/
public function getTemplate($params = false)
{
$template = new \stdClass;
$template->template = 'system';
$template->params = new Registry;
if ($params)
{
return $template;
}
return $template->template;
}
/**
* Gets a user state.
*
* @param string $key The path of the state.
* @param mixed $default Optional default value, returned if the
internal value is null.
*
* @return mixed The user state or null.
*
* @since 3.2
*/
public function getUserState($key, $default = null)
{
$session = \JFactory::getSession();
$registry = $session->get('registry');
if ($registry !== null)
{
return $registry->get($key, $default);
}
return $default;
}
/**
* Gets the value of a user state variable.
*
* @param string $key The key of the user state variable.
* @param string $request The name of the variable passed in a
request.
* @param string $default The default value for the variable if not
found. Optional.
* @param string $type Filter for the variable, for valid values
see {@link \JFilterInput::clean()}. Optional.
*
* @return mixed The request user state.
*
* @since 3.2
*/
public function getUserStateFromRequest($key, $request, $default = null,
$type = 'none')
{
$cur_state = $this->getUserState($key, $default);
$new_state = $this->input->get($request, null, $type);
if ($new_state === null)
{
return $cur_state;
}
// Save the new value only if it was set in this request.
$this->setUserState($key, $new_state);
return $new_state;
}
/**
* Initialise the application.
*
* @param array $options An optional associative array of
configuration settings.
*
* @return void
*
* @since 3.2
*/
protected function initialiseApp($options = array())
{
// Set the configuration in the API.
$this->config = \JFactory::getConfig();
// Check that we were given a language in the array (since by default may
be blank).
if (isset($options['language']))
{
$this->set('language', $options['language']);
}
// Build our language object
$lang = \JLanguage::getInstance($this->get('language'),
$this->get('debug_lang'));
// Load the language to the API
$this->loadLanguage($lang);
// Register the language object with \JFactory
\JFactory::$language = $this->getLanguage();
// Load the library language files
$this->loadLibraryLanguage();
// Set user specific editor.
$user = \JFactory::getUser();
$editor = $user->getParam('editor',
$this->get('editor'));
if (!\JPluginHelper::isEnabled('editors', $editor))
{
$editor = $this->get('editor');
if (!\JPluginHelper::isEnabled('editors', $editor))
{
$editor = 'none';
}
}
$this->set('editor', $editor);
// Trigger the onAfterInitialise event.
\JPluginHelper::importPlugin('system');
$this->triggerEvent('onAfterInitialise');
}
/**
* Is admin interface?
*
* @return boolean True if this application is administrator.
*
* @since 3.2
* @deprecated 4.0 Use isClient('administrator') instead.
*/
public function isAdmin()
{
return $this->isClient('administrator');
}
/**
* Is site interface?
*
* @return boolean True if this application is site.
*
* @since 3.2
* @deprecated 4.0 Use isClient('site') instead.
*/
public function isSite()
{
return $this->isClient('site');
}
/**
* Checks if HTTPS is forced in the client configuration.
*
* @param integer $clientId An optional client id (defaults to current
application client).
*
* @return boolean True if is forced for the client, false otherwise.
*
* @since 3.7.3
*/
public function isHttpsForced($clientId = null)
{
$clientId = (int) ($clientId !== null ? $clientId :
$this->getClientId());
$forceSsl = (int) $this->get('force_ssl');
if ($clientId === 0 && $forceSsl === 2)
{
return true;
}
if ($clientId === 1 && $forceSsl >= 1)
{
return true;
}
return false;
}
/**
* Check the client interface by name.
*
* @param string $identifier String identifier for the application
interface
*
* @return boolean True if this application is of the given type client
interface.
*
* @since 3.7.0
*/
public function isClient($identifier)
{
return $this->getName() === $identifier;
}
/**
* Load the library language files for the application
*
* @return void
*
* @since 3.6.3
*/
protected function loadLibraryLanguage()
{
$this->getLanguage()->load('lib_joomla',
JPATH_ADMINISTRATOR);
}
/**
* Allows the application to load a custom or default session.
*
* The logic and options for creating this object are adequately generic
for default cases
* but for many applications it will make sense to override this method
and create a session,
* if required, based on more specific needs.
*
* @param \JSession $session An optional session object. If omitted,
the session is created.
*
* @return CMSApplication This method is chainable.
*
* @since 3.2
*/
public function loadSession(\JSession $session = null)
{
if ($session !== null)
{
$this->session = $session;
return $this;
}
$this->registerEvent('onAfterSessionStart', array($this,
'afterSessionStart'));
/*
* Note: The below code CANNOT change from instantiating a session via
\JFactory until there is a proper dependency injection container supported
* by the application. The current default behaviours result in this
method being called each time an application class is instantiated.
* https://github.com/joomla/joomla-cms/issues/12108 explains why things
will crash and burn if you ever attempt to make this change
* without a proper dependency injection container.
*/
$session = \JFactory::getSession(
array(
'name' =>
\JApplicationHelper::getHash($this->get('session_name',
get_class($this))),
'expire' => $this->get('lifetime') ?
$this->get('lifetime') * 60 : 900,
'force_ssl' => $this->isHttpsForced(),
)
);
$session->initialise($this->input, $this->dispatcher);
// Get the session handler from the configuration.
$handler = $this->get('session_handler', 'none');
/*
* Check for extra session metadata when:
*
* 1) The database handler is in use and the session is new
* 2) The database handler is not in use and the time is an even numbered
second or the session is new
*/
if (($handler !== 'database' && (time() % 2 ||
$session->isNew())) || ($handler === 'database' &&
$session->isNew()))
{
$this->checkSession();
}
// Set the session object.
$this->session = $session;
return $this;
}
/**
* Login authentication function.
*
* Username and encoded password are passed the onUserLogin event which
* is responsible for the user validation. A successful validation updates
* the current session record with the user's details.
*
* Username and encoded password are sent as credentials (along with other
* possibilities) to each observer (authentication plugin) for user
* validation. Successful validation will update the current session with
* the user details.
*
* @param array $credentials Array('username' => string,
'password' => string)
* @param array $options Array('remember' => boolean)
*
* @return boolean|\JException True on success, false if failed or
silent handling is configured, or a \JException object on authentication
error.
*
* @since 3.2
*/
public function login($credentials, $options = array())
{
// Get the global \JAuthentication object.
$authenticate = \JAuthentication::getInstance();
$response = $authenticate->authenticate($credentials, $options);
// Import the user plugin group.
\JPluginHelper::importPlugin('user');
if ($response->status === \JAuthentication::STATUS_SUCCESS)
{
/*
* Validate that the user should be able to login (different to being
authenticated).
* This permits authentication plugins blocking the user.
*/
$authorisations = $authenticate->authorise($response, $options);
$denied_states = \JAuthentication::STATUS_EXPIRED |
\JAuthentication::STATUS_DENIED;
foreach ($authorisations as $authorisation)
{
if ((int) $authorisation->status & $denied_states)
{
// Trigger onUserAuthorisationFailure Event.
$this->triggerEvent('onUserAuthorisationFailure',
array((array) $authorisation));
// If silent is set, just return false.
if (isset($options['silent']) &&
$options['silent'])
{
return false;
}
// Return the error.
switch ($authorisation->status)
{
case \JAuthentication::STATUS_EXPIRED:
return \JError::raiseWarning('102002',
\JText::_('JLIB_LOGIN_EXPIRED'));
case \JAuthentication::STATUS_DENIED:
return \JError::raiseWarning('102003',
\JText::_('JLIB_LOGIN_DENIED'));
default:
return \JError::raiseWarning('102004',
\JText::_('JLIB_LOGIN_AUTHORISATION'));
}
}
}
// OK, the credentials are authenticated and user is authorised.
Let's fire the onLogin event.
$results = $this->triggerEvent('onUserLogin', array((array)
$response, $options));
/*
* If any of the user plugins did not successfully complete the login
routine
* then the whole method fails.
*
* Any errors raised should be done in the plugin as this provides the
ability
* to provide much more information about why the routine may have
failed.
*/
$user = \JFactory::getUser();
if ($response->type === 'Cookie')
{
$user->set('cookieLogin', true);
}
if (in_array(false, $results, true) == false)
{
$options['user'] = $user;
$options['responseType'] = $response->type;
// The user is successfully logged in. Run the after login events
$this->triggerEvent('onUserAfterLogin', array($options));
return true;
}
}
// Trigger onUserLoginFailure Event.
$this->triggerEvent('onUserLoginFailure', array((array)
$response));
// If silent is set, just return false.
if (isset($options['silent']) &&
$options['silent'])
{
return false;
}
// If status is success, any error will have been raised by the user
plugin
if ($response->status !== \JAuthentication::STATUS_SUCCESS)
{
$this->getLogger()->warning($response->error_message,
array('category' => 'jerror'));
}
return false;
}
/**
* Logout authentication function.
*
* Passed the current user information to the onUserLogout event and
reverts the current
* session record back to 'anonymous' parameters.
* If any of the authentication plugins did not successfully complete
* the logout routine then the whole method fails. Any errors raised
* should be done in the plugin as this provides the ability to give
* much more information about why the routine may have failed.
*
* @param integer $userid The user to load - Can be an integer or
string - If string, it is converted to ID automatically
* @param array $options Array('clientid' => array of
client id's)
*
* @return boolean True on success
*
* @since 3.2
*/
public function logout($userid = null, $options = array())
{
// Get a user object from the \JApplication.
$user = \JFactory::getUser($userid);
// Build the credentials array.
$parameters['username'] = $user->get('username');
$parameters['id'] = $user->get('id');
// Set clientid in the options array if it hasn't been set already
and shared sessions are not enabled.
if (!$this->get('shared_session', '0') &&
!isset($options['clientid']))
{
$options['clientid'] = $this->getClientId();
}
// Import the user plugin group.
\JPluginHelper::importPlugin('user');
// OK, the credentials are built. Lets fire the onLogout event.
$results = $this->triggerEvent('onUserLogout',
array($parameters, $options));
// Check if any of the plugins failed. If none did, success.
if (!in_array(false, $results, true))
{
$options['username'] = $user->get('username');
$this->triggerEvent('onUserAfterLogout', array($options));
return true;
}
// Trigger onUserLoginFailure Event.
$this->triggerEvent('onUserLogoutFailure',
array($parameters));
return false;
}
/**
* Redirect to another URL.
*
* If the headers have not been sent the redirect will be accomplished
using a "301 Moved Permanently"
* or "303 See Other" code in the header pointing to the new
location. If the headers have already been
* sent this will be accomplished using a JavaScript statement.
*
* @param string $url The URL to redirect to. Can only be
http/https URL
* @param integer $status The HTTP 1.1 status code to be provided. 303
is assumed by default.
*
* @return void
*
* @since 3.2
*/
public function redirect($url, $status = 303)
{
// Handle B/C by checking if a message was passed to the method, will be
removed at 4.0
if (func_num_args() > 1)
{
$args = func_get_args();
/*
* Do some checks on the $args array, values below correspond to legacy
redirect() method
*
* $args[0] = $url
* $args[1] = Message to enqueue
* $args[2] = Message type
* $args[3] = $status (previously moved)
*/
if (isset($args[1]) && !empty($args[1]) &&
(!is_bool($args[1]) && !is_int($args[1])))
{
$this->getLogger()->warning(
'Passing a message and message type to ' . __METHOD__ .
'() is deprecated. '
. 'Please set your message via ' . __CLASS__ .
'::enqueueMessage() prior to calling ' . __CLASS__
. '::redirect().',
array('category' => 'deprecated')
);
$message = $args[1];
// Set the message type if present
if (isset($args[2]) && !empty($args[2]))
{
$type = $args[2];
}
else
{
$type = 'message';
}
// Enqueue the message
$this->enqueueMessage($message, $type);
// Reset the $moved variable
$status = isset($args[3]) ? (boolean) $args[3] : false;
}
}
// Persist messages if they exist.
if ($this->_messageQueue)
{
$session = \JFactory::getSession();
$session->set('application.queue',
$this->_messageQueue);
}
// Hand over processing to the parent now
parent::redirect($url, $status);
}
/**
* Rendering is the process of pushing the document buffers into the
template
* placeholders, retrieving data from the document and pushing it into
* the application response buffer.
*
* @return void
*
* @since 3.2
*/
protected function render()
{
// Setup the document options.
$this->docOptions['template'] =
$this->get('theme');
$this->docOptions['file'] =
$this->get('themeFile', 'index.php');
$this->docOptions['params'] =
$this->get('themeParams');
if ($this->get('themes.base'))
{
$this->docOptions['directory'] =
$this->get('themes.base');
}
// Fall back to constants.
else
{
$this->docOptions['directory'] =
defined('JPATH_THEMES') ? JPATH_THEMES :
(defined('JPATH_BASE') ? JPATH_BASE : __DIR__) .
'/themes';
}
// Parse the document.
$this->document->parse($this->docOptions);
// Trigger the onBeforeRender event.
\JPluginHelper::importPlugin('system');
$this->triggerEvent('onBeforeRender');
$caching = false;
if ($this->isClient('site') &&
$this->get('caching') &&
$this->get('caching', 2) == 2 &&
!\JFactory::getUser()->get('id'))
{
$caching = true;
}
// Render the document.
$data = $this->document->render($caching, $this->docOptions);
// Set the application output data.
$this->setBody($data);
// Trigger the onAfterRender event.
$this->triggerEvent('onAfterRender');
// Mark afterRender in the profiler.
JDEBUG ? $this->profiler->mark('afterRender') : null;
}
/**
* Route the application.
*
* Routing is the process of examining the request environment to
determine which
* component should receive the request. The component optional parameters
* are then set in the request object to be processed when the application
is being
* dispatched.
*
* @return void
*
* @since 3.2
*/
protected function route()
{
// Get the full request URI.
$uri = clone \JUri::getInstance();
$router = static::getRouter();
$result = $router->parse($uri);
$active = $this->getMenu()->getActive();
if ($active !== null
&& $active->type === 'alias'
&& $active->params->get('alias_redirect')
&& in_array($this->input->getMethod(),
array('GET', 'HEAD'), true))
{
$item =
$this->getMenu()->getItem($active->params->get('aliasoptions'));
if ($item !== null)
{
$oldUri = clone \JUri::getInstance();
if ($oldUri->getVar('Itemid') == $active->id)
{
$oldUri->setVar('Itemid', $item->id);
}
$base = \JUri::base(true);
$oldPath = StringHelper::strtolower(substr($oldUri->getPath(),
strlen($base) + 1));
$activePathPrefix = StringHelper::strtolower($active->route);
$position = strpos($oldPath, $activePathPrefix);
if ($position !== false)
{
$oldUri->setPath($base . '/' . substr_replace($oldPath,
$item->route, $position, strlen($activePathPrefix)));
$this->setHeader('Expires', 'Wed, 17 Aug 2005
00:00:00 GMT', true);
$this->setHeader('Last-Modified', gmdate('D, d M Y
H:i:s') . ' GMT', true);
$this->setHeader('Cache-Control', 'no-store,
no-cache, must-revalidate, post-check=0, pre-check=0', false);
$this->setHeader('Pragma', 'no-cache');
$this->sendHeaders();
$this->redirect((string) $oldUri, 301);
}
}
}
foreach ($result as $key => $value)
{
$this->input->def($key, $value);
}
// Trigger the onAfterRoute event.
\JPluginHelper::importPlugin('system');
$this->triggerEvent('onAfterRoute');
}
/**
* Sets the value of a user state variable.
*
* @param string $key The path of the state.
* @param mixed $value The value of the variable.
*
* @return mixed The previous state, if one existed.
*
* @since 3.2
*/
public function setUserState($key, $value)
{
$session = \JFactory::getSession();
$registry = $session->get('registry');
if ($registry !== null)
{
return $registry->set($key, $value);
}
return;
}
/**
* Sends all headers prior to returning the string
*
* @param boolean $compress If true, compress the data
*
* @return string
*
* @since 3.2
*/
public function toString($compress = false)
{
// Don't compress something if the server is going to do it anyway.
Waste of time.
if ($compress && !ini_get('zlib.output_compression')
&& ini_get('output_handler') !==
'ob_gzhandler')
{
$this->compress();
}
if ($this->allowCache() === false)
{
$this->setHeader('Cache-Control', 'no-cache',
false);
// HTTP 1.0
$this->setHeader('Pragma', 'no-cache');
}
$this->sendHeaders();
return $this->getBody();
}
}
DaemonApplication.php000064400000061030151160044060010641 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Application;
defined('JPATH_PLATFORM') or die;
jimport('joomla.filesystem.folder');
use Joomla\Registry\Registry;
/**
* Class to turn CliApplication applications into daemons. It requires CLI
and PCNTL support built into PHP.
*
* @link https://www.php.net/manual/en/book.pcntl.php
* @link https://www.php.net/manual/en/features.commandline.php
* @since 1.7.0
*/
class DaemonApplication extends CliApplication
{
/**
* @var array The available POSIX signals to be caught by default.
* @link https://www.php.net/manual/pcntl.constants.php
* @since 1.7.0
*/
protected static $signals = array(
'SIGHUP',
'SIGINT',
'SIGQUIT',
'SIGILL',
'SIGTRAP',
'SIGABRT',
'SIGIOT',
'SIGBUS',
'SIGFPE',
'SIGUSR1',
'SIGSEGV',
'SIGUSR2',
'SIGPIPE',
'SIGALRM',
'SIGTERM',
'SIGSTKFLT',
'SIGCLD',
'SIGCHLD',
'SIGCONT',
'SIGTSTP',
'SIGTTIN',
'SIGTTOU',
'SIGURG',
'SIGXCPU',
'SIGXFSZ',
'SIGVTALRM',
'SIGPROF',
'SIGWINCH',
'SIGPOLL',
'SIGIO',
'SIGPWR',
'SIGSYS',
'SIGBABY',
'SIG_BLOCK',
'SIG_UNBLOCK',
'SIG_SETMASK',
);
/**
* @var boolean True if the daemon is in the process of exiting.
* @since 1.7.0
*/
protected $exiting = false;
/**
* @var integer The parent process id.
* @since 3.0.0
*/
protected $parentId = 0;
/**
* @var integer The process id of the daemon.
* @since 1.7.0
*/
protected $processId = 0;
/**
* @var boolean True if the daemon is currently running.
* @since 1.7.0
*/
protected $running = false;
/**
* Class constructor.
*
* @param \JInputCli $input An optional argument to
provide dependency injection for the application's
* input object. If the argument
is a \JInputCli object that object will become
* the application's input
object, otherwise a default input object is created.
* @param Registry $config An optional argument to
provide dependency injection for the application's
* config object. If the argument
is a Registry object that object will become
* the application's config
object, otherwise a default config object is created.
* @param \JEventDispatcher $dispatcher An optional argument to
provide dependency injection for the application's
* event dispatcher. If the
argument is a \JEventDispatcher object that object will become
* the application's event
dispatcher, if it is null then the default event dispatcher
* will be created based on the
application's loadDispatcher() method.
*
* @since 1.7.0
* @throws \RuntimeException
*/
public function __construct(\JInputCli $input = null, Registry $config =
null, \JEventDispatcher $dispatcher = null)
{
// Verify that the process control extension for PHP is available.
if (!defined('SIGHUP'))
{
\JLog::add('The PCNTL extension for PHP is not available.',
\JLog::ERROR);
throw new \RuntimeException('The PCNTL extension for PHP is not
available.');
}
// Verify that POSIX support for PHP is available.
if (!function_exists('posix_getpid'))
{
\JLog::add('The POSIX extension for PHP is not available.',
\JLog::ERROR);
throw new \RuntimeException('The POSIX extension for PHP is not
available.');
}
// Call the parent constructor.
parent::__construct($input, $config, $dispatcher);
// Set some system limits.
@set_time_limit($this->config->get('max_execution_time',
0));
if ($this->config->get('max_memory_limit') !== null)
{
ini_set('memory_limit',
$this->config->get('max_memory_limit', '256M'));
}
// Flush content immediately.
ob_implicit_flush();
}
/**
* Method to handle POSIX signals.
*
* @param integer $signal The received POSIX signal.
*
* @return void
*
* @since 1.7.0
* @see pcntl_signal()
* @throws \RuntimeException
*/
public static function signal($signal)
{
// Log all signals sent to the daemon.
\JLog::add('Received signal: ' . $signal, \JLog::DEBUG);
// Let's make sure we have an application instance.
if (!is_subclass_of(static::$instance, 'CliApplication'))
{
\JLog::add('Cannot find the application instance.',
\JLog::EMERGENCY);
throw new \RuntimeException('Cannot find the application
instance.');
}
// Fire the onReceiveSignal event.
static::$instance->triggerEvent('onReceiveSignal',
array($signal));
switch ($signal)
{
case SIGINT:
case SIGTERM:
// Handle shutdown tasks
if (static::$instance->running &&
static::$instance->isActive())
{
static::$instance->shutdown();
}
else
{
static::$instance->close();
}
break;
case SIGHUP:
// Handle restart tasks
if (static::$instance->running &&
static::$instance->isActive())
{
static::$instance->shutdown(true);
}
else
{
static::$instance->close();
}
break;
case SIGCHLD:
// A child process has died
while (static::$instance->pcntlWait($signal, WNOHANG || WUNTRACED)
> 0)
{
usleep(1000);
}
break;
case SIGCLD:
while (static::$instance->pcntlWait($signal, WNOHANG) > 0)
{
$signal = static::$instance->pcntlChildExitStatus($signal);
}
break;
default:
break;
}
}
/**
* Check to see if the daemon is active. This does not assume that $this
daemon is active, but
* only if an instance of the application is active as a daemon.
*
* @return boolean True if daemon is active.
*
* @since 1.7.0
*/
public function isActive()
{
// Get the process id file location for the application.
$pidFile = $this->config->get('application_pid_file');
// If the process id file doesn't exist then the daemon is obviously
not running.
if (!is_file($pidFile))
{
return false;
}
// Read the contents of the process id file as an integer.
$fp = fopen($pidFile, 'r');
$pid = fread($fp, filesize($pidFile));
$pid = (int) $pid;
fclose($fp);
// Check to make sure that the process id exists as a positive integer.
if (!$pid)
{
return false;
}
// Check to make sure the process is active by pinging it and ensure it
responds.
if (!posix_kill($pid, 0))
{
// No response so remove the process id file and log the situation.
@ unlink($pidFile);
\JLog::add('The process found based on PID file was
unresponsive.', \JLog::WARNING);
return false;
}
return true;
}
/**
* Load an object or array into the application configuration object.
*
* @param mixed $data Either an array or object to be loaded into the
configuration object.
*
* @return DaemonApplication Instance of $this to allow chaining.
*
* @since 1.7.0
*/
public function loadConfiguration($data)
{
// Execute the parent load method.
parent::loadConfiguration($data);
/*
* Setup some application metadata options. This is useful if we ever
want to write out startup scripts
* or just have some sort of information available to share about things.
*/
// The application author name. This string is used in generating
startup scripts and has
// a maximum of 50 characters.
$tmp = (string) $this->config->get('author_name',
'Joomla Platform');
$this->config->set('author_name', (strlen($tmp) > 50)
? substr($tmp, 0, 50) : $tmp);
// The application author email. This string is used in generating
startup scripts.
$tmp = (string) $this->config->get('author_email',
'admin@joomla.org');
$this->config->set('author_email', filter_var($tmp,
FILTER_VALIDATE_EMAIL));
// The application name. This string is used in generating startup
scripts.
$tmp = (string) $this->config->get('application_name',
'DaemonApplication');
$this->config->set('application_name', (string)
preg_replace('/[^A-Z0-9_-]/i', '', $tmp));
// The application description. This string is used in generating
startup scripts.
$tmp = (string)
$this->config->get('application_description', 'A
generic Joomla Platform application.');
$this->config->set('application_description',
filter_var($tmp, FILTER_SANITIZE_STRING));
/*
* Setup the application path options. This defines the default
executable name, executable directory,
* and also the path to the daemon process id file.
*/
// The application executable daemon. This string is used in generating
startup scripts.
$tmp = (string)
$this->config->get('application_executable',
basename($this->input->executable));
$this->config->set('application_executable', $tmp);
// The home directory of the daemon.
$tmp = (string)
$this->config->get('application_directory',
dirname($this->input->executable));
$this->config->set('application_directory', $tmp);
// The pid file location. This defaults to a path inside the /tmp
directory.
$name = $this->config->get('application_name');
$tmp = (string)
$this->config->get('application_pid_file',
strtolower('/tmp/' . $name . '/' . $name .
'.pid'));
$this->config->set('application_pid_file', $tmp);
/*
* Setup the application identity options. It is important to remember
if the default of 0 is set for
* either UID or GID then changing that setting will not be attempted as
there is no real way to "change"
* the identity of a process from some user to root.
*/
// The user id under which to run the daemon.
$tmp = (int) $this->config->get('application_uid', 0);
$options = array('options' => array('min_range'
=> 0, 'max_range' => 65000));
$this->config->set('application_uid', filter_var($tmp,
FILTER_VALIDATE_INT, $options));
// The group id under which to run the daemon.
$tmp = (int) $this->config->get('application_gid', 0);
$options = array('options' => array('min_range'
=> 0, 'max_range' => 65000));
$this->config->set('application_gid', filter_var($tmp,
FILTER_VALIDATE_INT, $options));
// Option to kill the daemon if it cannot switch to the chosen identity.
$tmp = (bool)
$this->config->get('application_require_identity', 1);
$this->config->set('application_require_identity', $tmp);
/*
* Setup the application runtime options. By default our execution time
limit is infinite obviously
* because a daemon should be constantly running unless told otherwise.
The default limit for memory
* usage is 256M, which admittedly is a little high, but remember it is a
"limit" and PHP's memory
* management leaves a bit to be desired :-)
*/
// The maximum execution time of the application in seconds. Zero is
infinite.
$tmp = $this->config->get('max_execution_time');
if ($tmp !== null)
{
$this->config->set('max_execution_time', (int) $tmp);
}
// The maximum amount of memory the application can use.
$tmp = $this->config->get('max_memory_limit',
'256M');
if ($tmp !== null)
{
$this->config->set('max_memory_limit', (string) $tmp);
}
return $this;
}
/**
* Execute the daemon.
*
* @return void
*
* @since 1.7.0
*/
public function execute()
{
// Trigger the onBeforeExecute event.
$this->triggerEvent('onBeforeExecute');
// Enable basic garbage collection.
gc_enable();
\JLog::add('Starting ' . $this->name, \JLog::INFO);
// Set off the process for becoming a daemon.
if ($this->daemonize())
{
// Declare ticks to start signal monitoring. When you declare ticks,
PCNTL will monitor
// incoming signals after each tick and call the relevant signal handler
automatically.
declare (ticks = 1);
// Start the main execution loop.
while (true)
{
// Perform basic garbage collection.
$this->gc();
// Don't completely overload the CPU.
usleep(1000);
// Execute the main application logic.
$this->doExecute();
}
}
// We were not able to daemonize the application so log the failure and
die gracefully.
else
{
\JLog::add('Starting ' . $this->name . ' failed',
\JLog::INFO);
}
// Trigger the onAfterExecute event.
$this->triggerEvent('onAfterExecute');
}
/**
* Restart daemon process.
*
* @return void
*
* @since 1.7.0
*/
public function restart()
{
\JLog::add('Stopping ' . $this->name, \JLog::INFO);
$this->shutdown(true);
}
/**
* Stop daemon process.
*
* @return void
*
* @since 1.7.0
*/
public function stop()
{
\JLog::add('Stopping ' . $this->name, \JLog::INFO);
$this->shutdown();
}
/**
* Method to change the identity of the daemon process and resources.
*
* @return boolean True if identity successfully changed
*
* @since 1.7.0
* @see posix_setuid()
*/
protected function changeIdentity()
{
// Get the group and user ids to set for the daemon.
$uid = (int) $this->config->get('application_uid', 0);
$gid = (int) $this->config->get('application_gid', 0);
// Get the application process id file path.
$file = $this->config->get('application_pid_file');
// Change the user id for the process id file if necessary.
if ($uid && (fileowner($file) != $uid) && (!@
chown($file, $uid)))
{
\JLog::add('Unable to change user ownership of the process id
file.', \JLog::ERROR);
return false;
}
// Change the group id for the process id file if necessary.
if ($gid && (filegroup($file) != $gid) && (!@
chgrp($file, $gid)))
{
\JLog::add('Unable to change group ownership of the process id
file.', \JLog::ERROR);
return false;
}
// Set the correct home directory for the process.
if ($uid && ($info = posix_getpwuid($uid)) &&
is_dir($info['dir']))
{
system('export HOME="' . $info['dir'] .
'"');
}
// Change the user id for the process necessary.
if ($uid && (posix_getuid($file) != $uid) && (!@
posix_setuid($uid)))
{
\JLog::add('Unable to change user ownership of the proccess.',
\JLog::ERROR);
return false;
}
// Change the group id for the process necessary.
if ($gid && (posix_getgid($file) != $gid) && (!@
posix_setgid($gid)))
{
\JLog::add('Unable to change group ownership of the
proccess.', \JLog::ERROR);
return false;
}
// Get the user and group information based on uid and gid.
$user = posix_getpwuid($uid);
$group = posix_getgrgid($gid);
\JLog::add('Changed daemon identity to ' .
$user['name'] . ':' . $group['name'],
\JLog::INFO);
return true;
}
/**
* Method to put the application into the background.
*
* @return boolean
*
* @since 1.7.0
* @throws \RuntimeException
*/
protected function daemonize()
{
// Is there already an active daemon running?
if ($this->isActive())
{
\JLog::add($this->name . ' daemon is still running. Exiting the
application.', \JLog::EMERGENCY);
return false;
}
// Reset Process Information
$this->safeMode = !!@ ini_get('safe_mode');
$this->processId = 0;
$this->running = false;
// Detach process!
try
{
// Check if we should run in the foreground.
if (!$this->input->get('f'))
{
// Detach from the terminal.
$this->detach();
}
else
{
// Setup running values.
$this->exiting = false;
$this->running = true;
// Set the process id.
$this->processId = (int) posix_getpid();
$this->parentId = $this->processId;
}
}
catch (\RuntimeException $e)
{
\JLog::add('Unable to fork.', \JLog::EMERGENCY);
return false;
}
// Verify the process id is valid.
if ($this->processId < 1)
{
\JLog::add('The process id is invalid; the fork failed.',
\JLog::EMERGENCY);
return false;
}
// Clear the umask.
@ umask(0);
// Write out the process id file for concurrency management.
if (!$this->writeProcessIdFile())
{
\JLog::add('Unable to write the pid file at: ' .
$this->config->get('application_pid_file'),
\JLog::EMERGENCY);
return false;
}
// Attempt to change the identity of user running the process.
if (!$this->changeIdentity())
{
// If the identity change was required then we need to return false.
if ($this->config->get('application_require_identity'))
{
\JLog::add('Unable to change process owner.',
\JLog::CRITICAL);
return false;
}
else
{
\JLog::add('Unable to change process owner.',
\JLog::WARNING);
}
}
// Setup the signal handlers for the daemon.
if (!$this->setupSignalHandlers())
{
return false;
}
// Change the current working directory to the application working
directory.
@ chdir($this->config->get('application_directory'));
return true;
}
/**
* This is truly where the magic happens. This is where we fork the
process and kill the parent
* process, which is essentially what turns the application into a daemon.
*
* @return void
*
* @since 3.0.0
* @throws \RuntimeException
*/
protected function detach()
{
\JLog::add('Detaching the ' . $this->name . '
daemon.', \JLog::DEBUG);
// Attempt to fork the process.
$pid = $this->fork();
// If the pid is positive then we successfully forked, and can close this
application.
if ($pid)
{
// Add the log entry for debugging purposes and exit gracefully.
\JLog::add('Ending ' . $this->name . ' parent
process', \JLog::DEBUG);
$this->close();
}
// We are in the forked child process.
else
{
// Setup some protected values.
$this->exiting = false;
$this->running = true;
// Set the parent to self.
$this->parentId = $this->processId;
}
}
/**
* Method to fork the process.
*
* @return integer The child process id to the parent process, zero to
the child process.
*
* @since 1.7.0
* @throws \RuntimeException
*/
protected function fork()
{
// Attempt to fork the process.
$pid = $this->pcntlFork();
// If the fork failed, throw an exception.
if ($pid === -1)
{
throw new \RuntimeException('The process could not be
forked.');
}
// Update the process id for the child.
elseif ($pid === 0)
{
$this->processId = (int) posix_getpid();
}
// Log the fork in the parent.
else
{
// Log the fork.
\JLog::add('Process forked ' . $pid, \JLog::DEBUG);
}
// Trigger the onFork event.
$this->postFork();
return $pid;
}
/**
* Method to perform basic garbage collection and memory management in the
sense of clearing the
* stat cache. We will probably call this method pretty regularly in our
main loop.
*
* @return void
*
* @since 1.7.0
*/
protected function gc()
{
// Perform generic garbage collection.
gc_collect_cycles();
// Clear the stat cache so it doesn't blow up memory.
clearstatcache();
}
/**
* Method to attach the DaemonApplication signal handler to the known
signals. Applications
* can override these handlers by using the pcntl_signal() function and
attaching a different
* callback method.
*
* @return boolean
*
* @since 1.7.0
* @see pcntl_signal()
*/
protected function setupSignalHandlers()
{
// We add the error suppression for the loop because on some platforms
some constants are not defined.
foreach (self::$signals as $signal)
{
// Ignore signals that are not defined.
if (!defined($signal) || !is_int(constant($signal)) ||
(constant($signal) === 0))
{
// Define the signal to avoid notices.
\JLog::add('Signal "' . $signal . '" not
defined. Defining it as null.', \JLog::DEBUG);
define($signal, null);
// Don't listen for signal.
continue;
}
// Attach the signal handler for the signal.
if (!$this->pcntlSignal(constant($signal),
array('DaemonApplication', 'signal')))
{
\JLog::add(sprintf('Unable to reroute signal handler: %s',
$signal), \JLog::EMERGENCY);
return false;
}
}
return true;
}
/**
* Method to shut down the daemon and optionally restart it.
*
* @param boolean $restart True to restart the daemon on exit.
*
* @return void
*
* @since 1.7.0
*/
protected function shutdown($restart = false)
{
// If we are already exiting, chill.
if ($this->exiting)
{
return;
}
// If not, now we are.
else
{
$this->exiting = true;
}
// If we aren't already daemonized then just kill the application.
if (!$this->running && !$this->isActive())
{
\JLog::add('Process was not daemonized yet, just halting current
process', \JLog::INFO);
$this->close();
}
// Only read the pid for the parent file.
if ($this->parentId == $this->processId)
{
// Read the contents of the process id file as an integer.
$fp = fopen($this->config->get('application_pid_file'),
'r');
$pid = fread($fp,
filesize($this->config->get('application_pid_file')));
$pid = (int) $pid;
fclose($fp);
// Remove the process id file.
@ unlink($this->config->get('application_pid_file'));
// If we are supposed to restart the daemon we need to execute the same
command.
if ($restart)
{
$this->close(exec(implode(' ', $GLOBALS['argv'])
. ' > /dev/null &'));
}
// If we are not supposed to restart the daemon let's just kill -9.
else
{
passthru('kill -9 ' . $pid);
$this->close();
}
}
}
/**
* Method to write the process id file out to disk.
*
* @return boolean
*
* @since 1.7.0
*/
protected function writeProcessIdFile()
{
// Verify the process id is valid.
if ($this->processId < 1)
{
\JLog::add('The process id is invalid.', \JLog::EMERGENCY);
return false;
}
// Get the application process id file path.
$file = $this->config->get('application_pid_file');
if (empty($file))
{
\JLog::add('The process id file path is empty.',
\JLog::ERROR);
return false;
}
// Make sure that the folder where we are writing the process id file
exists.
$folder = dirname($file);
if (!is_dir($folder) && !\JFolder::create($folder))
{
\JLog::add('Unable to create directory: ' . $folder,
\JLog::ERROR);
return false;
}
// Write the process id file out to disk.
if (!file_put_contents($file, $this->processId))
{
\JLog::add('Unable to write proccess id file: ' . $file,
\JLog::ERROR);
return false;
}
// Make sure the permissions for the proccess id file are accurate.
if (!chmod($file, 0644))
{
\JLog::add('Unable to adjust permissions for the proccess id file:
' . $file, \JLog::ERROR);
return false;
}
return true;
}
/**
* Method to handle post-fork triggering of the onFork event.
*
* @return void
*
* @since 3.0.0
*/
protected function postFork()
{
// Trigger the onFork event.
$this->triggerEvent('onFork');
}
/**
* Method to return the exit code of a terminated child process.
*
* @param integer $status The status parameter is the status parameter
supplied to a successful call to pcntl_waitpid().
*
* @return integer The child process exit code.
*
* @see pcntl_wexitstatus()
* @since 1.7.3
*/
protected function pcntlChildExitStatus($status)
{
return pcntl_wexitstatus($status);
}
/**
* Method to return the exit code of a terminated child process.
*
* @return integer On success, the PID of the child process is returned
in the parent's thread
* of execution, and a 0 is returned in the child's
thread of execution. On
* failure, a -1 will be returned in the parent's
context, no child process
* will be created, and a PHP error is raised.
*
* @see pcntl_fork()
* @since 1.7.3
*/
protected function pcntlFork()
{
return pcntl_fork();
}
/**
* Method to install a signal handler.
*
* @param integer $signal The signal number.
* @param callable $handler The signal handler which may be the name
of a user created function,
* or method, or either of the two global
constants SIG_IGN or SIG_DFL.
* @param boolean $restart Specifies whether system call restarting
should be used when this
* signal arrives.
*
* @return boolean True on success.
*
* @see pcntl_signal()
* @since 1.7.3
*/
protected function pcntlSignal($signal, $handler, $restart = true)
{
return pcntl_signal($signal, $handler, $restart);
}
/**
* Method to wait on or return the status of a forked child.
*
* @param integer &$status Status information.
* @param integer $options If wait3 is available on your system
(mostly BSD-style systems),
* you can provide the optional options
parameter.
*
* @return integer The process ID of the child which exited, -1 on error
or zero if WNOHANG
* was provided as an option (on wait3-available
systems) and no child was available.
*
* @see pcntl_wait()
* @since 1.7.3
*/
protected function pcntlWait(&$status, $options = 0)
{
return pcntl_wait($status, $options);
}
}
SiteApplication.php000064400000052445151160044060010354 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Application;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Input\Input;
use Joomla\Registry\Registry;
/**
* Joomla! Site Application class
*
* @since 3.2
*/
final class SiteApplication extends CMSApplication
{
/**
* Option to filter by language
*
* @var boolean
* @since 3.2
* @deprecated 4.0 Will be renamed $language_filter
*/
protected $_language_filter = false;
/**
* Option to detect language by the browser
*
* @var boolean
* @since 3.2
* @deprecated 4.0 Will be renamed $detect_browser
*/
protected $_detect_browser = false;
/**
* Class constructor.
*
* @param Input $input An optional argument to
provide dependency injection for the application's
* input object. If the
argument is a \JInput object that object will become
* the application's input
object, otherwise a default input object is created.
* @param Registry $config An optional argument to
provide dependency injection for the application's
* config object. If the
argument is a Registry object that object will become
* the application's config
object, otherwise a default config object is created.
* @param \JApplicationWebClient $client An optional argument to
provide dependency injection for the application's
* client object. If the
argument is a \JApplicationWebClient object that object will become
* the application's client
object, otherwise a default client object is created.
*
* @since 3.2
*/
public function __construct(Input $input = null, Registry $config = null,
\JApplicationWebClient $client = null)
{
// Register the application name
$this->_name = 'site';
// Register the client ID
$this->_clientId = 0;
// Execute the parent constructor
parent::__construct($input, $config, $client);
}
/**
* Check if the user can access the application
*
* @param integer $itemid The item ID to check authorisation for
*
* @return void
*
* @since 3.2
*
* @throws \Exception When you are not authorised to view the home page
menu item
*/
protected function authorise($itemid)
{
$menus = $this->getMenu();
$user = \JFactory::getUser();
if (!$menus->authorise($itemid))
{
if ($user->get('id') == 0)
{
// Set the data
$this->setUserState('users.login.form.data',
array('return' => \JUri::getInstance()->toString()));
$url =
\JRoute::_('index.php?option=com_users&view=login', false);
$this->enqueueMessage(\JText::_('JGLOBAL_YOU_MUST_LOGIN_FIRST'),
'error');
$this->redirect($url);
}
else
{
// Get the home page menu item
$home_item =
$menus->getDefault($this->getLanguage()->getTag());
// If we are already in the homepage raise an exception
if ($menus->getActive()->id == $home_item->id)
{
throw new \Exception(\JText::_('JERROR_ALERTNOAUTHOR'),
403);
}
// Otherwise redirect to the homepage and show an error
$this->enqueueMessage(\JText::_('JERROR_ALERTNOAUTHOR'),
'error');
$this->redirect(\JRoute::_('index.php?Itemid=' .
$home_item->id, false));
}
}
}
/**
* Dispatch the application
*
* @param string $component The component which is being rendered.
*
* @return void
*
* @since 3.2
*/
public function dispatch($component = null)
{
// Get the component if not set.
if (!$component)
{
$component = $this->input->getCmd('option', null);
}
// Load the document to the API
$this->loadDocument();
// Set up the params
$document = $this->getDocument();
$router = static::getRouter();
$params = $this->getParams();
// Register the document object with \JFactory
\JFactory::$document = $document;
switch ($document->getType())
{
case 'html':
// Get language
$lang_code = $this->getLanguage()->getTag();
$languages = \JLanguageHelper::getLanguages('lang_code');
// Set metadata
if (isset($languages[$lang_code]) &&
$languages[$lang_code]->metakey)
{
$document->setMetaData('keywords',
$languages[$lang_code]->metakey);
}
else
{
$document->setMetaData('keywords',
$this->get('MetaKeys'));
}
$document->setMetaData('rights',
$this->get('MetaRights'));
if ($router->getMode() == JROUTER_MODE_SEF)
{
$document->setBase(htmlspecialchars(\JUri::current()));
}
// Get the template
$template = $this->getTemplate(true);
// Store the template and its params to the config
$this->set('theme', $template->template);
$this->set('themeParams', $template->params);
break;
case 'feed':
$document->setBase(htmlspecialchars(\JUri::current()));
break;
}
$document->setTitle($params->get('page_title'));
$document->setDescription($params->get('page_description'));
// Add version number or not based on global configuration
if ($this->get('MetaVersion', 0))
{
$document->setGenerator('Joomla! - Open Source Content
Management - Version ' . JVERSION);
}
else
{
$document->setGenerator('Joomla! - Open Source Content
Management');
}
$contents = ComponentHelper::renderComponent($component);
$document->setBuffer($contents, 'component');
// Trigger the onAfterDispatch event.
\JPluginHelper::importPlugin('system');
$this->triggerEvent('onAfterDispatch');
}
/**
* Method to run the Web application routines.
*
* @return void
*
* @since 3.2
*/
protected function doExecute()
{
// Initialise the application
$this->initialiseApp();
// Mark afterInitialise in the profiler.
JDEBUG ? $this->profiler->mark('afterInitialise') : null;
// Route the application
$this->route();
// Mark afterRoute in the profiler.
JDEBUG ? $this->profiler->mark('afterRoute') : null;
/*
* Check if the user is required to reset their password
*
* Before $this->route(); "option" and "view"
can't be safely read using:
* $this->input->getCmd('option'); or
$this->input->getCmd('view');
* ex: due of the sef urls
*/
$this->checkUserRequireReset('com_users',
'profile', 'edit',
'com_users/profile.save,com_users/profile.apply,com_users/user.logout');
// Dispatch the application
$this->dispatch();
// Mark afterDispatch in the profiler.
JDEBUG ? $this->profiler->mark('afterDispatch') : null;
}
/**
* Return the current state of the detect browser option.
*
* @return boolean
*
* @since 3.2
*/
public function getDetectBrowser()
{
return $this->_detect_browser;
}
/**
* Return the current state of the language filter.
*
* @return boolean
*
* @since 3.2
*/
public function getLanguageFilter()
{
return $this->_language_filter;
}
/**
* Return a reference to the \JMenu object.
*
* @param string $name The name of the application/client.
* @param array $options An optional associative array of
configuration settings.
*
* @return \JMenu \JMenu object.
*
* @since 3.2
*/
public function getMenu($name = 'site', $options = array())
{
return parent::getMenu($name, $options);
}
/**
* Get the application parameters
*
* @param string $option The component option
*
* @return Registry The parameters object
*
* @since 3.2
* @deprecated 4.0 Use getParams() instead
*/
public function getPageParameters($option = null)
{
return $this->getParams($option);
}
/**
* Get the application parameters
*
* @param string $option The component option
*
* @return Registry The parameters object
*
* @since 3.2
*/
public function getParams($option = null)
{
static $params = array();
$hash = '__default';
if (!empty($option))
{
$hash = $option;
}
if (!isset($params[$hash]))
{
// Get component parameters
if (!$option)
{
$option = $this->input->getCmd('option', null);
}
// Get new instance of component global parameters
$params[$hash] = clone ComponentHelper::getParams($option);
// Get menu parameters
$menus = $this->getMenu();
$menu = $menus->getActive();
// Get language
$lang_code = $this->getLanguage()->getTag();
$languages = \JLanguageHelper::getLanguages('lang_code');
$title = $this->get('sitename');
if (isset($languages[$lang_code]) &&
$languages[$lang_code]->metadesc)
{
$description = $languages[$lang_code]->metadesc;
}
else
{
$description = $this->get('MetaDesc');
}
$rights = $this->get('MetaRights');
$robots = $this->get('robots');
// Retrieve com_menu global settings
$temp = clone ComponentHelper::getParams('com_menus');
// Lets cascade the parameters if we have menu item parameters
if (is_object($menu))
{
// Get show_page_heading from com_menu global settings
$params[$hash]->def('show_page_heading',
$temp->get('show_page_heading'));
$params[$hash]->merge($menu->params);
$title = $menu->title;
}
else
{
// Merge com_menu global settings
$params[$hash]->merge($temp);
// If supplied, use page title
$title = $temp->get('page_title', $title);
}
$params[$hash]->def('page_title', $title);
$params[$hash]->def('page_description', $description);
$params[$hash]->def('page_rights', $rights);
$params[$hash]->def('robots', $robots);
}
return $params[$hash];
}
/**
* Return a reference to the \JPathway object.
*
* @param string $name The name of the application.
* @param array $options An optional associative array of
configuration settings.
*
* @return \JPathway A \JPathway object
*
* @since 3.2
*/
public function getPathway($name = 'site', $options = array())
{
return parent::getPathway($name, $options);
}
/**
* Return a reference to the \JRouter object.
*
* @param string $name The name of the application.
* @param array $options An optional associative array of
configuration settings.
*
* @return \JRouter
*
* @since 3.2
*/
public static function getRouter($name = 'site', array $options
= array())
{
return parent::getRouter($name, $options);
}
/**
* Gets the name of the current template.
*
* @param boolean $params True to return the template parameters
*
* @return string The name of the template.
*
* @since 3.2
* @throws \InvalidArgumentException
*/
public function getTemplate($params = false)
{
if (is_object($this->template))
{
if (!file_exists(JPATH_THEMES . '/' .
$this->template->template . '/index.php'))
{
throw new
\InvalidArgumentException(\JText::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE',
$this->template->template));
}
if ($params)
{
return $this->template;
}
return $this->template->template;
}
// Get the id of the active menu item
$menu = $this->getMenu();
$item = $menu->getActive();
if (!$item)
{
$item = $menu->getItem($this->input->getInt('Itemid',
null));
}
$id = 0;
if (is_object($item))
{
// Valid item retrieved
$id = $item->template_style_id;
}
$tid = $this->input->getUint('templateStyle', 0);
if (is_numeric($tid) && (int) $tid > 0)
{
$id = (int) $tid;
}
$cache = \JFactory::getCache('com_templates', '');
if ($this->_language_filter)
{
$tag = $this->getLanguage()->getTag();
}
else
{
$tag = '';
}
$cacheId = 'templates0' . $tag;
if ($cache->contains($cacheId))
{
$templates = $cache->get($cacheId);
}
else
{
// Load styles
$db = \JFactory::getDbo();
$query = $db->getQuery(true)
->select('id, home, template, s.params')
->from('#__template_styles as s')
->where('s.client_id = 0')
->where('e.enabled = 1')
->join('LEFT', '#__extensions as e ON
e.element=s.template AND e.type=' .
$db->quote('template') . ' AND
e.client_id=s.client_id');
$db->setQuery($query);
$templates = $db->loadObjectList('id');
foreach ($templates as &$template)
{
// Create home element
if ($template->home == 1 && !isset($template_home) ||
$this->_language_filter && $template->home == $tag)
{
$template_home = clone $template;
}
$template->params = new Registry($template->params);
}
// Unset the $template reference to the last $templates[n] item cycled
in the foreach above to avoid editing it later
unset($template);
// Add home element, after loop to avoid double execution
if (isset($template_home))
{
$template_home->params = new Registry($template_home->params);
$templates[0] = $template_home;
}
$cache->store($templates, $cacheId);
}
if (isset($templates[$id]))
{
$template = $templates[$id];
}
else
{
$template = $templates[0];
}
// Allows for overriding the active template from the request
$template_override = $this->input->getCmd('template',
'');
// Only set template override if it is a valid template (= it exists and
is enabled)
if (!empty($template_override))
{
if (file_exists(JPATH_THEMES . '/' . $template_override .
'/index.php'))
{
foreach ($templates as $tmpl)
{
if ($tmpl->template === $template_override)
{
$template = $tmpl;
break;
}
}
}
}
// Need to filter the default value as well
$template->template =
\JFilterInput::getInstance()->clean($template->template,
'cmd');
// Fallback template
if (!file_exists(JPATH_THEMES . '/' . $template->template .
'/index.php'))
{
$this->enqueueMessage(\JText::_('JERROR_ALERTNOTEMPLATE'),
'error');
// Try to find data for 'beez3' template
$original_tmpl = $template->template;
foreach ($templates as $tmpl)
{
if ($tmpl->template === 'beez3')
{
$template = $tmpl;
break;
}
}
// Check, the data were found and if template really exists
if (!file_exists(JPATH_THEMES . '/' . $template->template .
'/index.php'))
{
throw new
\InvalidArgumentException(\JText::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE',
$original_tmpl));
}
}
// Cache the result
$this->template = $template;
if ($params)
{
return $template;
}
return $template->template;
}
/**
* Initialise the application.
*
* @param array $options An optional associative array of
configuration settings.
*
* @return void
*
* @since 3.2
*/
protected function initialiseApp($options = array())
{
$user = \JFactory::getUser();
// If the user is a guest we populate it with the guest user group.
if ($user->guest)
{
$guestUsergroup =
ComponentHelper::getParams('com_users')->get('guest_usergroup',
1);
$user->groups = array($guestUsergroup);
}
/*
* If a language was specified it has priority, otherwise use user or
default language settings
* Check this only if the languagefilter plugin is enabled
*
* @TODO - Remove the hardcoded dependency to the languagefilter plugin
*/
if (\JPluginHelper::isEnabled('system',
'languagefilter'))
{
$plugin = \JPluginHelper::getPlugin('system',
'languagefilter');
$pluginParams = new Registry($plugin->params);
$this->setLanguageFilter(true);
$this->setDetectBrowser($pluginParams->get('detect_browser',
'1') == '1');
}
if (empty($options['language']))
{
// Detect the specified language
$lang = $this->input->getString('language', null);
// Make sure that the user's language exists
if ($lang && \JLanguageHelper::exists($lang))
{
$options['language'] = $lang;
}
}
if (empty($options['language']) &&
$this->getLanguageFilter())
{
// Detect cookie language
$lang =
$this->input->cookie->get(md5($this->get('secret') .
'language'), null, 'string');
// Make sure that the user's language exists
if ($lang && \JLanguageHelper::exists($lang))
{
$options['language'] = $lang;
}
}
if (empty($options['language']))
{
// Detect user language
$lang = $user->getParam('language');
// Make sure that the user's language exists
if ($lang && \JLanguageHelper::exists($lang))
{
$options['language'] = $lang;
}
}
if (empty($options['language']) &&
$this->getDetectBrowser())
{
// Detect browser language
$lang = \JLanguageHelper::detectLanguage();
// Make sure that the user's language exists
if ($lang && \JLanguageHelper::exists($lang))
{
$options['language'] = $lang;
}
}
if (empty($options['language']))
{
// Detect default language
$params = ComponentHelper::getParams('com_languages');
$options['language'] = $params->get('site',
$this->get('language', 'en-GB'));
}
// One last check to make sure we have something
if (!\JLanguageHelper::exists($options['language']))
{
$lang = $this->config->get('language',
'en-GB');
if (\JLanguageHelper::exists($lang))
{
$options['language'] = $lang;
}
else
{
// As a last ditch fail to english
$options['language'] = 'en-GB';
}
}
// Finish initialisation
parent::initialiseApp($options);
}
/**
* Load the library language files for the application
*
* @return void
*
* @since 3.6.3
*/
protected function loadLibraryLanguage()
{
/*
* Try the lib_joomla file in the current language (without allowing the
loading of the file in the default language)
* Fallback to the default language if necessary
*/
$this->getLanguage()->load('lib_joomla', JPATH_SITE,
null, false, true)
|| $this->getLanguage()->load('lib_joomla',
JPATH_ADMINISTRATOR, null, false, true);
}
/**
* Login authentication function
*
* @param array $credentials Array('username' => string,
'password' => string)
* @param array $options Array('remember' => boolean)
*
* @return boolean True on success.
*
* @since 3.2
*/
public function login($credentials, $options = array())
{
// Set the application login entry point
if (!array_key_exists('entry_url', $options))
{
$options['entry_url'] = \JUri::base() .
'index.php?option=com_users&task=user.login';
}
// Set the access control action to check.
$options['action'] = 'core.login.site';
return parent::login($credentials, $options);
}
/**
* Rendering is the process of pushing the document buffers into the
template
* placeholders, retrieving data from the document and pushing it into
* the application response buffer.
*
* @return void
*
* @since 3.2
*/
protected function render()
{
switch ($this->document->getType())
{
case 'feed':
// No special processing for feeds
break;
case 'html':
default:
$template = $this->getTemplate(true);
$file = $this->input->get('tmpl',
'index');
if ($file === 'offline' &&
!$this->get('offline'))
{
$this->set('themeFile', 'index.php');
}
if ($this->get('offline') &&
!\JFactory::getUser()->authorise('core.login.offline'))
{
$this->setUserState('users.login.form.data',
array('return' => \JUri::getInstance()->toString()));
$this->set('themeFile', 'offline.php');
$this->setHeader('Status', '503 Service Temporarily
Unavailable', 'true');
}
if (!is_dir(JPATH_THEMES . '/' . $template->template)
&& !$this->get('offline'))
{
$this->set('themeFile', 'component.php');
}
// Ensure themeFile is set by now
if ($this->get('themeFile') == '')
{
$this->set('themeFile', $file . '.php');
}
break;
}
parent::render();
}
/**
* Route the application.
*
* Routing is the process of examining the request environment to
determine which
* component should receive the request. The component optional parameters
* are then set in the request object to be processed when the application
is being
* dispatched.
*
* @return void
*
* @since 3.2
*/
protected function route()
{
// Execute the parent method
parent::route();
$Itemid = $this->input->getInt('Itemid', null);
$this->authorise($Itemid);
}
/**
* Set the current state of the detect browser option.
*
* @param boolean $state The new state of the detect browser option
*
* @return boolean The previous state
*
* @since 3.2
*/
public function setDetectBrowser($state = false)
{
$old = $this->_detect_browser;
$this->_detect_browser = $state;
return $old;
}
/**
* Set the current state of the language filter.
*
* @param boolean $state The new state of the language filter
*
* @return boolean The previous state
*
* @since 3.2
*/
public function setLanguageFilter($state = false)
{
$old = $this->_language_filter;
$this->_language_filter = $state;
return $old;
}
/**
* Overrides the default template that would be used
*
* @param string $template The template name
* @param mixed $styleParams The template style parameters
*
* @return void
*
* @since 3.2
*/
public function setTemplate($template, $styleParams = null)
{
if (is_dir(JPATH_THEMES . '/' . $template))
{
$this->template = new \stdClass;
$this->template->template = $template;
if ($styleParams instanceof Registry)
{
$this->template->params = $styleParams;
}
else
{
$this->template->params = new Registry($styleParams);
}
// Store the template and its params to the config
$this->set('theme', $this->template->template);
$this->set('themeParams', $this->template->params);
}
}
}
WebApplication.php000064400000112477151160044060010167 0ustar00<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Application;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Input\Input;
use Joomla\Registry\Registry;
use Joomla\String\StringHelper;
/**
* Base class for a Joomla! Web application.
*
* @since 2.5.0
* @note As of 4.0 this class will be abstract
*/
class WebApplication extends BaseApplication
{
/**
* @var string Character encoding string.
* @since 1.7.3
*/
public $charSet = 'utf-8';
/**
* @var string Response mime type.
* @since 1.7.3
*/
public $mimeType = 'text/html';
/**
* @var \JDate The body modified date for response headers.
* @since 1.7.3
*/
public $modifiedDate;
/**
* @var \JApplicationWebClient The application client object.
* @since 1.7.3
*/
public $client;
/**
* @var \JDocument The application document object.
* @since 1.7.3
*/
protected $document;
/**
* @var \JLanguage The application language object.
* @since 1.7.3
*/
protected $language;
/**
* @var \JSession The application session object.
* @since 1.7.3
*/
protected $session;
/**
* @var object The application response object.
* @since 1.7.3
*/
protected $response;
/**
* @var WebApplication The application instance.
* @since 1.7.3
*/
protected static $instance;
/**
* A map of integer HTTP 1.1 response codes to the full HTTP Status for
the headers.
*
* @var object
* @since 3.4
* @link http://tools.ietf.org/pdf/rfc7231.pdf
*/
private $responseMap = array(
100 => 'HTTP/1.1 100 Continue',
101 => 'HTTP/1.1 101 Switching Protocols',
102 => 'HTTP/1.1 102 Processing',
200 => 'HTTP/1.1 200 OK',
201 => 'HTTP/1.1 201 Created',
202 => 'HTTP/1.1 202 Accepted',
203 => 'HTTP/1.1 203 Non-Authoritative Information',
204 => 'HTTP/1.1 204 No Content',
205 => 'HTTP/1.1 205 Reset Content',
206 => 'HTTP/1.1 206 Partial Content',
207 => 'HTTP/1.1 207 Multi-Status',
208 => 'HTTP/1.1 208 Already Reported',
226 => 'HTTP/1.1 226 IM Used',
300 => 'HTTP/1.1 300 Multiple Choices',
301 => 'HTTP/1.1 301 Moved Permanently',
302 => 'HTTP/1.1 302 Found',
303 => 'HTTP/1.1 303 See other',
304 => 'HTTP/1.1 304 Not Modified',
305 => 'HTTP/1.1 305 Use Proxy',
306 => 'HTTP/1.1 306 (Unused)',
307 => 'HTTP/1.1 307 Temporary Redirect',
308 => 'HTTP/1.1 308 Permanent Redirect',
400 => 'HTTP/1.1 400 Bad Request',
401 => 'HTTP/1.1 401 Unauthorized',
402 => 'HTTP/1.1 402 Payment Required',
403 => 'HTTP/1.1 403 Forbidden',
404 => 'HTTP/1.1 404 Not Found',
405 => 'HTTP/1.1 405 Method Not Allowed',
406 => 'HTTP/1.1 406 Not Acceptable',
407 => 'HTTP/1.1 407 Proxy Authentication Required',
408 => 'HTTP/1.1 408 Request Timeout',
409 => 'HTTP/1.1 409 Conflict',
410 => 'HTTP/1.1 410 Gone',
411 => 'HTTP/1.1 411 Length Required',
412 => 'HTTP/1.1 412 Precondition Failed',
413 => 'HTTP/1.1 413 Payload Too Large',
414 => 'HTTP/1.1 414 URI Too Long',
415 => 'HTTP/1.1 415 Unsupported Media Type',
416 => 'HTTP/1.1 416 Range Not Satisfiable',
417 => 'HTTP/1.1 417 Expectation Failed',
418 => 'HTTP/1.1 418 I\'m a teapot',
421 => 'HTTP/1.1 421 Misdirected Request',
422 => 'HTTP/1.1 422 Unprocessable Entity',
423 => 'HTTP/1.1 423 Locked',
424 => 'HTTP/1.1 424 Failed Dependency',
426 => 'HTTP/1.1 426 Upgrade Required',
428 => 'HTTP/1.1 428 Precondition Required',
429 => 'HTTP/1.1 429 Too Many Requests',
431 => 'HTTP/1.1 431 Request Header Fields Too Large',
451 => 'HTTP/1.1 451 Unavailable For Legal Reasons',
500 => 'HTTP/1.1 500 Internal Server Error',
501 => 'HTTP/1.1 501 Not Implemented',
502 => 'HTTP/1.1 502 Bad Gateway',
503 => 'HTTP/1.1 503 Service Unavailable',
504 => 'HTTP/1.1 504 Gateway Timeout',
505 => 'HTTP/1.1 505 HTTP Version Not Supported',
506 => 'HTTP/1.1 506 Variant Also Negotiates',
507 => 'HTTP/1.1 507 Insufficient Storage',
508 => 'HTTP/1.1 508 Loop Detected',
510 => 'HTTP/1.1 510 Not Extended',
511 => 'HTTP/1.1 511 Network Authentication Required',
);
/**
* A map of HTTP Response headers which may only send a single value, all
others
* are considered to allow multiple
*
* @var object
* @since 3.5.2
* @link https://tools.ietf.org/html/rfc7230
*/
private $singleValueResponseHeaders = array(
'status', // This is not a valid header name, but the
representation used by Joomla to identify the HTTP Response Code
'content-length',
'host',
'content-type',
'content-location',
'date',
'location',
'retry-after',
'server',
'mime-version',
'last-modified',
'etag',
'accept-ranges',
'content-range',
'age',
'expires',
'clear-site-data',
'pragma',
'strict-transport-security',
'content-security-policy',
'content-security-policy-report-only',
'x-frame-options',
'x-xss-protection',
'x-content-type-options',
'referrer-policy',
'expect-ct',
'feature-policy', // @deprecated - see:
https://scotthelme.co.uk/goodbye-feature-policy-and-hello-permissions-policy/
'permissions-policy',
);
/**
* Class constructor.
*
* @param Input $input An optional argument to
provide dependency injection for the application's
* input object. If the
argument is a \JInput object that object will become
* the application's input
object, otherwise a default input object is created.
* @param Registry $config An optional argument to
provide dependency injection for the application's
* config object. If the
argument is a Registry object that object will become
* the application's config
object, otherwise a default config object is created.
* @param \JApplicationWebClient $client An optional argument to
provide dependency injection for the application's
* client object. If the
argument is a \JApplicationWebClient object that object will become
* the application's client
object, otherwise a default client object is created.
*
* @since 1.7.3
*/
public function __construct(Input $input = null, Registry $config = null,
\JApplicationWebClient $client = null)
{
// If an input object is given use it.
if ($input instanceof Input)
{
$this->input = $input;
}
// Create the input based on the application logic.
else
{
$this->input = new Input;
}
// If a config object is given use it.
if ($config instanceof Registry)
{
$this->config = $config;
}
// Instantiate a new configuration object.
else
{
$this->config = new Registry;
}
// If a client object is given use it.
if ($client instanceof \JApplicationWebClient)
{
$this->client = $client;
}
// Instantiate a new web client object.
else
{
$this->client = new \JApplicationWebClient;
}
// Load the configuration object.
$this->loadConfiguration($this->fetchConfigurationData());
// Set the execution datetime and timestamp;
$this->set('execution.datetime', gmdate('Y-m-d
H:i:s'));
$this->set('execution.timestamp', time());
// Setup the response object.
$this->response = new \stdClass;
$this->response->cachable = false;
$this->response->headers = array();
$this->response->body = array();
// Set the system URIs.
$this->loadSystemUris();
}
/**
* Returns a reference to the global WebApplication object, only creating
it if it doesn't already exist.
*
* This method must be invoked as: $web = WebApplication::getInstance();
*
* @param string $name The name (optional) of the JApplicationWeb
class to instantiate.
*
* @return WebApplication
*
* @since 1.7.3
*/
public static function getInstance($name = null)
{
// Only create the object if it doesn't exist.
if (empty(self::$instance))
{
if (class_exists($name) && (is_subclass_of($name,
'\\Joomla\\CMS\\Application\\WebApplication')))
{
self::$instance = new $name;
}
else
{
self::$instance = new WebApplication;
}
}
return self::$instance;
}
/**
* Initialise the application.
*
* @param mixed $session An optional argument to provide dependency
injection for the application's
* session object. If the argument is a
\JSession object that object will become
* the application's session object, if
it is false then there will be no session
* object, and if it is null then the default
session object will be created based
* on the application's loadSession()
method.
* @param mixed $document An optional argument to provide dependency
injection for the application's
* document object. If the argument is a
\JDocument object that object will become
* the application's document object, if
it is false then there will be no document
* object, and if it is null then the default
document object will be created based
* on the application's loadDocument()
method.
* @param mixed $language An optional argument to provide dependency
injection for the application's
* language object. If the argument is a
\JLanguage object that object will become
* the application's language object, if
it is false then there will be no language
* object, and if it is null then the default
language object will be created based
* on the application's loadLanguage()
method.
* @param mixed $dispatcher An optional argument to provide dependency
injection for the application's
* event dispatcher. If the argument is a
\JEventDispatcher object that object will become
* the application's event dispatcher,
if it is null then the default event dispatcher
* will be created based on the
application's loadDispatcher() method.
*
* @return WebApplication Instance of $this to allow chaining.
*
* @deprecated 4.0
* @see WebApplication::loadSession()
* @see WebApplication::loadDocument()
* @see WebApplication::loadLanguage()
* @see WebApplication::loadDispatcher()
* @since 1.7.3
*/
public function initialise($session = null, $document = null, $language =
null, $dispatcher = null)
{
// Create the session based on the application logic.
if ($session !== false)
{
$this->loadSession($session);
}
// Create the document based on the application logic.
if ($document !== false)
{
$this->loadDocument($document);
}
// Create the language based on the application logic.
if ($language !== false)
{
$this->loadLanguage($language);
}
$this->loadDispatcher($dispatcher);
return $this;
}
/**
* Execute the application.
*
* @return void
*
* @since 1.7.3
*/
public function execute()
{
// Trigger the onBeforeExecute event.
$this->triggerEvent('onBeforeExecute');
// Perform application routines.
$this->doExecute();
// Trigger the onAfterExecute event.
$this->triggerEvent('onAfterExecute');
// If we have an application document object, render it.
if ($this->document instanceof \JDocument)
{
// Trigger the onBeforeRender event.
$this->triggerEvent('onBeforeRender');
// Render the application output.
$this->render();
// Trigger the onAfterRender event.
$this->triggerEvent('onAfterRender');
}
// If gzip compression is enabled in configuration and the server is
compliant, compress the output.
if ($this->get('gzip') &&
!ini_get('zlib.output_compression') &&
(ini_get('output_handler') != 'ob_gzhandler'))
{
$this->compress();
}
// Trigger the onBeforeRespond event.
$this->triggerEvent('onBeforeRespond');
// Send the application response.
$this->respond();
// Trigger the onAfterRespond event.
$this->triggerEvent('onAfterRespond');
}
/**
* Rendering is the process of pushing the document buffers into the
template
* placeholders, retrieving data from the document and pushing it into
* the application response buffer.
*
* @return void
*
* @since 1.7.3
*/
protected function render()
{
// Setup the document options.
$options = array(
'template' => $this->get('theme'),
'file' => $this->get('themeFile',
'index.php'),
'params' => $this->get('themeParams'),
);
if ($this->get('themes.base'))
{
$options['directory'] =
$this->get('themes.base');
}
// Fall back to constants.
else
{
$options['directory'] = defined('JPATH_THEMES') ?
JPATH_THEMES : (defined('JPATH_BASE') ? JPATH_BASE : __DIR__) .
'/themes';
}
// Parse the document.
$this->document->parse($options);
// Render the document.
$data =
$this->document->render($this->get('cache_enabled'),
$options);
// Set the application output data.
$this->setBody($data);
}
/**
* Checks the accept encoding of the browser and compresses the data
before
* sending it to the client if possible.
*
* @return void
*
* @since 1.7.3
*/
protected function compress()
{
// Supported compression encodings.
$supported = array(
'x-gzip' => 'gz',
'gzip' => 'gz',
'deflate' => 'deflate',
);
// Get the supported encoding.
$encodings = array_intersect($this->client->encodings,
array_keys($supported));
// If no supported encoding is detected do nothing and return.
if (empty($encodings))
{
return;
}
// Verify that headers have not yet been sent, and that our connection is
still alive.
if ($this->checkHeadersSent() || !$this->checkConnectionAlive())
{
return;
}
// Iterate through the encodings and attempt to compress the data using
any found supported encodings.
foreach ($encodings as $encoding)
{
if (($supported[$encoding] == 'gz') || ($supported[$encoding]
== 'deflate'))
{
// Verify that the server supports gzip compression before we attempt
to gzip encode the data.
if (!extension_loaded('zlib') ||
ini_get('zlib.output_compression'))
{
continue;
}
// Attempt to gzip encode the data with an optimal level 4.
$data = $this->getBody();
$gzdata = gzencode($data, 4, ($supported[$encoding] == 'gz')
? FORCE_GZIP : FORCE_DEFLATE);
// If there was a problem encoding the data just try the next encoding
scheme.
if ($gzdata === false)
{
continue;
}
// Set the encoding headers.
$this->setHeader('Content-Encoding', $encoding);
$this->setHeader('Vary', 'Accept-Encoding');
// Header will be removed at 4.0
if ($this->get('MetaVersion'))
{
$this->setHeader('X-Content-Encoded-By',
'Joomla');
}
// Replace the output with the encoded data.
$this->setBody($gzdata);
// Compression complete, let's break out of the loop.
break;
}
}
}
/**
* Method to send the application response to the client. All headers
will be sent prior to the main
* application output data.
*
* @return void
*
* @since 1.7.3
*/
protected function respond()
{
// Send the content-type header.
$this->setHeader('Content-Type', $this->mimeType .
'; charset=' . $this->charSet);
// If the response is set to uncachable, we need to set some appropriate
headers so browsers don't cache the response.
if (!$this->response->cachable)
{
// Expires in the past.
$this->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00
GMT', true);
// Always modified.
$this->setHeader('Last-Modified', gmdate('D, d M Y
H:i:s') . ' GMT', true);
$this->setHeader('Cache-Control', 'no-store, no-cache,
must-revalidate, post-check=0, pre-check=0', false);
// HTTP 1.0
$this->setHeader('Pragma', 'no-cache');
}
else
{
// Expires.
$this->setHeader('Expires', gmdate('D, d M Y
H:i:s', time() + 900) . ' GMT');
// Last modified.
if ($this->modifiedDate instanceof \JDate)
{
$this->setHeader('Last-Modified',
$this->modifiedDate->format('D, d M Y H:i:s'));
}
}
$this->sendHeaders();
echo $this->getBody();
}
/**
* Redirect to another URL.
*
* If the headers have not been sent the redirect will be accomplished
using a "301 Moved Permanently"
* or "303 See Other" code in the header pointing to the new
location. If the headers have already been
* sent this will be accomplished using a JavaScript statement.
*
* @param string $url The URL to redirect to. Can only be
http/https URL.
* @param integer $status The HTTP 1.1 status code to be provided. 303
is assumed by default.
*
* @return void
*
* @since 1.7.3
*/
public function redirect($url, $status = 303)
{
// Check for relative internal links.
if (preg_match('#^index\.php#', $url))
{
// We changed this from "$this->get('uri.base.full') .
$url" due to the inability to run the system tests with the original
code
$url = \JUri::base() . $url;
}
// Perform a basic sanity check to make sure we don't have any CRLF
garbage.
$url = preg_split("/[\r\n]/", $url);
$url = $url[0];
/*
* Here we need to check and see if the URL is relative or absolute.
Essentially, do we need to
* prepend the URL with our base URL for a proper redirect. The
rudimentary way we are looking
* at this is to simply check whether or not the URL string has a valid
scheme or not.
*/
if (!preg_match('#^[a-z]+\://#i', $url))
{
// Get a \JUri instance for the requested URI.
$uri = \JUri::getInstance($this->get('uri.request'));
// Get a base URL to prepend from the requested URI.
$prefix = $uri->toString(array('scheme', 'user',
'pass', 'host', 'port'));
// We just need the prefix since we have a path relative to the root.
if ($url[0] == '/')
{
$url = $prefix . $url;
}
// It's relative to where we are now, so lets add that.
else
{
$parts = explode('/',
$uri->toString(array('path')));
array_pop($parts);
$path = implode('/', $parts) . '/';
$url = $prefix . $path . $url;
}
}
// If the headers have already been sent we need to send the redirect
statement via JavaScript.
if ($this->checkHeadersSent())
{
echo "<script>document.location.href=" .
json_encode(str_replace("'", ''', $url))
. ";</script>\n";
}
else
{
// We have to use a JavaScript redirect here because MSIE doesn't
play nice with utf-8 URLs.
if (($this->client->engine == \JApplicationWebClient::TRIDENT)
&& !StringHelper::is_ascii($url))
{
$html = '<html><head>';
$html .= '<meta http-equiv="content-type"
content="text/html; charset=' . $this->charSet . '"
/>';
$html .= '<script>document.location.href=' .
json_encode(str_replace("'", ''', $url))
. ';</script>';
$html .=
'</head><body></body></html>';
echo $html;
}
else
{
// Check if we have a boolean for the status variable for compatibility
with old $move parameter
// @deprecated 4.0
if (is_bool($status))
{
$status = $status ? 301 : 303;
}
// Now check if we have an integer status code that maps to a valid
redirect. If we don't then set a 303
// @deprecated 4.0 From 4.0 if no valid status code is given an
InvalidArgumentException will be thrown
if (!is_int($status) || !$this->isRedirectState($status))
{
$status = 303;
}
// All other cases use the more efficient HTTP header for redirection.
$this->setHeader('Status', $status, true);
$this->setHeader('Location', $url, true);
}
}
// Trigger the onBeforeRespond event.
$this->triggerEvent('onBeforeRespond');
// Set appropriate headers
$this->respond();
// Trigger the onAfterRespond event.
$this->triggerEvent('onAfterRespond');
// Close the application after the redirect.
$this->close();
}
/**
* Checks if a state is a redirect state
*
* @param integer $state The HTTP 1.1 status code.
*
* @return boolean
*
* @since 3.8.0
*/
protected function isRedirectState($state)
{
$state = (int) $state;
return ($state > 299 && $state < 400);
}
/**
* Load an object or array into the application configuration object.
*
* @param mixed $data Either an array or object to be loaded into the
configuration object.
*
* @return WebApplication Instance of $this to allow chaining.
*
* @since 1.7.3
*/
public function loadConfiguration($data)
{
// Load the data into the configuration object.
if (is_array($data))
{
$this->config->loadArray($data);
}
elseif (is_object($data))
{
$this->config->loadObject($data);
}
return $this;
}
/**
* Set/get cachable state for the response. If $allow is set, sets the
cachable state of the
* response. Always returns the current state.
*
* @param boolean $allow True to allow browser caching.
*
* @return boolean
*
* @since 1.7.3
*/
public function allowCache($allow = null)
{
if ($allow !== null)
{
$this->response->cachable = (bool) $allow;
}
return $this->response->cachable;
}
/**
* Method to set a response header. If the replace flag is set then all
headers
* with the given name will be replaced by the new one. The headers are
stored
* in an internal array to be sent when the site is sent to the browser.
*
* @param string $name The name of the header to set.
* @param string $value The value of the header to set.
* @param boolean $replace True to replace any headers with the same
name.
*
* @return WebApplication Instance of $this to allow chaining.
*
* @since 1.7.3
*/
public function setHeader($name, $value, $replace = false)
{
// Sanitize the input values.
$name = (string) $name;
$value = (string) $value;
// Create an array of duplicate header names
$keys = false;
if ($this->response->headers)
{
$names = array();
foreach ($this->response->headers as $key => $header)
{
$names[$key] = $header['name'];
}
// Find existing headers by name
$keys = array_keys($names, $name);
}
// Remove if $replace is true and there are duplicate names
if ($replace && $keys)
{
$this->response->headers =
array_diff_key($this->response->headers, array_flip($keys));
}
/*
* If no keys found, safe to insert (!$keys)
* If ($keys && $replace) it's a replacement and previous
have been deleted
* If ($keys && !in_array...) it's a multiple value header
*/
$single = in_array(strtolower($name),
$this->singleValueResponseHeaders);
if ($value && (!$keys || ($keys && ($replace ||
!$single))))
{
// Add the header to the internal array.
$this->response->headers[] = array('name' => $name,
'value' => $value);
}
return $this;
}
/**
* Method to get the array of response headers to be sent when the
response is sent
* to the client.
*
* @return array *
*
* @since 1.7.3
*/
public function getHeaders()
{
return $this->response->headers;
}
/**
* Method to clear any set response headers.
*
* @return WebApplication Instance of $this to allow chaining.
*
* @since 1.7.3
*/
public function clearHeaders()
{
$this->response->headers = array();
return $this;
}
/**
* Send the response headers.
*
* @return WebApplication Instance of $this to allow chaining.
*
* @since 1.7.3
*/
public function sendHeaders()
{
if (!$this->checkHeadersSent())
{
// Creating an array of headers, making arrays of headers with multiple
values
$val = array();
foreach ($this->response->headers as $header)
{
if ('status' == strtolower($header['name']))
{
// 'status' headers indicate an HTTP status, and need to be
handled slightly differently
$status = $this->getHttpStatusValue($header['value']);
$this->header($status, true, (int) $header['value']);
}
else
{
$val[$header['name']] =
!isset($val[$header['name']]) ? $header['value'] :
implode(', ', array($val[$header['name']],
$header['value']));
$this->header($header['name'] . ': ' .
$val[$header['name']], true);
}
}
}
return $this;
}
/**
* Check if a given value can be successfully mapped to a valid http
status value
*
* @param string $value The given status as int or string
*
* @return string
*
* @since 3.8.0
*/
protected function getHttpStatusValue($value)
{
$code = (int) $value;
if (array_key_exists($code, $this->responseMap))
{
return $this->responseMap[$code];
}
return 'HTTP/1.1 ' . $code;
}
/**
* Set body content. If body content already defined, this will replace
it.
*
* @param string $content The content to set as the response body.
*
* @return WebApplication Instance of $this to allow chaining.
*
* @since 1.7.3
*/
public function setBody($content)
{
$this->response->body = array((string) $content);
return $this;
}
/**
* Prepend content to the body content
*
* @param string $content The content to prepend to the response body.
*
* @return WebApplication Instance of $this to allow chaining.
*
* @since 1.7.3
*/
public function prependBody($content)
{
array_unshift($this->response->body, (string) $content);
return $this;
}
/**
* Append content to the body content
*
* @param string $content The content to append to the response body.
*
* @return WebApplication Instance of $this to allow chaining.
*
* @since 1.7.3
*/
public function appendBody($content)
{
$this->response->body[] = (string) $content;
return $this;
}
/**
* Return the body content
*
* @param boolean $asArray True to return the body as an array of
strings.
*
* @return mixed The response body either as an array or concatenated
string.
*
* @since 1.7.3
*/
public function getBody($asArray = false)
{
return $asArray ? $this->response->body : implode((array)
$this->response->body);
}
/**
* Method to get the application document object.
*
* @return \JDocument The document object
*
* @since 1.7.3
*/
public function getDocument()
{
return $this->document;
}
/**
* Method to get the application language object.
*
* @return \JLanguage The language object
*
* @since 1.7.3
*/
public function getLanguage()
{
return $this->language;
}
/**
* Method to get the application session object.
*
* @return \JSession The session object
*
* @since 1.7.3
*/
public function getSession()
{
return $this->session;
}
/**
* Method to check the current client connection status to ensure that it
is alive. We are
* wrapping this to isolate the connection_status() function from our code
base for testing reasons.
*
* @return boolean True if the connection is valid and normal.
*
* @see connection_status()
* @since 1.7.3
*/
protected function checkConnectionAlive()
{
return connection_status() === CONNECTION_NORMAL;
}
/**
* Method to check to see if headers have already been sent. We are
wrapping this to isolate the
* headers_sent() function from our code base for testing reasons.
*
* @return boolean True if the headers have already been sent.
*
* @see headers_sent()
* @since 1.7.3
*/
protected function checkHeadersSent()
{
return headers_sent();
}
/**
* Method to detect the requested URI from server environment variables.
*
* @return string The requested URI
*
* @since 1.7.3
*/
protected function detectRequestUri()
{
// First we need to detect the URI scheme.
if (isset($_SERVER['HTTPS']) &&
!empty($_SERVER['HTTPS']) &&
(strtolower($_SERVER['HTTPS']) != 'off'))
{
$scheme = 'https://';
}
else
{
$scheme = 'http://';
}
/*
* There are some differences in the way that Apache and IIS populate
server environment variables. To
* properly detect the requested URI we need to adjust our algorithm
based on whether or not we are getting
* information from Apache or IIS.
*/
// Define variable to return
$uri = '';
// If PHP_SELF and REQUEST_URI are both populated then we will assume
"Apache Mode".
if (!empty($_SERVER['PHP_SELF']) &&
!empty($_SERVER['REQUEST_URI']))
{
// The URI is built from the HTTP_HOST and REQUEST_URI environment
variables in an Apache environment.
$uri = $scheme . $_SERVER['HTTP_HOST'] .
$_SERVER['REQUEST_URI'];
}
// If not in "Apache Mode" we will assume that we are in an IIS
environment and proceed.
elseif (isset($_SERVER['HTTP_HOST']))
{
// IIS uses the SCRIPT_NAME variable instead of a REQUEST_URI
variable... thanks, MS
$uri = $scheme . $_SERVER['HTTP_HOST'] .
$_SERVER['SCRIPT_NAME'];
// If the QUERY_STRING variable exists append it to the URI string.
if (isset($_SERVER['QUERY_STRING']) &&
!empty($_SERVER['QUERY_STRING']))
{
$uri .= '?' . $_SERVER['QUERY_STRING'];
}
}
return trim($uri);
}
/**
* Method to load a PHP configuration class file based on convention and
return the instantiated data object. You
* will extend this method in child classes to provide configuration data
from whatever data source is relevant
* for your specific application.
*
* @param string $file The path and filename of the configuration
file. If not provided, configuration.php
* in JPATH_CONFIGURATION will be used.
* @param string $class The class name to instantiate.
*
* @return mixed Either an array or object to be loaded into the
configuration object.
*
* @since 1.7.3
* @throws \RuntimeException
*/
protected function fetchConfigurationData($file = '', $class =
'\JConfig')
{
// Instantiate variables.
$config = array();
if (empty($file))
{
$file = JPATH_CONFIGURATION . '/configuration.php';
// Applications can choose not to have any configuration data
// by not implementing this method and not having a config file.
if (!file_exists($file))
{
$file = '';
}
}
if (!empty($file))
{
\JLoader::register($class, $file);
if (class_exists($class))
{
$config = new $class;
}
else
{
throw new \RuntimeException('Configuration class does not
exist.');
}
}
return $config;
}
/**
* Flush the media version to refresh versionable assets
*
* @return void
*
* @since 3.2
*/
public function flushAssets()
{
$version = new \JVersion;
$version->refreshMediaVersion();
}
/**
* Method to send a header to the client. We are wrapping this to isolate
the header() function
* from our code base for testing reasons.
*
* @param string $string The header string.
* @param boolean $replace The optional replace parameter indicates
whether the header should
* replace a previous similar header, or add a
second header of the same type.
* @param integer $code Forces the HTTP response code to the
specified value. Note that
* this parameter only has an effect if the
string is not empty.
*
* @return void
*
* @see header()
* @since 1.7.3
*/
protected function header($string, $replace = true, $code = null)
{
$string = str_replace(chr(0), '', $string);
header($string, $replace, $code);
}
/**
* Determine if we are using a secure (SSL) connection.
*
* @return boolean True if using SSL, false if not.
*
* @since 3.0.1
*/
public function isSSLConnection()
{
return (isset($_SERVER['HTTPS']) &&
($_SERVER['HTTPS'] == 'on')) ||
getenv('SSL_PROTOCOL_VERSION');
}
/**
* Allows the application to load a custom or default document.
*
* The logic and options for creating this object are adequately generic
for default cases
* but for many applications it will make sense to override this method
and create a document,
* if required, based on more specific needs.
*
* @param \JDocument $document An optional document object. If
omitted, the factory document is created.
*
* @return WebApplication This method is chainable.
*
* @since 1.7.3
*/
public function loadDocument(\JDocument $document = null)
{
$this->document = ($document === null) ? \JFactory::getDocument() :
$document;
return $this;
}
/**
* Allows the application to load a custom or default language.
*
* The logic and options for creating this object are adequately generic
for default cases
* but for many applications it will make sense to override this method
and create a language,
* if required, based on more specific needs.
*
* @param \JLanguage $language An optional language object. If
omitted, the factory language is created.
*
* @return WebApplication This method is chainable.
*
* @since 1.7.3
*/
public function loadLanguage(\JLanguage $language = null)
{
$this->language = ($language === null) ? \JFactory::getLanguage() :
$language;
return $this;
}
/**
* Allows the application to load a custom or default session.
*
* The logic and options for creating this object are adequately generic
for default cases
* but for many applications it will make sense to override this method
and create a session,
* if required, based on more specific needs.
*
* @param \JSession $session An optional session object. If omitted,
the session is created.
*
* @return WebApplication This method is chainable.
*
* @since 1.7.3
*/
public function loadSession(\JSession $session = null)
{
if ($session !== null)
{
$this->session = $session;
return $this;
}
// Generate a session name.
$name = md5($this->get('secret') .
$this->get('session_name', get_class($this)));
// Calculate the session lifetime.
$lifetime = (($this->get('sess_lifetime')) ?
$this->get('sess_lifetime') * 60 : 900);
// Get the session handler from the configuration.
$handler = $this->get('sess_handler', 'none');
// Initialize the options for \JSession.
$options = array(
'name' => $name,
'expire' => $lifetime,
'force_ssl' => $this->get('force_ssl'),
);
$this->registerEvent('onAfterSessionStart', array($this,
'afterSessionStart'));
// Instantiate the session object.
$session = \JSession::getInstance($handler, $options);
$session->initialise($this->input, $this->dispatcher);
if ($session->getState() == 'expired')
{
$session->restart();
}
else
{
$session->start();
}
// Set the session object.
$this->session = $session;
return $this;
}
/**
* After the session has been started we need to populate it with some
default values.
*
* @return void
*
* @since 3.0.1
*/
public function afterSessionStart()
{
$session = \JFactory::getSession();
if ($session->isNew())
{
$session->set('registry', new Registry);
$session->set('user', new \JUser);
}
}
/**
* Method to load the system URI strings for the application.
*
* @param string $requestUri An optional request URI to use instead of
detecting one from the
* server environment variables.
*
* @return void
*
* @since 1.7.3
*/
protected function loadSystemUris($requestUri = null)
{
// Set the request URI.
if (!empty($requestUri))
{
$this->set('uri.request', $requestUri);
}
else
{
$this->set('uri.request', $this->detectRequestUri());
}
// Check to see if an explicit base URI has been set.
$siteUri = trim($this->get('site_uri'));
if ($siteUri != '')
{
$uri = \JUri::getInstance($siteUri);
$path = $uri->toString(array('path'));
}
// No explicit base URI was set so we need to detect it.
else
{
// Start with the requested URI.
$uri = \JUri::getInstance($this->get('uri.request'));
// If we are working from a CGI SAPI with the
'cgi.fix_pathinfo' directive disabled we use PHP_SELF.
if (strpos(php_sapi_name(), 'cgi') !== false &&
!ini_get('cgi.fix_pathinfo') &&
!empty($_SERVER['REQUEST_URI']))
{
// We aren't expecting PATH_INFO within PHP_SELF so this should
work.
$path = dirname($_SERVER['PHP_SELF']);
}
// Pretty much everything else should be handled with SCRIPT_NAME.
else
{
$path = dirname($_SERVER['SCRIPT_NAME']);
}
}
$host = $uri->toString(array('scheme', 'user',
'pass', 'host', 'port'));
// Check if the path includes "index.php".
if (strpos($path, 'index.php') !== false)
{
// Remove the index.php portion of the path.
$path = substr_replace($path, '', strpos($path,
'index.php'), 9);
}
$path = rtrim($path, '/\\');
// Set the base URI both as just a path and as the full URI.
$this->set('uri.base.full', $host . $path . '/');
$this->set('uri.base.host', $host);
$this->set('uri.base.path', $path . '/');
// Set the extended (non-base) part of the request URI as the route.
if (stripos($this->get('uri.request'),
$this->get('uri.base.full')) === 0)
{
$this->set('uri.route',
substr_replace($this->get('uri.request'), '', 0,
strlen($this->get('uri.base.full'))));
}
// Get an explicitly set media URI is present.
$mediaURI = trim($this->get('media_uri'));
if ($mediaURI)
{
if (strpos($mediaURI, '://') !== false)
{
$this->set('uri.media.full', $mediaURI);
$this->set('uri.media.path', $mediaURI);
}
else
{
// Normalise slashes.
$mediaURI = trim($mediaURI, '/\\');
$mediaURI = !empty($mediaURI) ? '/' . $mediaURI .
'/' : '/';
$this->set('uri.media.full',
$this->get('uri.base.host') . $mediaURI);
$this->set('uri.media.path', $mediaURI);
}
}
// No explicit media URI was set, build it dynamically from the base uri.
else
{
$this->set('uri.media.full',
$this->get('uri.base.full') . 'media/');
$this->set('uri.media.path',
$this->get('uri.base.path') . 'media/');
}
}
}