Файловый менеджер - Редактировать - /home/lmsyaran/public_html/khsh/Application.tar
Назад
AdministratorApplication.php 0000644 00000031423 15117163426 0012272 0 ustar 00 <?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.php 0000644 00000014223 15117163427 0010671 0 ustar 00 <?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.php 0000644 00000011203 15117163427 0010317 0 ustar 00 <?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.php 0000644 00000016461 15117163427 0010167 0 ustar 00 <?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.php 0000644 00000075052 15117163427 0010103 0 ustar 00 <?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.php 0000644 00000061030 15117163427 0010653 0 ustar 00 <?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.php 0000644 00000052445 15117163427 0010366 0 ustar 00 <?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.php 0000644 00000112477 15117163427 0010201 0 ustar 00 <?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/'); } } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0.45 |
proxy
|
phpinfo
|
Настройка