Spade
Mini Shell
PKu�[��]��rating_star.pngnu�[����PNG
IHDRVu\��IDATxڕ�=@@`g�K��!����8�^4:��p�d^�$"o�H���LCz�F�D:�
R�g�e6�H�PC ;+9S� h�A����M�Bq�\���0(�~���l�
Dl�̒!t�^2��P�C���2:;�Uư���UIEND�B`�PKu�[W9����rating_star_blank.pngnu�[����PNG
IHDR�|�l�IDATxc@Y"�%��>�}�\�!B��%�����e��
�d�E,\�]�P PD�+��3\�K&�
�p�\T��%�
��|uy���o�,6����V0K��AHh93��Ό.Z
�n><�9��IEND�B`�PKu�[��V\��sort_asc.pngnu�[����PNG
IHDR�|�lGIDATx��G@!��^�Wp���';� �7�K��������U��6=ҢŎ4k�$�U��OT��A�x���H���IEND�B`�PKu�[J!G`��
sort_desc.pngnu�[����PNG
IHDR�|�lNIDATx��1�`^��4 /�q�+�jo�!2�o|�u���\\�b�8�ڭ���ݙ��ZL`��0E�1��i���T�IEND�B`�PK|��[���/�/actionlogs/actionlogs.phpnu�[���<?php
/**
* @package Joomla.Plugins
* @subpackage System.actionlogs
*
* @copyright (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\User;
/**
* Joomla! Users Actions Logging Plugin.
*
* @since 3.9.0
*/
class PlgSystemActionLogs extends JPlugin
{
/**
* Application object.
*
* @var JApplicationCms
* @since 3.9.0
*/
protected $app;
/**
* Database object.
*
* @var JDatabaseDriver
* @since 3.9.0
*/
protected $db;
/**
* Load plugin language file automatically so that it can be used inside
component
*
* @var boolean
* @since 3.9.0
*/
protected $autoloadLanguage = true;
/**
* Constructor.
*
* @param object &$subject The object to observe.
* @param array $config An optional associative array of
configuration settings.
*
* @since 3.9.0
*/
public function __construct(&$subject, $config)
{
parent::__construct($subject, $config);
// Import actionlog plugin group so that these plugins will be triggered
for events
PluginHelper::importPlugin('actionlog');
}
/**
* Adds additional fields to the user editing form for logs e-mail
notifications
*
* @param JForm $form The form to be altered.
* @param mixed $data The associated data for the form.
*
* @return boolean
*
* @since 3.9.0
*/
public function onContentPrepareForm($form, $data)
{
if (!$form instanceof Form)
{
$this->subject->setError('JERROR_NOT_A_FORM');
return false;
}
$formName = $form->getName();
$allowedFormNames = array(
'com_users.profile',
'com_admin.profile',
'com_users.user',
);
if (!in_array($formName, $allowedFormNames))
{
return true;
}
/**
* We only allow users who has Super User permission change this setting
for himself or for other users
* who has same Super User permission
*/
$user = Factory::getUser();
if (!$user->authorise('core.admin'))
{
return true;
}
// If we are on the save command, no data is passed to $data variable, we
need to get it directly from request
$jformData = $this->app->input->get('jform', array(),
'array');
if ($jformData && !$data)
{
$data = $jformData;
}
if (is_array($data))
{
$data = (object) $data;
}
if (empty($data->id) ||
!User::getInstance($data->id)->authorise('core.admin'))
{
return true;
}
Form::addFormPath(__DIR__ . '/forms');
if ((!PluginHelper::isEnabled('actionlog', 'joomla'))
&&
(Factory::getApplication()->isClient('administrator')))
{
$form->loadFile('information', false);
return true;
}
if (!PluginHelper::isEnabled('actionlog', 'joomla'))
{
return true;
}
$form->loadFile('actionlogs', false);
}
/**
* Runs on content preparation
*
* @param string $context The context for the data
* @param object $data An object containing the data for the form.
*
* @return boolean
*
* @since 3.9.0
*/
public function onContentPrepareData($context, $data)
{
if (!in_array($context, array('com_users.profile',
'com_admin.profile', 'com_users.user')))
{
return true;
}
if (is_array($data))
{
$data = (object) $data;
}
if
(!User::getInstance($data->id)->authorise('core.admin'))
{
return true;
}
$query = $this->db->getQuery(true)
->select($this->db->quoteName(array('notify',
'extensions')))
->from($this->db->quoteName('#__action_logs_users'))
->where($this->db->quoteName('user_id') . ' =
' . (int) $data->id);
try
{
$values = $this->db->setQuery($query)->loadObject();
}
catch (JDatabaseExceptionExecuting $e)
{
return false;
}
if (!$values)
{
return true;
}
$data->actionlogs = new StdClass;
$data->actionlogs->actionlogsNotify = $values->notify;
$data->actionlogs->actionlogsExtensions = $values->extensions;
if (!HTMLHelper::isRegistered('users.actionlogsNotify'))
{
HTMLHelper::register('users.actionlogsNotify',
array(__CLASS__, 'renderActionlogsNotify'));
}
if (!HTMLHelper::isRegistered('users.actionlogsExtensions'))
{
HTMLHelper::register('users.actionlogsExtensions',
array(__CLASS__, 'renderActionlogsExtensions'));
}
return true;
}
/**
* Runs after the HTTP response has been sent to the client and delete log
records older than certain days
*
* @return void
*
* @since 3.9.0
*/
public function onAfterRespond()
{
$daysToDeleteAfter = (int)
$this->params->get('logDeletePeriod', 0);
if ($daysToDeleteAfter <= 0)
{
return;
}
// The delete frequency will be once per day
$deleteFrequency = 3600 * 24;
// Do we need to run? Compare the last run timestamp stored in the
plugin's options with the current
// timestamp. If the difference is greater than the cache timeout we
shall not execute again.
$now = time();
$last = (int) $this->params->get('lastrun', 0);
if (abs($now - $last) < $deleteFrequency)
{
return;
}
// Update last run status
$this->params->set('lastrun', $now);
$db = $this->db;
$query = $db->getQuery(true)
->update($db->qn('#__extensions'))
->set($db->qn('params') . ' = ' .
$db->q($this->params->toString('JSON')))
->where($db->qn('type') . ' = ' .
$db->q('plugin'))
->where($db->qn('folder') . ' = ' .
$db->q('system'))
->where($db->qn('element') . ' = ' .
$db->q('actionlogs'));
try
{
// Lock the tables to prevent multiple plugin executions causing a race
condition
$db->lockTable('#__extensions');
}
catch (Exception $e)
{
// If we can't lock the tables it's too risky to continue
execution
return;
}
try
{
// Update the plugin parameters
$result = $db->setQuery($query)->execute();
$this->clearCacheGroups(array('com_plugins'), array(0, 1));
}
catch (Exception $exc)
{
// If we failed to execute
$db->unlockTables();
$result = false;
}
try
{
// Unlock the tables after writing
$db->unlockTables();
}
catch (Exception $e)
{
// If we can't lock the tables assume we have somehow failed
$result = false;
}
// Abort on failure
if (!$result)
{
return;
}
$daysToDeleteAfter = (int)
$this->params->get('logDeletePeriod', 0);
$now = $db->quote(Factory::getDate()->toSql());
if ($daysToDeleteAfter > 0)
{
$conditions = array($db->quoteName('log_date') . '
< ' . $query->dateAdd($now, -1 * $daysToDeleteAfter, '
DAY'));
$query->clear()
->delete($db->quoteName('#__action_logs'))->where($conditions);
$db->setQuery($query);
try
{
$db->execute();
}
catch (RuntimeException $e)
{
// Ignore it
return;
}
}
}
/**
* Utility method to act on a user after it has been saved.
*
* @param array $user Holds the new user data.
* @param boolean $isNew True if a new user is stored.
* @param boolean $success True if user was successfully stored in the
database.
* @param string $msg Message.
*
* @return boolean
*
* @since 3.9.0
*/
public function onUserAfterSave($user, $isNew, $success, $msg)
{
if (!$success)
{
return false;
}
// Clear access rights in case user groups were changed.
$userObject = new User($user['id']);
$userObject->clearAccessRights();
$authorised = $userObject->authorise('core.admin');
$query = $this->db->getQuery(true)
->select('COUNT(*)')
->from($this->db->quoteName('#__action_logs_users'))
->where($this->db->quoteName('user_id') . ' =
' . (int) $user['id']);
try
{
$exists = (bool) $this->db->setQuery($query)->loadResult();
}
catch (JDatabaseExceptionExecuting $e)
{
return false;
}
// If preferences don't exist, insert.
if (!$exists && $authorised &&
isset($user['actionlogs']))
{
$values = array((int) $user['id'], (int)
$user['actionlogs']['actionlogsNotify']);
$columns = array('user_id', 'notify');
if
(isset($user['actionlogs']['actionlogsExtensions']))
{
$values[] =
$this->db->quote(json_encode($user['actionlogs']['actionlogsExtensions']));
$columns[] = 'extensions';
}
$query = $this->db->getQuery(true)
->insert($this->db->quoteName('#__action_logs_users'))
->columns($this->db->quoteName($columns))
->values(implode(',', $values));
}
elseif ($exists && $authorised &&
isset($user['actionlogs']))
{
// Update preferences.
$values = array($this->db->quoteName('notify') . '
= ' . (int)
$user['actionlogs']['actionlogsNotify']);
if
(isset($user['actionlogs']['actionlogsExtensions']))
{
$values[] = $this->db->quoteName('extensions') . '
= ' .
$this->db->quote(json_encode($user['actionlogs']['actionlogsExtensions']));
}
$query = $this->db->getQuery(true)
->update($this->db->quoteName('#__action_logs_users'))
->set($values)
->where($this->db->quoteName('user_id') . ' =
' . (int) $user['id']);
}
elseif ($exists && !$authorised)
{
// Remove preferences if user is not authorised.
$query = $this->db->getQuery(true)
->delete($this->db->quoteName('#__action_logs_users'))
->where($this->db->quoteName('user_id') . ' =
' . (int) $user['id']);
}
try
{
$this->db->setQuery($query)->execute();
}
catch (JDatabaseExceptionExecuting $e)
{
return false;
}
return true;
}
/**
* Removes user preferences
*
* Method is called after user data is deleted from the database
*
* @param array $user Holds the user data
* @param boolean $success True if user was successfully stored in the
database
* @param string $msg Message
*
* @return boolean
*
* @since 3.9.0
*/
public function onUserAfterDelete($user, $success, $msg)
{
if (!$success)
{
return false;
}
$query = $this->db->getQuery(true)
->delete($this->db->quoteName('#__action_logs_users'))
->where($this->db->quoteName('user_id') . ' =
' . (int) $user['id']);
try
{
$this->db->setQuery($query)->execute();
}
catch (JDatabaseExceptionExecuting $e)
{
return false;
}
return true;
}
/**
* Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
*
* @param array $clearGroups The cache groups to clean
* @param array $cacheClients The cache clients (site, admin) to clean
*
* @return void
*
* @since 3.9.0
*/
private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
{
$conf = Factory::getConfig();
foreach ($clearGroups as $group)
{
foreach ($cacheClients as $clientId)
{
try
{
$options = array(
'defaultgroup' => $group,
'cachebase' => $clientId ? JPATH_ADMINISTRATOR .
'/cache' :
$conf->get('cache_path', JPATH_SITE .
'/cache')
);
$cache = Cache::getInstance('callback', $options);
$cache->clean();
}
catch (Exception $e)
{
// Ignore it
}
}
}
}
/**
* Method to render a value.
*
* @param integer|string $value The value (0 or 1).
*
* @return string The rendered value.
*
* @since 3.9.16
*/
public static function renderActionlogsNotify($value)
{
return Text::_($value ? 'JYES' : 'JNO');
}
/**
* Method to render a list of extensions.
*
* @param array|string $extensions Array of extensions or an empty
string if none selected.
*
* @return string The rendered value.
*
* @since 3.9.16
*/
public static function renderActionlogsExtensions($extensions)
{
// No extensions selected.
if (!$extensions)
{
return Text::_('JNONE');
}
// Load the helper.
JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR .
'/components/com_actionlogs/helpers/actionlogs.php');
foreach ($extensions as &$extension)
{
// Load extension language files and translate extension name.
ActionlogsHelper::loadTranslationFiles($extension);
$extension = Text::_($extension);
}
return implode(', ', $extensions);
}
}
PK|��[؞���actionlogs/actionlogs.xmlnu�[���<?xml
version="1.0" encoding="UTF-8"?>
<extension version="3.9" type="plugin"
group="system" method="upgrade">
<name>PLG_SYSTEM_ACTIONLOGS</name>
<author>Joomla! Project</author>
<creationDate>May 2018</creationDate>
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.9.0</version>
<description>PLG_SYSTEM_ACTIONLOGS_XML_DESCRIPTION</description>
<files>
<filename
plugin="actionlogs">actionlogs.php</filename>
<folder>forms</folder>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_actionlogs.ini</language>
<language
tag="en-GB">en-GB.plg_system_actionlogs.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="logDeletePeriod"
type="number"
label="PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD"
description="PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD_DESC"
default="0"
min="0"
filter="int"
validate="number"
/>
<field
name="lastrun"
type="hidden"
default="0"
filter="integer"
/>
</fieldset>
</fields>
</config>
</extension>
PK|��[��<__actionlogs/forms/actionlogs.xmlnu�[���<?xml
version="1.0" encoding="UTF-8"?>
<form>
<fieldset name="actionlogs"
label="PLG_SYSTEM_ACTIONLOGS_OPTIONS"
addfieldpath="/administrator/components/com_actionlogs/models/fields">
<fields name="actionlogs">
<field
name="actionlogsNotify"
type="radio"
label="PLG_SYSTEM_ACTIONLOGS_NOTIFICATIONS"
description="PLG_SYSTEM_ACTIONLOGS_NOTIFICATIONS_DESC"
class="btn-group btn-group-yesno"
default="0"
filter="integer"
required="true"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="actionlogsExtensions"
type="logtype"
label="PLG_SYSTEM_ACTIONLOGS_EXTENSIONS_NOTIFICATIONS"
description="PLG_SYSTEM_ACTIONLOGS_EXTENSIONS_NOTIFICATIONS_DESC"
multiple="true"
validate="options"
showon="actionlogsNotify:1"
/>
</fields>
</fieldset>
</form>
PK|��[�����
actionlogs/forms/information.xmlnu�[���<?xml
version="1.0" encoding="UTF-8"?>
<form>
<fields name="params">
<fieldset name="information"
label="PLG_SYSTEM_ACTIONLOGS_OPTIONS"
addfieldpath="/administrator/components/com_actionlogs/models/fields">
<field
name="Information"
type="plugininfo"
label="PLG_SYSTEM_ACTIONLOGS_INFO_LABEL"
description="PLG_SYSTEM_ACTIONLOGS_INFO_DESC"
/>
</fieldset>
</fields>
</form>
PK|��[�~�cccache/cache.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.cache
*
* @copyright (C) 2007 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Joomla! Page Cache Plugin.
*
* @since 1.5
*/
class PlgSystemCache extends JPlugin
{
/**
* Cache instance.
*
* @var JCache
* @since 1.5
*/
public $_cache;
/**
* Cache key
*
* @var string
* @since 3.0
*/
public $_cache_key;
/**
* Application object.
*
* @var JApplicationCms
* @since 3.8.0
*/
protected $app;
/**
* Constructor.
*
* @param object &$subject The object to observe.
* @param array $config An optional associative array of
configuration settings.
*
* @since 1.5
*/
public function __construct(& $subject, $config)
{
parent::__construct($subject, $config);
// Get the application if not done by JPlugin.
if (!isset($this->app))
{
$this->app = JFactory::getApplication();
}
// Set the cache options.
$options = array(
'defaultgroup' => 'page',
'browsercache' =>
$this->params->get('browsercache', 0),
'caching' => false,
);
// Instantiate cache with previous options and create the cache key
identifier.
$this->_cache = JCache::getInstance('page', $options);
$this->_cache_key = JUri::getInstance()->toString();
}
/**
* Get a cache key for the current page based on the url and possible
other factors.
*
* @return string
*
* @since 3.7
*/
protected function getCacheKey()
{
static $key;
if (!$key)
{
JPluginHelper::importPlugin('pagecache');
$parts =
JEventDispatcher::getInstance()->trigger('onPageCacheGetKey');
$parts[] = JUri::getInstance()->toString();
$key = md5(serialize($parts));
}
return $key;
}
/**
* After Initialise Event.
* Checks if URL exists in cache, if so dumps it directly and closes.
*
* @return void
*
* @since 1.5
*/
public function onAfterInitialise()
{
if ($this->app->isClient('administrator') ||
$this->app->get('offline', '0') ||
$this->app->getMessageQueue())
{
return;
}
// If any pagecache plugins return false for onPageCacheSetCaching, do
not use the cache.
JPluginHelper::importPlugin('pagecache');
$results =
JEventDispatcher::getInstance()->trigger('onPageCacheSetCaching');
$caching = !in_array(false, $results, true);
if ($caching && JFactory::getUser()->guest &&
$this->app->input->getMethod() === 'GET')
{
$this->_cache->setCaching(true);
}
$data = $this->_cache->get($this->getCacheKey());
// If page exist in cache, show cached page.
if ($data !== false)
{
// Set HTML page from cache.
$this->app->setBody($data);
// Dumps HTML page.
echo $this->app->toString((bool)
$this->app->get('gzip'));
// Mark afterCache in debug and run debug onAfterRespond events.
// e.g., show Joomla Debug Console if debug is active.
if (JDEBUG)
{
JProfiler::getInstance('Application')->mark('afterCache');
JEventDispatcher::getInstance()->trigger('onAfterRespond');
}
// Closes the application.
$this->app->close();
}
}
/**
* After Render Event.
* Verify if current page is not excluded from cache.
*
* @return void
*
* @since 3.9.12
*/
public function onAfterRender()
{
if ($this->_cache->getCaching() === false)
{
return;
}
// We need to check if user is guest again here, because auto-login
plugins have not been fired before the first aid check.
// Page is excluded if excluded in plugin settings.
if (!JFactory::getUser()->guest || $this->app->getMessageQueue()
|| $this->isExcluded() === true)
{
$this->_cache->setCaching(false);
return;
}
// Disable compression before caching the page.
$this->app->set('gzip', false);
}
/**
* After Respond Event.
* Stores page in cache.
*
* @return void
*
* @since 1.5
*/
public function onAfterRespond()
{
if ($this->_cache->getCaching() === false)
{
return;
}
// Saves current page in cache.
$this->_cache->store($this->app->getBody(),
$this->getCacheKey());
}
/**
* Check if the page is excluded from the cache or not.
*
* @return boolean True if the page is excluded else false
*
* @since 3.5
*/
protected function isExcluded()
{
// Check if menu items have been excluded.
if ($exclusions =
$this->params->get('exclude_menu_items', array()))
{
// Get the current menu item.
$active = $this->app->getMenu()->getActive();
if ($active && $active->id && in_array((int)
$active->id, (array) $exclusions))
{
return true;
}
}
// Check if regular expressions are being used.
if ($exclusions = $this->params->get('exclude',
''))
{
// Normalize line endings.
$exclusions = str_replace(array("\r\n", "\r"),
"\n", $exclusions);
// Split them.
$exclusions = explode("\n", $exclusions);
// Gets internal URI.
$internal_uri = '/index.php?' .
JUri::getInstance()->buildQuery($this->app->getRouter()->getVars());
// Loop through each pattern.
if ($exclusions)
{
foreach ($exclusions as $exclusion)
{
// Make sure the exclusion has some content
if ($exclusion !== '')
{
// Test both external and internal URI
if (preg_match('#' . $exclusion . '#i',
$this->_cache_key . ' ' . $internal_uri, $match))
{
return true;
}
}
}
}
}
// If any pagecache plugins return true for onPageCacheIsExcluded,
exclude.
JPluginHelper::importPlugin('pagecache');
$results =
JEventDispatcher::getInstance()->trigger('onPageCacheIsExcluded');
return in_array(true, $results, true);
}
}
PK|��[a6�cache/cache.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_cache</name>
<author>Joomla! Project</author>
<creationDate>February 2007</creationDate>
<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_CACHE_XML_DESCRIPTION</description>
<files>
<filename plugin="cache">cache.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_cache.ini</language>
<language
tag="en-GB">en-GB.plg_system_cache.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="browsercache"
type="radio"
label="PLG_CACHE_FIELD_BROWSERCACHE_LABEL"
description="PLG_CACHE_FIELD_BROWSERCACHE_DESC"
class="btn-group btn-group-yesno"
default="0"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="exclude_menu_items"
type="menuitem"
label="PLG_CACHE_FIELD_EXCLUDE_MENU_ITEMS_LABEL"
description="PLG_CACHE_FIELD_EXCLUDE_MENU_ITEMS_DESC"
multiple="multiple"
filter="int_array"
/>
</fieldset>
<fieldset name="advanced">
<field
name="exclude"
type="textarea"
label="PLG_CACHE_FIELD_EXCLUDE_LABEL"
description="PLG_CACHE_FIELD_EXCLUDE_DESC"
class="input-xxlarge"
rows="15"
filter="raw"
/>
</fieldset>
</fields>
</config>
</extension>
PK|��[�+Gb�b�debug/debug.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\Utilities\ArrayHelper;
/**
* Joomla! Debug plugin.
*
* @since 1.5
*/
class PlgSystemDebug extends JPlugin
{
/**
* xdebug.file_link_format from the php.ini.
*
* @var string
* @since 1.7
*/
protected $linkFormat = '';
/**
* True if debug lang is on.
*
* @var boolean
* @since 3.0
*/
private $debugLang = false;
/**
* Holds log entries handled by the plugin.
*
* @var array
* @since 3.1
*/
private $logEntries = array();
/**
* Holds SHOW PROFILES of queries.
*
* @var array
* @since 3.1.2
*/
private $sqlShowProfiles = array();
/**
* Holds all SHOW PROFILE FOR QUERY n, indexed by n-1.
*
* @var array
* @since 3.1.2
*/
private $sqlShowProfileEach = array();
/**
* Holds all EXPLAIN EXTENDED for all queries.
*
* @var array
* @since 3.1.2
*/
private $explains = array();
/**
* Holds total amount of executed queries.
*
* @var int
* @since 3.2
*/
private $totalQueries = 0;
/**
* Application object.
*
* @var JApplicationCms
* @since 3.3
*/
protected $app;
/**
* Database object.
*
* @var JDatabaseDriver
* @since 3.8.0
*/
protected $db;
/**
* Container for callback functions to be triggered when rendering the
console.
*
* @var callable[]
* @since 3.7.0
*/
private static $displayCallbacks = array();
/**
* Constructor.
*
* @param object &$subject The object to observe.
* @param array $config An optional associative array of
configuration settings.
*
* @since 1.5
*/
public function __construct(&$subject, $config)
{
parent::__construct($subject, $config);
// Log the deprecated API.
if ($this->params->get('log-deprecated', 0))
{
JLog::addLogger(array('text_file' =>
'deprecated.php'), JLog::ALL, array('deprecated'));
}
// Log everything (except deprecated APIs, these are logged separately
with the option above).
if ($this->params->get('log-everything', 0))
{
JLog::addLogger(array('text_file' =>
'everything.php'), JLog::ALL, array('deprecated',
'databasequery'), true);
}
// Get the application if not done by JPlugin. This may happen during
upgrades from Joomla 2.5.
if (!$this->app)
{
$this->app = JFactory::getApplication();
}
// Get the db if not done by JPlugin. This may happen during upgrades
from Joomla 2.5.
if (!$this->db)
{
$this->db = JFactory::getDbo();
}
$this->debugLang = $this->app->get('debug_lang');
// Skip the plugin if debug is off
if ($this->debugLang == '0' &&
$this->app->get('debug') == '0')
{
return;
}
// Only if debugging or language debug is enabled.
if (JDEBUG || $this->debugLang)
{
JFactory::getConfig()->set('gzip', 0);
ob_start();
ob_implicit_flush(false);
}
$this->linkFormat = ini_get('xdebug.file_link_format');
if ($this->params->get('logs', 1))
{
$priority = 0;
foreach ($this->params->get('log_priorities', array())
as $p)
{
$const = 'JLog::' . strtoupper($p);
if (!defined($const))
{
continue;
}
$priority |= constant($const);
}
// Split into an array at any character other than alphabet, numbers, _,
., or -
$categories = preg_split('/[^\w.-]+/',
$this->params->get('log_categories', ''), -1,
PREG_SPLIT_NO_EMPTY);
$mode = $this->params->get('log_category_mode',
0);
JLog::addLogger(array('logger' => 'callback',
'callback' => array($this, 'logger')), $priority,
$categories, $mode);
}
// Prepare disconnect handler for SQL profiling.
$db = $this->db;
$db->addDisconnectHandler(array($this,
'mysqlDisconnectHandler'));
// Log deprecated class aliases
foreach (JLoader::getDeprecatedAliases() as $deprecation)
{
JLog::add(
sprintf(
'%1$s has been aliased to %2$s and the former class name is
deprecated. The alias will be removed in %3$s.',
$deprecation['old'],
$deprecation['new'],
$deprecation['version']
),
JLog::WARNING,
'deprecated'
);
}
}
/**
* Add the CSS for debug.
* We can't do this in the constructor because stuff breaks.
*
* @return void
*
* @since 2.5
*/
public function onAfterDispatch()
{
// Only if debugging or language debug is enabled.
if ((JDEBUG || $this->debugLang) &&
$this->isAuthorisedDisplayDebug())
{
JHtml::_('stylesheet', 'cms/debug.css',
array('version' => 'auto', 'relative'
=> true));
}
// Disable asset media version if needed.
if (JDEBUG && (int)
$this->params->get('refresh_assets', 1) === 0)
{
$this->app->getDocument()->setMediaVersion(null);
}
// Only if debugging is enabled for SQL query popovers.
if (JDEBUG && $this->isAuthorisedDisplayDebug())
{
JHtml::_('bootstrap.tooltip');
JHtml::_('bootstrap.popover', '.hasPopover',
array('placement' => 'top'));
}
}
/**
* Show the debug info.
*
* @return void
*
* @since 1.6
*/
public function onAfterRespond()
{
// Do not render if debugging or language debug is not enabled.
if (!JDEBUG && !$this->debugLang)
{
return;
}
// User has to be authorised to see the debug information.
if (!$this->isAuthorisedDisplayDebug())
{
return;
}
// Only render for HTML output.
if (JFactory::getDocument()->getType() !== 'html')
{
return;
}
// Capture output.
$contents = ob_get_contents();
if ($contents)
{
ob_end_clean();
}
// No debug for Safari and Chrome redirection.
if (strpos($contents, '<html><head><meta
http-equiv="refresh" content="0;') === 0
&&
strpos(strtolower(isset($_SERVER['HTTP_USER_AGENT']) ?
$_SERVER['HTTP_USER_AGENT'] : ''), 'webkit')
!== false)
{
echo $contents;
return;
}
// Load language.
$this->loadLanguage();
$html = array();
// Some "mousewheel protecting" JS.
$html[] = "<script>function toggleContainer(name)
{
var e = document.getElementById(name);// MooTools might not be available
;)
e.style.display = e.style.display === 'none' ?
'block' : 'none';
}</script>";
$html[] = '<div id="system-debug"
class="profiler">';
$html[] = '<h2>' . JText::_('PLG_DEBUG_TITLE')
. '</h2>';
if (JDEBUG)
{
if (JError::getErrors())
{
$html[] = $this->display('errors');
}
if ($this->params->get('session', 1))
{
$html[] = $this->display('session');
}
if ($this->params->get('profile', 1))
{
$html[] = $this->display('profile_information');
}
if ($this->params->get('memory', 1))
{
$html[] = $this->display('memory_usage');
}
if ($this->params->get('queries', 1))
{
$html[] = $this->display('queries');
}
if (!empty($this->logEntries) &&
$this->params->get('logs', 1))
{
$html[] = $this->display('logs');
}
}
if ($this->debugLang)
{
if ($this->params->get('language_errorfiles', 1))
{
$languageErrors = JFactory::getLanguage()->getErrorFiles();
$html[] =
$this->display('language_files_in_error', $languageErrors);
}
if ($this->params->get('language_files', 1))
{
$html[] = $this->display('language_files_loaded');
}
if ($this->params->get('language_strings', 1))
{
$html[] = $this->display('untranslated_strings');
}
}
foreach (self::$displayCallbacks as $name => $callable)
{
$html[] = $this->displayCallback($name, $callable);
}
$html[] = '</div>';
echo str_replace('</body>', implode('', $html)
. '</body>', $contents);
}
/**
* Add a display callback to be rendered with the debug console.
*
* @param string $name The name of the callable, this is used to
generate the section title.
* @param callable $callable The callback function to be added.
*
* @return boolean
*
* @since 3.7.0
* @throws InvalidArgumentException
*/
public static function addDisplayCallback($name, $callable)
{
// TODO - When PHP 5.4 is the minimum the parameter should be typehinted
"callable" and this check removed
if (!is_callable($callable))
{
throw new InvalidArgumentException('A valid callback function must
be given.');
}
self::$displayCallbacks[$name] = $callable;
return true;
}
/**
* Remove a registered display callback
*
* @param string $name The name of the callable.
*
* @return boolean
*
* @since 3.7.0
*/
public static function removeDisplayCallback($name)
{
unset(self::$displayCallbacks[$name]);
return true;
}
/**
* Method to check if the current user is allowed to see the debug
information or not.
*
* @return boolean True if access is allowed.
*
* @since 3.0
*/
private function isAuthorisedDisplayDebug()
{
static $result = null;
if ($result !== null)
{
return $result;
}
// If the user is not allowed to view the output then end here.
$filterGroups = (array)
$this->params->get('filter_groups', array());
if (!empty($filterGroups))
{
$userGroups = JFactory::getUser()->get('groups');
if (!array_intersect($filterGroups, $userGroups))
{
$result = false;
return false;
}
}
$result = true;
return true;
}
/**
* General display method.
*
* @param string $item The item to display.
* @param array $errors Errors occurred during execution.
*
* @return string
*
* @since 2.5
*/
protected function display($item, array $errors = array())
{
$title = JText::_('PLG_DEBUG_' . strtoupper($item));
$status = '';
if (count($errors))
{
$status = ' dbg-error';
}
$fncName = 'display' . ucfirst(str_replace('_',
'', $item));
if (!method_exists($this, $fncName))
{
return __METHOD__ . ' -- Unknown method: ' . $fncName .
'<br />';
}
$html = array();
$js = "toggleContainer('dbg_container_" . $item .
"');";
$class = 'dbg-header' . $status;
$html[] = '<div class="' . $class . '"
onclick="' . $js . '"><a
href="javascript:void(0);"><h3>' . $title .
'</h3></a></div>';
// @todo set with js.. ?
$style = ' style="display: none;"';
$html[] = '<div ' . $style . '
class="dbg-container" id="dbg_container_' . $item .
'">';
$html[] = $this->$fncName();
$html[] = '</div>';
return implode('', $html);
}
/**
* Display method for callback functions.
*
* @param string $name The name of the callable.
* @param callable $callable The callable function.
*
* @return string
*
* @since 3.7.0
*/
protected function displayCallback($name, $callable)
{
$title = JText::_('PLG_DEBUG_' . strtoupper($name));
$html = array();
$js = "toggleContainer('dbg_container_" . $name .
"');";
$class = 'dbg-header';
$html[] = '<div class="' . $class . '"
onclick="' . $js . '"><a
href="javascript:void(0);"><h3>' . $title .
'</h3></a></div>';
// @todo set with js.. ?
$style = ' style="display: none;"';
$html[] = '<div ' . $style . '
class="dbg-container" id="dbg_container_' . $name .
'">';
$html[] = call_user_func($callable);
$html[] = '</div>';
return implode('', $html);
}
/**
* Display session information.
*
* Called recursively.
*
* @param string $key A session key.
* @param mixed $session The session array, initially null.
* @param integer $id Used to identify the DIV for the JavaScript
toggling code.
*
* @return string
*
* @since 2.5
*/
protected function displaySession($key = '', $session = null,
$id = 0)
{
if (!$session)
{
$session = JFactory::getSession()->getData();
}
$html = array();
static $id;
if (!is_array($session))
{
$html[] = $key . '<pre>' .
$this->prettyPrintJSON($session) . '</pre>' . PHP_EOL;
}
else
{
foreach ($session as $sKey => $entries)
{
$display = true;
if (is_array($entries) && $entries)
{
$display = false;
}
if (is_object($entries))
{
$o = ArrayHelper::fromObject($entries);
if ($o)
{
$entries = $o;
$display = false;
}
}
if (!$display)
{
$js = "toggleContainer('dbg_container_session" . $id .
'_' . $sKey . "');";
$html[] = '<div class="dbg-header"
onclick="' . $js . '"><a
href="javascript:void(0);"><h3>' . $sKey .
'</h3></a></div>';
// @todo set with js.. ?
$style = ' style="display: none;"';
$html[] = '<div ' . $style . '
class="dbg-container" id="dbg_container_session' . $id
. '_' . $sKey . '">';
$id++;
// Recurse...
$this->displaySession($sKey, $entries, $id);
$html[] = '</div>';
continue;
}
if (is_array($entries))
{
$entries = implode($entries);
}
if (is_string($entries))
{
$html[] = $sKey . '<pre>' .
$this->prettyPrintJSON($entries) . '</pre>' . PHP_EOL;
}
}
}
return implode('', $html);
}
/**
* Display errors.
*
* @return string
*
* @since 2.5
*/
protected function displayErrors()
{
$html = array();
$html[] = '<ol>';
while ($error = JError::getError(true))
{
$col = (E_WARNING == $error->get('level')) ?
'red' : 'orange';
$html[] = '<li>';
$html[] = '<b style="color: ' . $col .
'">' . $error->getMessage() . '</b><br
/>';
$info = $error->get('info');
if ($info)
{
$html[] = '<pre>' . print_r($info, true) .
'</pre><br />';
}
$html[] = $this->renderBacktrace($error);
$html[] = '</li>';
}
$html[] = '</ol>';
return implode('', $html);
}
/**
* Display profile information.
*
* @return string
*
* @since 2.5
*/
protected function displayProfileInformation()
{
$html = array();
$htmlMarks = array();
$totalTime = 0;
$totalMem = 0;
$marks = array();
$bars = array();
$barsMem = array();
foreach (JProfiler::getInstance('Application')->getMarks()
as $mark)
{
$totalTime += $mark->time;
$totalMem += (float) $mark->memory;
$htmlMark = sprintf(
JText::_('PLG_DEBUG_TIME') . ': <span
class="label label-time">%.2f ms</span> /
<span class="label
label-default">%.2f ms</span>'
. ' ' . JText::_('PLG_DEBUG_MEMORY') . ':
<span class="label label-memory">%0.3f MB</span> /
<span class="label label-default">%0.2f
MB</span>'
. ' %s: %s',
$mark->time,
$mark->totalTime,
$mark->memory,
$mark->totalMemory,
$mark->prefix,
$mark->label
);
$marks[] = (object) array(
'time' => $mark->time,
'memory' => $mark->memory,
'html' => $htmlMark,
'tip' => $mark->label,
);
}
$avgTime = $totalTime / max(count($marks), 1);
$avgMem = $totalMem / max(count($marks), 1);
foreach ($marks as $mark)
{
if ($mark->time > $avgTime * 1.5)
{
$barClass = 'bar-danger';
$labelClass = 'label-important label-danger';
}
elseif ($mark->time < $avgTime / 1.5)
{
$barClass = 'bar-success';
$labelClass = 'label-success';
}
else
{
$barClass = 'bar-warning';
$labelClass = 'label-warning';
}
if ($mark->memory > $avgMem * 1.5)
{
$barClassMem = 'bar-danger';
$labelClassMem = 'label-important label-danger';
}
elseif ($mark->memory < $avgMem / 1.5)
{
$barClassMem = 'bar-success';
$labelClassMem = 'label-success';
}
else
{
$barClassMem = 'bar-warning';
$labelClassMem = 'label-warning';
}
$barClass .= " progress-$barClass";
$barClassMem .= " progress-$barClassMem";
$bars[] = (object) array(
'width' => round($mark->time / ($totalTime / 100), 4),
'class' => $barClass,
'tip' => $mark->tip . ' ' .
round($mark->time, 2) . ' ms',
);
$barsMem[] = (object) array(
'width' => round((float) $mark->memory / ($totalMem /
100), 4),
'class' => $barClassMem,
'tip' => $mark->tip . ' ' .
round($mark->memory, 3) . ' MB',
);
$htmlMarks[] = '<div>' .
str_replace('label-time', $labelClass,
str_replace('label-memory', $labelClassMem, $mark->html)) .
'</div>';
}
$html[] = '<h4>' . JText::_('PLG_DEBUG_TIME') .
'</h4>';
$html[] = $this->renderBars($bars, 'profile');
$html[] = '<h4>' . JText::_('PLG_DEBUG_MEMORY')
. '</h4>';
$html[] = $this->renderBars($barsMem, 'profile');
$html[] = '<div class="dbg-profile-list">' .
implode('', $htmlMarks) . '</div>';
$db = $this->db;
// fix for support custom shutdown function via
register_shutdown_function().
$db->disconnect();
$log = $db->getLog();
if ($log)
{
$timings = $db->getTimings();
if ($timings)
{
$totalQueryTime = 0.0;
$lastStart = null;
foreach ($timings as $k => $v)
{
if (!($k % 2))
{
$lastStart = $v;
}
else
{
$totalQueryTime += $v - $lastStart;
}
}
$totalQueryTime *= 1000;
if ($totalQueryTime > ($totalTime * 0.25))
{
$labelClass = 'label-important';
}
elseif ($totalQueryTime < ($totalTime * 0.15))
{
$labelClass = 'label-success';
}
else
{
$labelClass = 'label-warning';
}
$html[] = '<br /><div>' . JText::sprintf(
'PLG_DEBUG_QUERIES_TIME',
sprintf('<span class="label ' . $labelClass .
'">%.2f ms</span>', $totalQueryTime)
) . '</div>';
if ($this->params->get('log-executed-sql', 0))
{
$this->writeToFile();
}
}
}
return implode('', $html);
}
/**
* Display memory usage.
*
* @return string
*
* @since 2.5
*/
protected function displayMemoryUsage()
{
$bytes = memory_get_usage();
return '<span class="label label-default">' .
JHtml::_('number.bytes', $bytes) . '</span>'
. ' (<span class="label label-default">'
. number_format($bytes, 0, JText::_('DECIMALS_SEPARATOR'),
JText::_('THOUSANDS_SEPARATOR'))
. ' '
. JText::_('PLG_DEBUG_BYTES')
. '</span>)';
}
/**
* Display logged queries.
*
* @return string
*
* @since 2.5
*/
protected function displayQueries()
{
$db = $this->db;
$log = $db->getLog();
if (!$log)
{
return null;
}
$timings = $db->getTimings();
$callStacks = $db->getCallStacks();
$db->setDebug(false);
$selectQueryTypeTicker = array();
$otherQueryTypeTicker = array();
$timing = array();
$maxtime = 0;
if (isset($timings[0]))
{
$startTime = $timings[0];
$endTime = $timings[count($timings) - 1];
$totalBargraphTime = $endTime - $startTime;
if ($totalBargraphTime > 0)
{
foreach ($log as $id => $query)
{
if (isset($timings[$id * 2 + 1]))
{
// Compute the query time: $timing[$k] = array( queryTime,
timeBetweenQueries ).
$timing[$id] = array(
($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000,
$id > 0 ? ($timings[$id * 2] - $timings[$id * 2 - 1]) * 1000 : 0,
);
$maxtime = max($maxtime, $timing[$id]['0']);
}
}
}
}
else
{
$startTime = null;
$totalBargraphTime = 1;
}
$bars = array();
$info = array();
$totalQueryTime = 0;
$duplicates = array();
foreach ($log as $id => $query)
{
$did = md5($query);
if (!isset($duplicates[$did]))
{
$duplicates[$did] = array();
}
$duplicates[$did][] = $id;
if ($timings && isset($timings[$id * 2 + 1]))
{
// Compute the query time.
$queryTime = ($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000;
$totalQueryTime += $queryTime;
// Run an EXPLAIN EXTENDED query on the SQL query if possible.
$hasWarnings = false;
$hasWarningsInProfile = false;
if (isset($this->explains[$id]))
{
$explain = $this->tableToHtml($this->explains[$id],
$hasWarnings);
}
else
{
$explain =
JText::sprintf('PLG_DEBUG_QUERY_EXPLAIN_NOT_POSSIBLE',
htmlspecialchars($query));
}
// Run a SHOW PROFILE query.
$profile = '';
if (isset($this->sqlShowProfileEach[$id]) &&
$db->getServerType() === 'mysql')
{
$profileTable = $this->sqlShowProfileEach[$id];
$profile = $this->tableToHtml($profileTable,
$hasWarningsInProfile);
}
// How heavy should the string length count: 0 - 1.
$ratio = 0.5;
$timeScore = $queryTime / ((strlen($query) + 1) * $ratio) * 200;
// Determine color of bargraph depending on query speed and presence of
warnings in EXPLAIN.
if ($timeScore > 10)
{
$barClass = 'bar-danger';
$labelClass = 'label-important';
}
elseif ($hasWarnings || $timeScore > 5)
{
$barClass = 'bar-warning';
$labelClass = 'label-warning';
}
else
{
$barClass = 'bar-success';
$labelClass = 'label-success';
}
// Computes bargraph as follows: Position begin and end of the bar
relatively to whole execution time.
// TODO: $prevBar is not used anywhere. Remove?
$prevBar = $id && isset($bars[$id - 1]) ? $bars[$id - 1] : 0;
$barPre = round($timing[$id][1] / ($totalBargraphTime * 10), 4);
$barWidth = round($timing[$id][0] / ($totalBargraphTime * 10), 4);
$minWidth = 0.3;
if ($barWidth < $minWidth)
{
$barPre -= ($minWidth - $barWidth);
if ($barPre < 0)
{
$minWidth += $barPre;
$barPre = 0;
}
$barWidth = $minWidth;
}
$bars[$id] = (object) array(
'class' => $barClass,
'width' => $barWidth,
'pre' => $barPre,
'tip' => sprintf('%.2f ms', $queryTime),
);
$info[$id] = (object) array(
'class' => $labelClass,
'explain' => $explain,
'profile' => $profile,
'hasWarnings' => $hasWarnings,
);
}
}
// Remove single queries from $duplicates.
$total_duplicates = 0;
foreach ($duplicates as $did => $dups)
{
if (count($dups) < 2)
{
unset($duplicates[$did]);
}
else
{
$total_duplicates += count($dups);
}
}
// Fix first bar width.
$minWidth = 0.3;
if ($bars[0]->width < $minWidth && isset($bars[1]))
{
$bars[1]->pre -= ($minWidth - $bars[0]->width);
if ($bars[1]->pre < 0)
{
$minWidth += $bars[1]->pre;
$bars[1]->pre = 0;
}
$bars[0]->width = $minWidth;
}
$memoryUsageNow = memory_get_usage();
$list = array();
foreach ($log as $id => $query)
{
// Start query type ticker additions.
$fromStart = stripos($query, 'from');
$whereStart = stripos($query, 'where', $fromStart);
if ($whereStart === false)
{
$whereStart = stripos($query, 'order by', $fromStart);
}
if ($whereStart === false)
{
$whereStart = strlen($query) - 1;
}
$fromString = substr($query, 0, $whereStart);
$fromString = str_replace(array("\t", "\n"), '
', $fromString);
$fromString = trim($fromString);
// Initialise the select/other query type counts the first time.
if (!isset($selectQueryTypeTicker[$fromString]))
{
$selectQueryTypeTicker[$fromString] = 0;
}
if (!isset($otherQueryTypeTicker[$fromString]))
{
$otherQueryTypeTicker[$fromString] = 0;
}
// Increment the count.
if (stripos($query, 'select') === 0)
{
$selectQueryTypeTicker[$fromString]++;
unset($otherQueryTypeTicker[$fromString]);
}
else
{
$otherQueryTypeTicker[$fromString]++;
unset($selectQueryTypeTicker[$fromString]);
}
$text = $this->highlightQuery($query);
if ($timings && isset($timings[$id * 2 + 1]))
{
// Compute the query time.
$queryTime = ($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000;
// Timing
// Formats the output for the query time with EXPLAIN query results as
tooltip:
$htmlTiming = '<div style="margin: 0 0
5px;"><span class="dbg-query-time">';
$htmlTiming .= JText::sprintf(
'PLG_DEBUG_QUERY_TIME',
sprintf(
'<span class="label
%s">%.2f ms</span>',
$info[$id]->class,
$timing[$id]['0']
)
);
if ($timing[$id]['1'])
{
$htmlTiming .= ' ' . JText::sprintf(
'PLG_DEBUG_QUERY_AFTER_LAST',
sprintf('<span class="label
label-default">%.2f ms</span>',
$timing[$id]['1'])
);
}
$htmlTiming .= '</span>';
if (isset($callStacks[$id][0]['memory']))
{
$memoryUsed = $callStacks[$id][0]['memory'][1] -
$callStacks[$id][0]['memory'][0];
$memoryBeforeQuery = $callStacks[$id][0]['memory'][0];
// Determine colour of query memory usage.
if ($memoryUsed > 0.1 * $memoryUsageNow)
{
$labelClass = 'label-important';
}
elseif ($memoryUsed > 0.05 * $memoryUsageNow)
{
$labelClass = 'label-warning';
}
else
{
$labelClass = 'label-success';
}
$htmlTiming .= ' ' . '<span
class="dbg-query-memory">'
. JText::sprintf(
'PLG_DEBUG_MEMORY_USED_FOR_QUERY',
sprintf('<span class="label ' . $labelClass .
'">%.3f MB</span>', $memoryUsed /
1048576),
sprintf('<span class="label
label-default">%.3f MB</span>',
$memoryBeforeQuery / 1048576)
)
. '</span>';
if ($callStacks[$id][0]['memory'][2] !== null)
{
// Determine colour of number or results.
$resultsReturned = $callStacks[$id][0]['memory'][2];
if ($resultsReturned > 3000)
{
$labelClass = 'label-important';
}
elseif ($resultsReturned > 1000)
{
$labelClass = 'label-warning';
}
elseif ($resultsReturned == 0)
{
$labelClass = '';
}
else
{
$labelClass = 'label-success';
}
$htmlResultsReturned = '<span class="label ' .
$labelClass . '">' . (int) $resultsReturned .
'</span>';
$htmlTiming .= ' <span
class="dbg-query-rowsnumber">'
. JText::sprintf('PLG_DEBUG_ROWS_RETURNED_BY_QUERY',
$htmlResultsReturned) . '</span>';
}
}
$htmlTiming .= '</div>';
// Bar.
$htmlBar = $this->renderBars($bars, 'query', $id);
// Profile query.
$title = JText::_('PLG_DEBUG_PROFILE');
if (!$info[$id]->profile)
{
$title = '<span class="dbg-noprofile">' .
$title . '</span>';
}
$htmlProfile = $info[$id]->profile ?:
JText::_('PLG_DEBUG_NO_PROFILE');
$htmlAccordions = JHtml::_(
'bootstrap.startAccordion', 'dbg_query_' . $id,
array(
'active' => $info[$id]->hasWarnings ?
('dbg_query_explain_' . $id) : '',
)
);
$htmlAccordions .= JHtml::_('bootstrap.addSlide',
'dbg_query_' . $id, JText::_('PLG_DEBUG_EXPLAIN'),
'dbg_query_explain_' . $id)
. $info[$id]->explain
. JHtml::_('bootstrap.endSlide');
$htmlAccordions .= JHtml::_('bootstrap.addSlide',
'dbg_query_' . $id, $title, 'dbg_query_profile_' . $id)
. $htmlProfile
. JHtml::_('bootstrap.endSlide');
// Call stack and back trace.
if (isset($callStacks[$id]))
{
$htmlAccordions .= JHtml::_('bootstrap.addSlide',
'dbg_query_' . $id, JText::_('PLG_DEBUG_CALL_STACK'),
'dbg_query_callstack_' . $id)
. $this->renderCallStack($callStacks[$id])
. JHtml::_('bootstrap.endSlide');
}
$htmlAccordions .= JHtml::_('bootstrap.endAccordion');
$did = md5($query);
if (isset($duplicates[$did]))
{
$dups = array();
foreach ($duplicates[$did] as $dup)
{
if ($dup != $id)
{
$dups[] = '<a class="alert-link"
href="#dbg-query-' . ($dup + 1) . '">#' . ($dup
+ 1) . '</a>';
}
}
$htmlQuery = '<div class="alert
alert-error">' .
JText::_('PLG_DEBUG_QUERY_DUPLICATES') . ': ' .
implode(' ', $dups) . '</div>'
. '<pre class="alert" title="' .
htmlspecialchars(JText::_('PLG_DEBUG_QUERY_DUPLICATES_FOUND'),
ENT_COMPAT, 'UTF-8') . '">' . $text .
'</pre>';
}
else
{
$htmlQuery = '<pre>' . $text .
'</pre>';
}
$list[] = '<a name="dbg-query-' . ($id + 1) .
'"></a>'
. $htmlTiming
. $htmlBar
. $htmlQuery
. $htmlAccordions;
}
else
{
$list[] = '<pre>' . $text . '</pre>';
}
}
$totalTime = 0;
foreach (JProfiler::getInstance('Application')->getMarks()
as $mark)
{
$totalTime += $mark->time;
}
if ($totalQueryTime > ($totalTime * 0.25))
{
$labelClass = 'label-important';
}
elseif ($totalQueryTime < ($totalTime * 0.15))
{
$labelClass = 'label-success';
}
else
{
$labelClass = 'label-warning';
}
if ($this->totalQueries === 0)
{
$this->totalQueries = $db->getCount();
}
$html = array();
$html[] = '<h4>' .
JText::sprintf('PLG_DEBUG_QUERIES_LOGGED',
$this->totalQueries)
. sprintf(' <span class="label ' . $labelClass .
'">%.2f ms</span>', $totalQueryTime) .
'</h4><br />';
if ($total_duplicates)
{
$html[] = '<div class="alert alert-error">'
. '<h4>' .
JText::sprintf('PLG_DEBUG_QUERY_DUPLICATES_TOTAL_NUMBER',
$total_duplicates) . '</h4>';
foreach ($duplicates as $dups)
{
$links = array();
foreach ($dups as $dup)
{
$links[] = '<a class="alert-link"
href="#dbg-query-' . ($dup + 1) . '">#' . ($dup
+ 1) . '</a>';
}
$html[] = '<div>' .
JText::sprintf('PLG_DEBUG_QUERY_DUPLICATES_NUMBER',
count($links)) . ': ' . implode(' ', $links)
. '</div>';
}
$html[] = '</div>';
}
$html[] = '<ol><li>' . implode('<hr
/></li><li>', $list) . '<hr
/></li></ol>';
if (!$this->params->get('query_types', 1))
{
return implode('', $html);
}
// Get the totals for the query types.
$totalSelectQueryTypes = count($selectQueryTypeTicker);
$totalOtherQueryTypes = count($otherQueryTypeTicker);
$totalQueryTypes = $totalSelectQueryTypes + $totalOtherQueryTypes;
$html[] = '<h4>' .
JText::sprintf('PLG_DEBUG_QUERY_TYPES_LOGGED', $totalQueryTypes)
. '</h4>';
if ($totalSelectQueryTypes)
{
$html[] = '<h5>' .
JText::_('PLG_DEBUG_SELECT_QUERIES') . '</h5>';
arsort($selectQueryTypeTicker);
$list = array();
foreach ($selectQueryTypeTicker as $query => $occurrences)
{
$list[] = '<pre>'
. JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES',
$this->highlightQuery($query), $occurrences)
. '</pre>';
}
$html[] = '<ol><li>' .
implode('</li><li>', $list) .
'</li></ol>';
}
if ($totalOtherQueryTypes)
{
$html[] = '<h5>' .
JText::_('PLG_DEBUG_OTHER_QUERIES') . '</h5>';
arsort($otherQueryTypeTicker);
$list = array();
foreach ($otherQueryTypeTicker as $query => $occurrences)
{
$list[] = '<pre>'
. JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES',
$this->highlightQuery($query), $occurrences)
. '</pre>';
}
$html[] = '<ol><li>' .
implode('</li><li>', $list) .
'</li></ol>';
}
return implode('', $html);
}
/**
* Render the bars.
*
* @param array &$bars Array of bar data
* @param string $class Optional class for items
* @param integer $id Id if the bar to highlight
*
* @return string
*
* @since 3.1.2
*/
protected function renderBars(&$bars, $class = '', $id =
null)
{
$html = array();
foreach ($bars as $i => $bar)
{
if (isset($bar->pre) && $bar->pre)
{
$html[] = '<div class="dbg-bar-spacer"
style="width:' . $bar->pre .
'%;"></div>';
}
$barClass = trim('bar dbg-bar progress-bar ' .
(isset($bar->class) ? $bar->class : ''));
if ($id !== null && $i == $id)
{
$barClass .= ' dbg-bar-active';
}
$tip = empty($bar->tip) ? '' : ' title="' .
htmlspecialchars($bar->tip, ENT_COMPAT, 'UTF-8') .
'"';
$html[] = '<a class="bar dbg-bar ' . $barClass .
'"' . $tip . ' style="width: '
. $bar->width . '%;" href="#dbg-' . $class .
'-' . ($i + 1) . '"></a>';
}
return '<div class="progress dbg-bars dbg-bars-' .
$class . '">' . implode('', $html) .
'</div>';
}
/**
* Render an HTML table based on a multi-dimensional array.
*
* @param array $table An array of tabular data.
* @param boolean &$hasWarnings Changes value to true if warnings
are displayed, otherwise untouched
*
* @return string
*
* @since 3.1.2
*/
protected function tableToHtml($table, &$hasWarnings)
{
if (!$table)
{
return null;
}
$html = array();
$html[] = '<table class="table table-striped
dbg-query-table">';
$html[] = '<thead>';
$html[] = '<tr>';
foreach (array_keys($table[0]) as $k)
{
$html[] = '<th>' . htmlspecialchars($k) .
'</th>';
}
$html[] = '</tr>';
$html[] = '</thead>';
$html[] = '<tbody>';
$durations = array();
foreach ($table as $tr)
{
if (isset($tr['Duration']))
{
$durations[] = $tr['Duration'];
}
}
rsort($durations, SORT_NUMERIC);
foreach ($table as $tr)
{
$html[] = '<tr>';
foreach ($tr as $k => $td)
{
if ($td === null)
{
// Display null's as 'NULL'.
$td = 'NULL';
}
// Treat special columns.
if ($k === 'Duration')
{
if ($td >= 0.001 && ($td == $durations[0] ||
(isset($durations[1]) && $td == $durations[1])))
{
// Duration column with duration value of more than 1 ms and within 2
top duration in SQL engine: Highlight warning.
$html[] = '<td class="dbg-warning">';
$hasWarnings = true;
}
else
{
$html[] = '<td>';
}
// Display duration in milliseconds with the unit instead of seconds.
$html[] = sprintf('%.2f ms', $td * 1000);
}
elseif ($k === 'Error')
{
// An error in the EXPLAIN query occurred, display it instead of the
result (means original query had syntax error most probably).
$html[] = '<td class="dbg-warning">' .
htmlspecialchars($td);
$hasWarnings = true;
}
elseif ($k === 'key')
{
if ($td === 'NULL')
{
// Displays query parts which don't use a key with warning:
$html[] = '<td><strong>' . '<span
class="dbg-warning" title="'
.
htmlspecialchars(JText::_('PLG_DEBUG_WARNING_NO_INDEX_DESC'),
ENT_COMPAT, 'UTF-8') . '">'
. JText::_('PLG_DEBUG_WARNING_NO_INDEX') .
'</span>' . '</strong>';
$hasWarnings = true;
}
else
{
$html[] = '<td><strong>' .
htmlspecialchars($td) . '</strong>';
}
}
elseif ($k === 'Extra')
{
$htmlTd = htmlspecialchars($td);
// Replace spaces with (non-breaking spaces) for less tall
tables displayed.
$htmlTd = preg_replace('/([^;]) /',
'\1 ', $htmlTd);
// Displays warnings for "Using filesort":
$htmlTdWithWarnings = str_replace(
'Using filesort',
'<span class="dbg-warning" title="'
.
htmlspecialchars(JText::_('PLG_DEBUG_WARNING_USING_FILESORT_DESC'),
ENT_COMPAT, 'UTF-8') . '">'
. JText::_('PLG_DEBUG_WARNING_USING_FILESORT') .
'</span>',
$htmlTd
);
if ($htmlTdWithWarnings !== $htmlTd)
{
$hasWarnings = true;
}
$html[] = '<td>' . $htmlTdWithWarnings;
}
else
{
$html[] = '<td>' . htmlspecialchars($td);
}
$html[] = '</td>';
}
$html[] = '</tr>';
}
$html[] = '</tbody>';
$html[] = '</table>';
return implode('', $html);
}
/**
* Disconnect handler for database to collect profiling and explain
information.
*
* @param JDatabaseDriver &$db Database object.
*
* @return void
*
* @since 3.1.2
*/
public function mysqlDisconnectHandler(&$db)
{
$db->setDebug(false);
$this->totalQueries = $db->getCount();
$dbVersion5037 = $db->getServerType() === 'mysql' &&
version_compare($db->getVersion(), '5.0.37',
'>=');
if ($dbVersion5037)
{
try
{
// Check if profiling is enabled.
$db->setQuery("SHOW VARIABLES LIKE
'have_profiling'");
$hasProfiling = $db->loadResult();
if ($hasProfiling)
{
// Run a SHOW PROFILE query.
$db->setQuery('SHOW PROFILES');
$this->sqlShowProfiles = $db->loadAssocList();
if ($this->sqlShowProfiles)
{
foreach ($this->sqlShowProfiles as $qn)
{
// Run SHOW PROFILE FOR QUERY for each query where a profile is
available (max 100).
$db->setQuery('SHOW PROFILE FOR QUERY ' . (int)
$qn['Query_ID']);
$this->sqlShowProfileEach[(int) ($qn['Query_ID'] - 1)]
= $db->loadAssocList();
}
}
}
else
{
$this->sqlShowProfileEach[0] = array(array('Error' =>
'MySql have_profiling = off'));
}
}
catch (Exception $e)
{
$this->sqlShowProfileEach[0] = array(array('Error' =>
$e->getMessage()));
}
}
if (in_array($db->getServerType(), array('mysql',
'postgresql'), true))
{
$log = $db->getLog();
foreach ($log as $k => $query)
{
$dbVersion56 = $db->getServerType() === 'mysql' &&
version_compare($db->getVersion(), '5.6', '>=');
$dbVersion80 = $db->getServerType() === 'mysql' &&
version_compare($db->getVersion(), '8.0', '>=');
if ($dbVersion80)
{
$dbVersion56 = false;
}
if ((stripos($query, 'select') === 0) || ($dbVersion56
&& ((stripos($query, 'delete') === 0) || (stripos($query,
'update') === 0))))
{
try
{
$db->setQuery('EXPLAIN ' . ($dbVersion56 ?
'EXTENDED ' : '') . $query);
$this->explains[$k] = $db->loadAssocList();
}
catch (Exception $e)
{
$this->explains[$k] = array(array('Error' =>
$e->getMessage()));
}
}
}
}
}
/**
* Displays errors in language files.
*
* @return string
*
* @since 2.5
*/
protected function displayLanguageFilesInError()
{
$errorfiles = JFactory::getLanguage()->getErrorFiles();
if (!count($errorfiles))
{
return '<p>' . JText::_('JNONE') .
'</p>';
}
$html = array();
$html[] = '<ul>';
foreach ($errorfiles as $file => $error)
{
$html[] = '<li>' . $this->formatLink($file) .
str_replace($file, '', $error) . '</li>';
}
$html[] = '</ul>';
return implode('', $html);
}
/**
* Display loaded language files.
*
* @return string
*
* @since 2.5
*/
protected function displayLanguageFilesLoaded()
{
$html = array();
$html[] = '<ul>';
foreach (JFactory::getLanguage()->getPaths() as /* $extension => */
$files)
{
foreach ($files as $file => $status)
{
$html[] = '<li>';
$html[] = $status
? JText::_('PLG_DEBUG_LANG_LOADED')
: JText::_('PLG_DEBUG_LANG_NOT_LOADED');
$html[] = ' : ';
$html[] = $this->formatLink($file);
$html[] = '</li>';
}
}
$html[] = '</ul>';
return implode('', $html);
}
/**
* Display untranslated language strings.
*
* @return string
*
* @since 2.5
*/
protected function displayUntranslatedStrings()
{
$stripFirst = $this->params->get('strip-first', 1);
$stripPref = $this->params->get('strip-prefix');
$stripSuff = $this->params->get('strip-suffix');
$orphans = JFactory::getLanguage()->getOrphans();
if (!count($orphans))
{
return '<p>' . JText::_('JNONE') .
'</p>';
}
ksort($orphans, SORT_STRING);
$guesses = array();
foreach ($orphans as $key => $occurance)
{
if (is_array($occurance) && isset($occurance[0]))
{
$info = $occurance[0];
$file = $info['file'] ?: '';
if (!isset($guesses[$file]))
{
$guesses[$file] = array();
}
// Prepare the key.
if (($pos = strpos($info['string'], '=')) > 0)
{
$parts = explode('=', $info['string']);
$key = $parts[0];
$guess = $parts[1];
}
else
{
$guess = str_replace('_', ' ',
$info['string']);
if ($stripFirst)
{
$parts = explode(' ', $guess);
if (count($parts) > 1)
{
array_shift($parts);
$guess = implode(' ', $parts);
}
}
$guess = trim($guess);
if ($stripPref)
{
$guess = trim(preg_replace(chr(1) . '^' . $stripPref .
chr(1) . 'i', '', $guess));
}
if ($stripSuff)
{
$guess = trim(preg_replace(chr(1) . $stripSuff . '$' .
chr(1) . 'i', '', $guess));
}
}
$key = strtoupper(trim($key));
$key = preg_replace('#\s+#', '_', $key);
$key = preg_replace('#\W#', '', $key);
// Prepare the text.
$guesses[$file][] = $key . '="' . $guess .
'"';
}
}
$html = array();
foreach ($guesses as $file => $keys)
{
$html[] = "\n\n# " . ($file ? $this->formatLink($file) :
JText::_('PLG_DEBUG_UNKNOWN_FILE')) . "\n\n";
$html[] = implode("\n", $keys);
}
return '<pre>' . implode('', $html) .
'</pre>';
}
/**
* Simple highlight for SQL queries.
*
* @param string $query The query to highlight.
*
* @return string
*
* @since 2.5
*/
protected function highlightQuery($query)
{
$newlineKeywords =
'#\b(FROM|LEFT|INNER|OUTER|WHERE|SET|VALUES|ORDER|GROUP|HAVING|LIMIT|ON|AND|CASE)\b#i';
$query = htmlspecialchars($query, ENT_QUOTES);
$query = preg_replace($newlineKeywords, '<br
/>  \\0', $query);
$regex = array(
// Tables are identified by the prefix.
'/(=)/' =>
'<b class="dbg-operator">$1</b>',
// All uppercase words have a special meaning.
'/(?<!\w|>)([A-Z_]{2,})(?!\w)/x' =>
'<span class="dbg-command">$1</span>',
// Tables are identified by the prefix.
'/(' . $this->db->getPrefix() . '[a-z_0-9]+)/'
=> '<span class="dbg-table">$1</span>',
);
$query = preg_replace(array_keys($regex), array_values($regex), $query);
$query = str_replace('*', '<b style="color:
red;">*</b>', $query);
return $query;
}
/**
* Render the backtrace.
*
* Stolen from JError to prevent it's removal.
*
* @param Exception $error The Exception object to be rendered.
*
* @return string Rendered backtrace.
*
* @since 2.5
*/
protected function renderBacktrace($error)
{
return JLayoutHelper::render('joomla.error.backtrace',
array('backtrace' => $error->getTrace()));
}
/**
* Replaces the Joomla! root with "JROOT" to improve
readability.
* Formats a link with a special value xdebug.file_link_format
* from the php.ini file.
*
* @param string $file The full path to the file.
* @param string $line The line number.
*
* @return string
*
* @since 2.5
*/
protected function formatLink($file, $line = '')
{
return JHtml::_('debug.xdebuglink', $file, $line);
}
/**
* Store log messages so they can be displayed later.
* This function is passed log entries by JLogLoggerCallback.
*
* @param JLogEntry $entry A log entry.
*
* @return void
*
* @since 3.1
*/
public function logger(JLogEntry $entry)
{
$this->logEntries[] = $entry;
}
/**
* Display log messages.
*
* @return string
*
* @since 3.1
*/
protected function displayLogs()
{
$priorities = array(
JLog::EMERGENCY => '<span class="badge
badge-important">EMERGENCY</span>',
JLog::ALERT => '<span class="badge
badge-important">ALERT</span>',
JLog::CRITICAL => '<span class="badge
badge-important">CRITICAL</span>',
JLog::ERROR => '<span class="badge
badge-important">ERROR</span>',
JLog::WARNING => '<span class="badge
badge-warning">WARNING</span>',
JLog::NOTICE => '<span class="badge
badge-info">NOTICE</span>',
JLog::INFO => '<span class="badge
badge-info">INFO</span>',
JLog::DEBUG => '<span
class="badge">DEBUG</span>',
);
$out = '';
$logEntriesTotal = count($this->logEntries);
// SQL log entries
$showExecutedSQL = $this->params->get('log-executed-sql',
0);
if (!$showExecutedSQL)
{
$logEntriesDatabasequery = count(
array_filter(
$this->logEntries, function ($logEntry)
{
return $logEntry->category === 'databasequery';
}
)
);
$logEntriesTotal -= $logEntriesDatabasequery;
}
// Deprecated log entries
$logEntriesDeprecated = count(
array_filter(
$this->logEntries, function ($logEntry)
{
return $logEntry->category === 'deprecated';
}
)
);
$showDeprecated =
$this->params->get('log-deprecated', 0);
if (!$showDeprecated)
{
$logEntriesTotal -= $logEntriesDeprecated;
}
$showEverything = $this->params->get('log-everything',
0);
$out .= '<h4>' .
JText::sprintf('PLG_DEBUG_LOGS_LOGGED', $logEntriesTotal) .
'</h4><br />';
if ($showDeprecated && $logEntriesDeprecated > 0)
{
$out .= '
<div class="alert alert-warning">
<h4>' .
JText::sprintf('PLG_DEBUG_LOGS_DEPRECATED_FOUND_TITLE',
$logEntriesDeprecated) . '</h4>
<div>' .
JText::_('PLG_DEBUG_LOGS_DEPRECATED_FOUND_TEXT') .
'</div>
</div>
<br />';
}
$out .= '<ol>';
$count = 1;
foreach ($this->logEntries as $entry)
{
// Don't show database queries if not selected.
if (!$showExecutedSQL && $entry->category ===
'databasequery')
{
continue;
}
// Don't show deprecated logs if not selected.
if (!$showDeprecated && $entry->category ===
'deprecated')
{
continue;
}
// Don't show everything logs if not selected.
if (!$showEverything && !in_array($entry->category,
array('deprecated', 'databasequery'), true))
{
continue;
}
$out .= '<li id="dbg_logs_' . $count .
'">';
$out .= '<h5>' . $priorities[$entry->priority] .
' ' . $entry->category . '</h5><br />
<pre>' . $entry->message . '</pre>';
if ($entry->callStack)
{
$out .= JHtml::_('bootstrap.startAccordion',
'dbg_logs_' . $count, array('active' =>
''));
$out .= JHtml::_('bootstrap.addSlide', 'dbg_logs_'
. $count, JText::_('PLG_DEBUG_CALL_STACK'),
'dbg_logs_backtrace_' . $count);
$out .= $this->renderCallStack($entry->callStack);
$out .= JHtml::_('bootstrap.endSlide');
$out .= JHtml::_('bootstrap.endAccordion');
}
$out .= '<hr /></li>';
$count++;
}
$out .= '</ol>';
return $out;
}
/**
* Renders call stack and back trace in HTML.
*
* @param array $callStack The call stack and back trace array.
*
* @return string The call stack and back trace in HMTL format.
*
* @since 3.5
*/
protected function renderCallStack(array $callStack = array())
{
$htmlCallStack = '';
if ($callStack !== null)
{
$htmlCallStack .= '<div>';
$htmlCallStack .= '<table class="table table-striped
dbg-query-table">';
$htmlCallStack .= '<thead>';
$htmlCallStack .= '<tr>';
$htmlCallStack .= '<th>#</th>';
$htmlCallStack .= '<th>' .
JText::_('PLG_DEBUG_CALL_STACK_CALLER') .
'</th>';
$htmlCallStack .= '<th>' .
JText::_('PLG_DEBUG_CALL_STACK_FILE_AND_LINE') .
'</th>';
$htmlCallStack .= '</tr>';
$htmlCallStack .= '</thead>';
$htmlCallStack .= '<tbody>';
$count = count($callStack);
foreach ($callStack as $call)
{
// Dont' back trace log classes.
if (isset($call['class']) &&
strpos($call['class'], 'JLog') !== false)
{
$count--;
continue;
}
$htmlCallStack .= '<tr>';
$htmlCallStack .= '<td>' . $count .
'</td>';
$htmlCallStack .= '<td>';
if (isset($call['class']))
{
// If entry has Class/Method print it.
$htmlCallStack .= htmlspecialchars($call['class'] .
$call['type'] . $call['function']) . '()';
}
else
{
if (isset($call['args']))
{
// If entry has args is a require/include.
$htmlCallStack .= htmlspecialchars($call['function']) .
' ' . $this->formatLink($call['args'][0]);
}
else
{
// It's a function.
$htmlCallStack .= htmlspecialchars($call['function']) .
'()';
}
}
$htmlCallStack .= '</td>';
$htmlCallStack .= '<td>';
// If entry doesn't have line and number the next is a
call_user_func.
if (!isset($call['file']) &&
!isset($call['line']))
{
$htmlCallStack .=
JText::_('PLG_DEBUG_CALL_STACK_SAME_FILE');
}
// If entry has file and line print it.
else
{
$htmlCallStack .=
$this->formatLink(htmlspecialchars($call['file']),
htmlspecialchars($call['line']));
}
$htmlCallStack .= '</td>';
$htmlCallStack .= '</tr>';
$count--;
}
$htmlCallStack .= '</tbody>';
$htmlCallStack .= '</table>';
$htmlCallStack .= '</div>';
if (!$this->linkFormat)
{
$htmlCallStack .= '<div>[<a
href="https://xdebug.org/docs/all_settings#file_link_format"
target="_blank" rel="noopener noreferrer">';
$htmlCallStack .= JText::_('PLG_DEBUG_LINK_FORMAT') .
'</a>]</div>';
}
}
return $htmlCallStack;
}
/**
* Pretty print JSON with colors.
*
* @param string $json The json raw string.
*
* @return string The json string pretty printed.
*
* @since 3.5
*/
protected function prettyPrintJSON($json = '')
{
// In PHP 5.4.0 or later we have pretty print option.
if (version_compare(PHP_VERSION, '5.4', '>='))
{
$json = json_encode($json, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
}
// Escape HTML in session vars
$json = htmlentities($json);
// Add some colors
$json = preg_replace('#"([^"]+)":#',
'<span class=\'black\'>"</span><span
class=\'green\'>$1</span><span
class=\'black\'>"</span>:', $json);
$json = preg_replace('#"(|[^"]+)"(\n|\r\n|,)#',
'<span
class=\'grey\'>"$1"</span>$2', $json);
$json = str_replace('null,', '<span
class=\'blue\'>null</span>,', $json);
return $json;
}
/**
* Write query to the log file
*
* @return void
*
* @since 3.5
*/
protected function writeToFile()
{
$app = JFactory::getApplication();
$domain = $app->isClient('site') ? 'site' :
'admin';
$input = $app->input;
$file = $app->get('log_path') . '/' . $domain .
'_' . $input->get('option') .
$input->get('view') . $input->get('layout') .
'.sql.php';
// Get the queries from log.
$current = '';
$db = $this->db;
$log = $db->getLog();
$timings = $db->getTimings();
foreach ($log as $id => $query)
{
if (isset($timings[$id * 2 + 1]))
{
$temp = str_replace('`', '', $log[$id]);
$temp = str_replace(array("\t", "\n",
"\r\n"), ' ', $temp);
$current .= $temp . ";\n";
}
}
if (JFile::exists($file))
{
JFile::delete($file);
}
$head = array('#');
$head[] = '#<?php die(\'Forbidden.\'); ?>';
$head[] = '#Date: ' . gmdate('Y-m-d H:i:s') . '
UTC';
$head[] = '#Software: ' . \JPlatform::getLongVersion();
$head[] = "\n";
// Write new file.
JFile::write($file, implode("\n", $head) . $current);
}
}
PK|��[�i�>>debug/debug.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_debug</name>
<author>Joomla! Project</author>
<creationDate>December 2006</creationDate>
<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_DEBUG_XML_DESCRIPTION</description>
<files>
<filename plugin="debug">debug.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_debug.ini</language>
<language
tag="en-GB">en-GB.plg_system_debug.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="filter_groups"
type="usergrouplist"
label="PLG_DEBUG_FIELD_ALLOWED_GROUPS_LABEL"
description="PLG_DEBUG_FIELD_ALLOWED_GROUPS_DESC"
multiple="true"
filter="int_array"
size="10"
/>
<field
name="session"
type="radio"
label="PLG_DEBUG_FIELD_SESSION_LABEL"
description="PLG_DEBUG_FIELD_SESSION_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="profile"
type="radio"
label="PLG_DEBUG_FIELD_PROFILING_LABEL"
description="PLG_DEBUG_FIELD_PROFILING_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="queries"
type="radio"
label="PLG_DEBUG_FIELD_QUERIES_LABEL"
description="PLG_DEBUG_FIELD_QUERIES_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="query_types"
type="radio"
label="PLG_DEBUG_FIELD_QUERY_TYPES_LABEL"
description="PLG_DEBUG_FIELD_QUERY_TYPES_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="memory"
type="radio"
label="PLG_DEBUG_FIELD_MEMORY_LABEL"
description="PLG_DEBUG_FIELD_MEMORY_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="logs"
type="radio"
label="PLG_DEBUG_FIELD_LOGS_LABEL"
description="PLG_DEBUG_FIELD_LOGS_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="log_priorities"
type="list"
label="PLG_DEBUG_FIELD_LOG_PRIORITIES_LABEL"
description="PLG_DEBUG_FIELD_LOG_PRIORITIES_DESC"
multiple="true"
default="all"
>
<option
value="all">PLG_DEBUG_FIELD_LOG_PRIORITIES_ALL</option>
<option
value="emergency">PLG_DEBUG_FIELD_LOG_PRIORITIES_EMERGENCY</option>
<option
value="alert">PLG_DEBUG_FIELD_LOG_PRIORITIES_ALERT</option>
<option
value="critical">PLG_DEBUG_FIELD_LOG_PRIORITIES_CRITICAL</option>
<option
value="error">PLG_DEBUG_FIELD_LOG_PRIORITIES_ERROR</option>
<option
value="warning">PLG_DEBUG_FIELD_LOG_PRIORITIES_WARNING</option>
<option
value="notice">PLG_DEBUG_FIELD_LOG_PRIORITIES_NOTICE</option>
<option
value="info">PLG_DEBUG_FIELD_LOG_PRIORITIES_INFO</option>
<option
value="debug">PLG_DEBUG_FIELD_LOG_PRIORITIES_DEBUG</option>
</field>
<field
name="log_categories"
type="text"
label="PLG_DEBUG_FIELD_LOG_CATEGORIES_LABEL"
description="PLG_DEBUG_FIELD_LOG_CATEGORIES_DESC"
size="60"
/>
<field
name="log_category_mode"
type="radio"
label="PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_LABEL"
description="PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_DESC"
default="0"
filter="integer"
class="btn-group btn-group-yesno btn-group-reversed"
>
<option
value="0">PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_INCLUDE</option>
<option
value="1">PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_EXCLUDE</option>
</field>
<field
name="refresh_assets"
type="radio"
label="PLG_DEBUG_FIELD_REFRESH_ASSETS_LABEL"
description="PLG_DEBUG_FIELD_REFRESH_ASSETS_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
</fieldset>
<fieldset
name="language"
label="PLG_DEBUG_LANGUAGE_FIELDSET_LABEL"
>
<field
name="language_errorfiles"
type="radio"
label="PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_LABEL"
description="PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="language_files"
type="radio"
label="PLG_DEBUG_FIELD_LANGUAGE_FILES_LABEL"
description="PLG_DEBUG_FIELD_LANGUAGE_FILES_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="language_strings"
type="radio"
label="PLG_DEBUG_FIELD_LANGUAGE_STRING_LABEL"
description="PLG_DEBUG_FIELD_LANGUAGE_STRING_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="strip-first"
type="radio"
label="PLG_DEBUG_FIELD_STRIP_FIRST_LABEL"
description="PLG_DEBUG_FIELD_STRIP_FIRST_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="strip-prefix"
type="textarea"
label="PLG_DEBUG_FIELD_STRIP_PREFIX_LABEL"
description="PLG_DEBUG_FIELD_STRIP_PREFIX_DESC"
cols="30"
rows="4"
/>
<field
name="strip-suffix"
type="textarea"
label="PLG_DEBUG_FIELD_STRIP_SUFFIX_LABEL"
description="PLG_DEBUG_FIELD_STRIP_SUFFIX_DESC"
cols="30"
rows="4"
/>
</fieldset>
<fieldset
name="logging"
label="PLG_DEBUG_LOGGING_FIELDSET_LABEL"
>
<field
name="log-deprecated"
type="radio"
label="PLG_DEBUG_FIELD_LOG_DEPRECATED_LABEL"
description="PLG_DEBUG_FIELD_LOG_DEPRECATED_DESC"
class="btn-group btn-group-yesno"
default="0"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="log-everything"
type="radio"
label="PLG_DEBUG_FIELD_LOG_EVERYTHING_LABEL"
description="PLG_DEBUG_FIELD_LOG_EVERYTHING_DESC"
class="btn-group btn-group-yesno"
default="0"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="log-executed-sql"
type="radio"
label="PLG_DEBUG_FIELD_EXECUTEDSQL_LABEL"
description="PLG_DEBUG_FIELD_EXECUTEDSQL_DESC"
class="btn-group btn-group-yesno"
default="0"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
</fieldset>
</fields>
</config>
</extension>
PK|��[��W8�2�2fields/fields.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.Fields
*
* @copyright (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Form\Form;
use Joomla\Registry\Registry;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Multilanguage;
JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR .
'/components/com_fields/helpers/fields.php');
/**
* Fields Plugin
*
* @since 3.7
*/
class PlgSystemFields extends JPlugin
{
/**
* Load the language file on instantiation.
*
* @var boolean
* @since 3.7.0
*/
protected $autoloadLanguage = true;
/**
* Normalizes the request data.
*
* @param string $context The context
* @param object $data The object
* @param Form $form The form
*
* @return void
*
* @since 3.8.7
*/
public function onContentNormaliseRequestData($context, $data, Form $form)
{
if (!FieldsHelper::extract($context, $data))
{
return true;
}
// Loop over all fields
foreach ($form->getGroup('com_fields') as $field)
{
if ($field->disabled === true)
{
/**
* Disabled fields should NEVER be added to the request as
* they should NEVER be added by the browser anyway so nothing to check
against
* as "disabled" means no interaction at all.
*/
// Make sure the data object has an entry before delete it
if (isset($data->com_fields[$field->fieldname]))
{
unset($data->com_fields[$field->fieldname]);
}
continue;
}
// Make sure the data object has an entry
if (isset($data->com_fields[$field->fieldname]))
{
continue;
}
// Set a default value for the field
$data->com_fields[$field->fieldname] = false;
}
}
/**
* The save event.
*
* @param string $context The context
* @param JTable $item The table
* @param boolean $isNew Is new item
* @param array $data The validated data
*
* @return boolean
*
* @since 3.7.0
*/
public function onContentAfterSave($context, $item, $isNew, $data =
array())
{
// Check if data is an array and the item has an id
if (!is_array($data) || empty($item->id) ||
empty($data['com_fields']))
{
return true;
}
// Create correct context for category
if ($context == 'com_categories.category')
{
$context = $item->extension . '.categories';
// Set the catid on the category to get only the fields which belong to
this category
$item->catid = $item->id;
}
// Check the context
$parts = FieldsHelper::extract($context, $item);
if (!$parts)
{
return true;
}
// Compile the right context for the fields
$context = $parts[0] . '.' . $parts[1];
// Loading the fields
$fields = FieldsHelper::getFields($context, $item);
if (!$fields)
{
return true;
}
// Loading the model
$model = JModelLegacy::getInstance('Field',
'FieldsModel', array('ignore_request' => true));
// Loop over the fields
foreach ($fields as $field)
{
// Determine the value if it is (un)available from the data
if (key_exists($field->name, $data['com_fields']))
{
$value = $data['com_fields'][$field->name] === false ?
null : $data['com_fields'][$field->name];
}
// Field not available on form, use stored value
else
{
$value = $field->rawvalue;
}
// If no value set (empty) remove value from database
if (is_array($value) ? !count($value) : !strlen($value))
{
$value = null;
}
// JSON encode value for complex fields
if (is_array($value) && (count($value, COUNT_NORMAL) !==
count($value, COUNT_RECURSIVE) || !count(array_filter(array_keys($value),
'is_numeric'))))
{
$value = json_encode($value);
}
// Setting the value for the field and the item
$model->setFieldValue($field->id, $item->id, $value);
}
return true;
}
/**
* The save event.
*
* @param array $userData The date
* @param boolean $isNew Is new
* @param boolean $success Is success
* @param string $msg The message
*
* @return boolean
*
* @since 3.7.0
*/
public function onUserAfterSave($userData, $isNew, $success, $msg)
{
// It is not possible to manipulate the user during save events
// Check if data is valid or we are in a recursion
if (!$userData['id'] || !$success)
{
return true;
}
$user = JFactory::getUser($userData['id']);
$task =
JFactory::getApplication()->input->getCmd('task');
// Skip fields save when we activate a user, because we will lose the
saved data
if (in_array($task, array('activate', 'block',
'unblock')))
{
return true;
}
// Trigger the events with a real user
$this->onContentAfterSave('com_users.user', $user, false,
$userData);
return true;
}
/**
* The delete event.
*
* @param string $context The context
* @param stdClass $item The item
*
* @return boolean
*
* @since 3.7.0
*/
public function onContentAfterDelete($context, $item)
{
$parts = FieldsHelper::extract($context, $item);
if (!$parts || empty($item->id))
{
return true;
}
$context = $parts[0] . '.' . $parts[1];
JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_fields/models', 'FieldsModel');
$model = JModelLegacy::getInstance('Field',
'FieldsModel', array('ignore_request' => true));
$model->cleanupValues($context, $item->id);
return true;
}
/**
* The user delete event.
*
* @param stdClass $user The context
* @param boolean $succes Is success
* @param string $msg The message
*
* @return boolean
*
* @since 3.7.0
*/
public function onUserAfterDelete($user, $succes, $msg)
{
$item = new stdClass;
$item->id = $user['id'];
return $this->onContentAfterDelete('com_users.user', $item);
}
/**
* The form event.
*
* @param JForm $form The form
* @param stdClass $data The data
*
* @return boolean
*
* @since 3.7.0
*/
public function onContentPrepareForm(JForm $form, $data)
{
$context = $form->getName();
// When a category is edited, the context is
com_categories.categorycom_content
if (strpos($context, 'com_categories.category') === 0)
{
$context = str_replace('com_categories.category',
'', $context) . '.categories';
// Set the catid on the category to get only the fields which belong to
this category
if (is_array($data) && key_exists('id', $data))
{
$data['catid'] = $data['id'];
}
if (is_object($data) && isset($data->id))
{
$data->catid = $data->id;
}
}
$parts = FieldsHelper::extract($context, $form);
if (!$parts)
{
return true;
}
$input = JFactory::getApplication()->input;
// If we are on the save command we need the actual data
$jformData = $input->get('jform', array(),
'array');
if ($jformData && !$data)
{
$data = $jformData;
}
if (is_array($data))
{
$data = (object) $data;
}
FieldsHelper::prepareForm($parts[0] . '.' . $parts[1], $form,
$data);
return true;
}
/**
* The display event.
*
* @param string $context The context
* @param stdClass $item The item
* @param Registry $params The params
* @param integer $limitstart The start
*
* @return string
*
* @since 3.7.0
*/
public function onContentAfterTitle($context, $item, $params, $limitstart
= 0)
{
return $this->display($context, $item, $params, 1);
}
/**
* The display event.
*
* @param string $context The context
* @param stdClass $item The item
* @param Registry $params The params
* @param integer $limitstart The start
*
* @return string
*
* @since 3.7.0
*/
public function onContentBeforeDisplay($context, $item, $params,
$limitstart = 0)
{
return $this->display($context, $item, $params, 2);
}
/**
* The display event.
*
* @param string $context The context
* @param stdClass $item The item
* @param Registry $params The params
* @param integer $limitstart The start
*
* @return string
*
* @since 3.7.0
*/
public function onContentAfterDisplay($context, $item, $params,
$limitstart = 0)
{
return $this->display($context, $item, $params, 3);
}
/**
* Performs the display event.
*
* @param string $context The context
* @param stdClass $item The item
* @param Registry $params The params
* @param integer $displayType The type
*
* @return string
*
* @since 3.7.0
*/
private function display($context, $item, $params, $displayType)
{
$parts = FieldsHelper::extract($context, $item);
if (!$parts)
{
return '';
}
// If we have a category, set the catid field to fetch only the fields
which belong to it
if ($parts[1] == 'categories' &&
!isset($item->catid))
{
$item->catid = $item->id;
}
$context = $parts[0] . '.' . $parts[1];
// Convert tags
if ($context == 'com_tags.tag' &&
!empty($item->type_alias))
{
// Set the context
$context = $item->type_alias;
$item = $this->prepareTagItem($item);
}
if (is_string($params) || !$params)
{
$params = new Registry($params);
}
$fields = FieldsHelper::getFields($context, $item, $displayType);
if ($fields)
{
$app = Factory::getApplication();
if ($app->isClient('site') &&
Multilanguage::isEnabled() && isset($item->language) &&
$item->language == '*')
{
$lang = $app->getLanguage()->getTag();
foreach ($fields as $key => $field)
{
if ($field->language == '*' || $field->language ==
$lang)
{
continue;
}
unset($fields[$key]);
}
}
}
if ($fields)
{
foreach ($fields as $key => $field)
{
$fieldDisplayType = $field->params->get('display',
'2');
if ($fieldDisplayType == $displayType)
{
continue;
}
unset($fields[$key]);
}
}
if ($fields)
{
return FieldsHelper::render(
$context,
'fields.render',
array(
'item' => $item,
'context' => $context,
'fields' => $fields
)
);
}
return '';
}
/**
* Performs the display event.
*
* @param string $context The context
* @param stdClass $item The item
*
* @return void
*
* @since 3.7.0
*/
public function onContentPrepare($context, $item)
{
// Check property exists (avoid costly & useless recreation), if need
to recreate them, just unset the property!
if (isset($item->jcfields))
{
return;
}
$parts = FieldsHelper::extract($context, $item);
if (!$parts)
{
return;
}
$context = $parts[0] . '.' . $parts[1];
// Convert tags
if ($context == 'com_tags.tag' &&
!empty($item->type_alias))
{
// Set the context
$context = $item->type_alias;
$item = $this->prepareTagItem($item);
}
// Get item's fields, also preparing their value property for manual
display
// (calling plugins events and loading layouts to get their HTML display)
$fields = FieldsHelper::getFields($context, $item, true);
// Adding the fields to the object
$item->jcfields = array();
foreach ($fields as $key => $field)
{
$item->jcfields[$field->id] = $field;
}
}
/**
* The finder event.
*
* @param stdClass $item The item
*
* @return boolean
*
* @since 3.7.0
*/
public function onPrepareFinderContent($item)
{
$section = strtolower($item->layout);
$tax = $item->getTaxonomy('Type');
if ($tax)
{
foreach ($tax as $context => $value)
{
// This is only a guess, needs to be improved
$component = strtolower($context);
if (strpos($context, 'com_') !== 0)
{
$component = 'com_' . $component;
}
// Transform com_article to com_content
if ($component === 'com_article')
{
$component = 'com_content';
}
// Create a dummy object with the required fields
$tmp = new stdClass;
$tmp->id = $item->__get('id');
if ($item->__get('catid'))
{
$tmp->catid = $item->__get('catid');
}
// Getting the fields for the constructed context
$fields = FieldsHelper::getFields($component . '.' .
$section, $tmp, true);
if (is_array($fields))
{
foreach ($fields as $field)
{
// Adding the instructions how to handle the text
$item->addInstruction(FinderIndexer::TEXT_CONTEXT,
$field->name);
// Adding the field value as a field
$item->{$field->name} = $field->value;
}
}
}
}
return true;
}
/**
* Prepares a tag item to be ready for com_fields.
*
* @param stdClass $item The item
*
* @return object
*
* @since 3.8.4
*/
private function prepareTagItem($item)
{
// Map core fields
$item->id = $item->content_item_id;
$item->language = $item->core_language;
// Also handle the catid
if (!empty($item->core_catid))
{
$item->catid = $item->core_catid;
}
return $item;
}
}
PK|��[W���fields/fields.xmlnu�[���<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="system" method="upgrade">
<name>plg_system_fields</name>
<author>Joomla! Project</author>
<creationDate>March 2016</creationDate>
<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.7.0</version>
<description>PLG_SYSTEM_FIELDS_XML_DESCRIPTION</description>
<files>
<filename plugin="fields">fields.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_fields.ini</language>
<language
tag="en-GB">en-GB.plg_system_fields.sys.ini</language>
</languages>
</extension>
PK|��[#�K<<highlight/highlight.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.Highlight
*
* @copyright (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* System plugin to highlight terms.
*
* @since 2.5
*/
class PlgSystemHighlight extends JPlugin
{
/**
* Method to catch the onAfterDispatch event.
*
* This is where we setup the click-through content highlighting for.
* The highlighting is done with JavaScript so we just
* need to check a few parameters and the JHtml behavior will do the rest.
*
* @return boolean True on success
*
* @since 2.5
*/
public function onAfterDispatch()
{
// Check that we are in the site application.
if (JFactory::getApplication()->isClient('administrator'))
{
return true;
}
// Set the variables.
$input = JFactory::getApplication()->input;
$extension = $input->get('option', '',
'cmd');
// Check if the highlighter is enabled.
if
(!JComponentHelper::getParams($extension)->get('highlight_terms',
1))
{
return true;
}
// Check if the highlighter should be activated in this environment.
if ($input->get('tmpl', '', 'cmd') ===
'component' || JFactory::getDocument()->getType() !==
'html')
{
return true;
}
// Get the terms to highlight from the request.
$terms = $input->request->get('highlight', null,
'base64');
$terms = $terms ? json_decode(base64_decode($terms)) : null;
// Check the terms.
if (empty($terms))
{
return true;
}
// Clean the terms array.
$filter = JFilterInput::getInstance();
$cleanTerms = array();
foreach ($terms as $term)
{
$cleanTerms[] = htmlspecialchars($filter->clean($term,
'string'));
}
// Activate the highlighter.
JHtml::_('behavior.highlighter', $cleanTerms);
// Adjust the component buffer.
$doc = JFactory::getDocument();
$buf = $doc->getBuffer('component');
$buf = '<br id="highlighter-start" />' . $buf .
'<br id="highlighter-end" />';
$doc->setBuffer($buf, 'component');
return true;
}
}
PK|��[;��f44highlight/highlight.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_highlight</name>
<author>Joomla! Project</author>
<creationDate>August 2011</creationDate>
<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later;
see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_SYSTEM_HIGHLIGHT_XML_DESCRIPTION</description>
<files>
<filename
plugin="highlight">highlight.php</filename>
</files>
<languages>
<language
tag="en-GB">language/en-GB/en-GB.plg_system_highlight.ini</language>
<language
tag="en-GB">language/en-GB/en-GB.plg_system_highlight.sys.ini</language>
</languages>
</extension>
PK|��[�����=languagecode/language/en-GB/en-GB.plg_system_languagecode.ininu�[���;
Joomla! Project
; (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_SYSTEM_LANGUAGECODE="System - Language Code"
PLG_SYSTEM_LANGUAGECODE_FIELD_DESC="Changes the language code used for
the <em>%s</em> language."
PLG_SYSTEM_LANGUAGECODE_FIELDSET_DESC="Changes the language code for
the generated HTML document. Example usage: You have installed the fr-FR
language pack and want the Search Engines to recognise the page as aimed at
French-speaking Canada. Add the tag 'fr-CA' to the corresponding
field for 'fr-FR' to resolve this."
PLG_SYSTEM_LANGUAGECODE_FIELDSET_LABEL="Language codes"
PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION="Provides the ability to
change the language code in the generated HTML document to improve
SEO.<br />The fields will appear when the plugin is enabled and
saved."
PK|��[o���Alanguagecode/language/en-GB/en-GB.plg_system_languagecode.sys.ininu�[���;
Joomla! Project
; (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_SYSTEM_LANGUAGECODE="System - Language Code"
PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION="Provides ability to change
the language code in the generated HTML document to improve SEO"
PK|��[�}`languagecode/languagecode.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.languagecode
*
* @copyright (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Language Code plugin class.
*
* @since 2.5
*/
class PlgSystemLanguagecode extends JPlugin
{
/**
* Plugin that changes the language code used in the <html /> tag.
*
* @return void
*
* @since 2.5
*/
public function onAfterRender()
{
$app = JFactory::getApplication();
// Use this plugin only in site application.
if ($app->isClient('site'))
{
// Get the response body.
$body = $app->getBody();
// Get the current language code.
$code = JFactory::getDocument()->getLanguage();
// Get the new code.
$new_code = $this->params->get($code);
// Replace the old code by the new code in the <html /> tag.
if ($new_code)
{
// Replace the new code in the HTML document.
$patterns = array(
chr(1) . '(<html.*\s+xml:lang=")(' . $code .
')(".*>)' . chr(1) . 'i',
chr(1) . '(<html.*\s+lang=")(' . $code .
')(".*>)' . chr(1) . 'i',
);
$replace = array(
'${1}' . strtolower($new_code) . '${3}',
'${1}' . strtolower($new_code) . '${3}'
);
}
else
{
$patterns = array();
$replace = array();
}
// Replace codes in <link hreflang="" /> attributes.
preg_match_all(chr(1) .
'(<link.*\s+hreflang=")([0-9a-z\-]*)(".*\s+rel="alternate".*/>)'
. chr(1) . 'i', $body, $matches);
foreach ($matches[2] as $match)
{
$new_code = $this->params->get(strtolower($match));
if ($new_code)
{
$patterns[] = chr(1) . '(<link.*\s+hreflang=")(' .
$match . ')(".*\s+rel="alternate".*/>)' .
chr(1) . 'i';
$replace[] = '${1}' . $new_code . '${3}';
}
}
preg_match_all(chr(1) .
'(<link.*\s+rel="alternate".*\s+hreflang=")([0-9A-Za-z\-]*)(".*/>)'
. chr(1) . 'i', $body, $matches);
foreach ($matches[2] as $match)
{
$new_code = $this->params->get(strtolower($match));
if ($new_code)
{
$patterns[] = chr(1) .
'(<link.*\s+rel="alternate".*\s+hreflang=")(' .
$match . ')(".*/>)' . chr(1) . 'i';
$replace[] = '${1}' . $new_code . '${3}';
}
}
// Replace codes in itemprop content
preg_match_all(chr(1) .
'(<meta.*\s+itemprop="inLanguage".*\s+content=")([0-9A-Za-z\-]*)(".*/>)'
. chr(1) . 'i', $body, $matches);
foreach ($matches[2] as $match)
{
$new_code = $this->params->get(strtolower($match));
if ($new_code)
{
$patterns[] = chr(1) .
'(<meta.*\s+itemprop="inLanguage".*\s+content=")('
. $match . ')(".*/>)' . chr(1) . 'i';
$replace[] = '${1}' . $new_code . '${3}';
}
}
$app->setBody(preg_replace($patterns, $replace, $body));
}
}
/**
* Prepare form.
*
* @param JForm $form The form to be altered.
* @param mixed $data The associated data for the form.
*
* @return boolean
*
* @since 2.5
*/
public function onContentPrepareForm(JForm $form, $data)
{
// Check we are manipulating the languagecode plugin.
if ($form->getName() !== 'com_plugins.plugin' ||
!$form->getField('languagecodeplugin', 'params'))
{
return true;
}
// Get site languages.
if ($languages = JLanguageHelper::getKnownLanguages(JPATH_SITE))
{
// Inject fields into the form.
foreach ($languages as $tag => $language)
{
$form->load('
<form>
<fields name="params">
<fieldset
name="languagecode"
label="PLG_SYSTEM_LANGUAGECODE_FIELDSET_LABEL"
description="PLG_SYSTEM_LANGUAGECODE_FIELDSET_DESC"
>
<field
name="' . strtolower($tag) . '"
type="text"
label="' . $tag . '"
description="' .
htmlspecialchars(JText::sprintf('PLG_SYSTEM_LANGUAGECODE_FIELD_DESC',
$language['name']), ENT_COMPAT, 'UTF-8') . '"
translate_description="false"
translate_label="false"
size="7"
filter="cmd"
/>
</fieldset>
</fields>
</form>
');
}
}
return true;
}
}
PK|��[�x�.��languagecode/languagecode.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_languagecode</name>
<author>Joomla! Project</author>
<creationDate>November 2011</creationDate>
<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION</description>
<files>
<filename
plugin="languagecode">languagecode.php</filename>
<folder>language</folder>
</files>
<languages>
<language
tag="en-GB">language/en-GB/en-GB.plg_system_languagecode.ini</language>
<language
tag="en-GB">language/en-GB/en-GB.plg_system_languagecode.sys.ini</language>
</languages>
<config>
<fields name="params">
<field
name="languagecodeplugin"
type="hidden"
default="true"
/>
</fields>
</config>
</extension>
PK|��[�ա�b�b!languagefilter/languagefilter.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.languagefilter
*
* @copyright (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\Registry\Registry;
use Joomla\String\StringHelper;
JLoader::register('MenusHelper', JPATH_ADMINISTRATOR .
'/components/com_menus/helpers/menus.php');
/**
* Joomla! Language Filter Plugin.
*
* @since 1.6
*/
class PlgSystemLanguageFilter extends JPlugin
{
/**
* The routing mode.
*
* @var boolean
* @since 2.5
*/
protected $mode_sef;
/**
* Available languages by sef.
*
* @var array
* @since 1.6
*/
protected $sefs;
/**
* Available languages by language codes.
*
* @var array
* @since 2.5
*/
protected $lang_codes;
/**
* The current language code.
*
* @var string
* @since 3.4.2
*/
protected $current_lang;
/**
* The default language code.
*
* @var string
* @since 2.5
*/
protected $default_lang;
/**
* The logged user language code.
*
* @var string
* @since 3.3.1
*/
private $user_lang_code;
/**
* Application object.
*
* @var JApplicationCms
* @since 3.3
*/
protected $app;
/**
* Constructor.
*
* @param object &$subject The object to observe
* @param array $config An optional associative array of
configuration settings.
*
* @since 1.6
*/
public function __construct(&$subject, $config)
{
parent::__construct($subject, $config);
$this->app = JFactory::getApplication();
// Setup language data.
$this->mode_sef = $this->app->get('sef', 0);
$this->sefs = JLanguageHelper::getLanguages('sef');
$this->lang_codes =
JLanguageHelper::getLanguages('lang_code');
$this->default_lang =
JComponentHelper::getParams('com_languages')->get('site',
'en-GB');
// If language filter plugin is executed in a site page.
if ($this->app->isClient('site'))
{
$levels = JFactory::getUser()->getAuthorisedViewLevels();
foreach ($this->sefs as $sef => $language)
{
// @todo: In Joomla 2.5.4 and earlier access wasn't set. Non
modified Content Languages got 0 as access value
// we also check if frontend language exists and is enabled
if (($language->access && !in_array($language->access,
$levels))
|| (!array_key_exists($language->lang_code,
JLanguageHelper::getInstalledLanguages(0))))
{
unset($this->lang_codes[$language->lang_code],
$this->sefs[$language->sef]);
}
}
}
// If language filter plugin is executed in an admin page (ex: JRoute
site).
else
{
// Set current language to default site language, fallback to en-GB if
there is no content language for the default site language.
$this->current_lang =
isset($this->lang_codes[$this->default_lang]) ?
$this->default_lang : 'en-GB';
foreach ($this->sefs as $sef => $language)
{
if (!array_key_exists($language->lang_code,
JLanguageHelper::getInstalledLanguages(0)))
{
unset($this->lang_codes[$language->lang_code]);
unset($this->sefs[$language->sef]);
}
}
}
}
/**
* After initialise.
*
* @return void
*
* @since 1.6
*/
public function onAfterInitialise()
{
$this->app->item_associations =
$this->params->get('item_associations', 0);
// We need to make sure we are always using the site router, even if the
language plugin is executed in admin app.
$router =
JApplicationCms::getInstance('site')->getRouter('site');
// Attach build rules for language SEF.
$router->attachBuildRule(array($this,
'preprocessBuildRule'), JRouter::PROCESS_BEFORE);
$router->attachBuildRule(array($this, 'buildRule'),
JRouter::PROCESS_DURING);
if ($this->mode_sef)
{
$router->attachBuildRule(array($this,
'postprocessSEFBuildRule'), JRouter::PROCESS_AFTER);
}
else
{
$router->attachBuildRule(array($this,
'postprocessNonSEFBuildRule'), JRouter::PROCESS_AFTER);
}
// Attach parse rules for language SEF.
$router->attachParseRule(array($this, 'parseRule'),
JRouter::PROCESS_DURING);
}
/**
* After route.
*
* @return void
*
* @since 3.4
*/
public function onAfterRoute()
{
// Add custom site name.
if ($this->app->isClient('site') &&
isset($this->lang_codes[$this->current_lang]) &&
$this->lang_codes[$this->current_lang]->sitename)
{
$this->app->set('sitename',
$this->lang_codes[$this->current_lang]->sitename);
}
}
/**
* Add build preprocess rule to router.
*
* @param JRouter &$router JRouter object.
* @param JUri &$uri JUri object.
*
* @return void
*
* @since 3.4
*/
public function preprocessBuildRule(&$router, &$uri)
{
$lang = $uri->getVar('lang', $this->current_lang);
$uri->setVar('lang', $lang);
if (isset($this->sefs[$lang]))
{
$lang = $this->sefs[$lang]->lang_code;
$uri->setVar('lang', $lang);
}
}
/**
* Add build rule to router.
*
* @param JRouter &$router JRouter object.
* @param JUri &$uri JUri object.
*
* @return void
*
* @since 1.6
*/
public function buildRule(&$router, &$uri)
{
$lang = $uri->getVar('lang');
if (isset($this->lang_codes[$lang]))
{
$sef = $this->lang_codes[$lang]->sef;
}
else
{
$sef = $this->lang_codes[$this->current_lang]->sef;
}
if ($this->mode_sef
&& (!$this->params->get('remove_default_prefix',
0)
|| $lang !== $this->default_lang
|| $lang !== $this->current_lang))
{
$uri->setPath($uri->getPath() . '/' . $sef .
'/');
}
}
/**
* postprocess build rule for SEF URLs
*
* @param JRouter &$router JRouter object.
* @param JUri &$uri JUri object.
*
* @return void
*
* @since 3.4
*/
public function postprocessSEFBuildRule(&$router, &$uri)
{
$uri->delVar('lang');
}
/**
* postprocess build rule for non-SEF URLs
*
* @param JRouter &$router JRouter object.
* @param JUri &$uri JUri object.
*
* @return void
*
* @since 3.4
*/
public function postprocessNonSEFBuildRule(&$router, &$uri)
{
$lang = $uri->getVar('lang');
if (isset($this->lang_codes[$lang]))
{
$uri->setVar('lang', $this->lang_codes[$lang]->sef);
}
}
/**
* Add parse rule to router.
*
* @param JRouter &$router JRouter object.
* @param JUri &$uri JUri object.
*
* @return void
*
* @since 1.6
*/
public function parseRule(&$router, &$uri)
{
// Did we find the current and existing language yet?
$found = false;
// Are we in SEF mode or not?
if ($this->mode_sef)
{
$path = $uri->getPath();
$parts = explode('/', $path);
$sef = StringHelper::strtolower($parts[0]);
// Do we have a URL Language Code ?
if (!isset($this->sefs[$sef]))
{
// Check if remove default URL language code is set
if ($this->params->get('remove_default_prefix', 0))
{
if ($parts[0])
{
// We load a default site language page
$lang_code = $this->default_lang;
}
else
{
// We check for an existing language cookie
$lang_code = $this->getLanguageCookie();
}
}
else
{
$lang_code = $this->getLanguageCookie();
}
// No language code. Try using browser settings or default site
language
if (!$lang_code &&
$this->params->get('detect_browser', 0) == 1)
{
$lang_code = JLanguageHelper::detectLanguage();
}
if (!$lang_code)
{
$lang_code = $this->default_lang;
}
if ($lang_code === $this->default_lang &&
$this->params->get('remove_default_prefix', 0))
{
$found = true;
}
}
else
{
// We found our language
$found = true;
$lang_code = $this->sefs[$sef]->lang_code;
// If we found our language, but its the default language and we
don't want a prefix for that, we are on a wrong URL.
// Or we try to change the language back to the default language. We
need a redirect to the proper URL for the default language.
if ($lang_code === $this->default_lang &&
$this->params->get('remove_default_prefix', 0))
{
// Create a cookie.
$this->setLanguageCookie($lang_code);
$found = false;
array_shift($parts);
$path = implode('/', $parts);
}
// We have found our language and the first part of our URL is the
language prefix
if ($found)
{
array_shift($parts);
// Empty parts array when "index.php" is the only part left.
if (count($parts) === 1 && $parts[0] ===
'index.php')
{
$parts = array();
}
$uri->setPath(implode('/', $parts));
}
}
}
// We are not in SEF mode
else
{
$lang_code = $this->getLanguageCookie();
if (!$lang_code &&
$this->params->get('detect_browser', 1))
{
$lang_code = JLanguageHelper::detectLanguage();
}
if (!isset($this->lang_codes[$lang_code]))
{
$lang_code = $this->default_lang;
}
}
$lang = $uri->getVar('lang', $lang_code);
if (isset($this->sefs[$lang]))
{
// We found our language
$found = true;
$lang_code = $this->sefs[$lang]->lang_code;
}
// We are called via POST or the nolangfilter url parameter was set. We
don't care about the language
// and simply set the default language as our current language.
if ($this->app->input->getMethod() === 'POST'
|| $this->app->input->get('nolangfilter', 0) == 1
|| count($this->app->input->post) > 0
|| count($this->app->input->files) > 0)
{
$found = true;
if (!isset($lang_code))
{
$lang_code = $this->getLanguageCookie();
}
if (!$lang_code &&
$this->params->get('detect_browser', 1))
{
$lang_code = JLanguageHelper::detectLanguage();
}
if (!isset($this->lang_codes[$lang_code]))
{
$lang_code = $this->default_lang;
}
}
// We have not found the language and thus need to redirect
if (!$found)
{
// Lets find the default language for this user
if (!isset($lang_code) || !isset($this->lang_codes[$lang_code]))
{
$lang_code = false;
if ($this->params->get('detect_browser', 1))
{
$lang_code = JLanguageHelper::detectLanguage();
if (!isset($this->lang_codes[$lang_code]))
{
$lang_code = false;
}
}
if (!$lang_code)
{
$lang_code = $this->default_lang;
}
}
if ($this->mode_sef)
{
// Use the current language sef or the default one.
if ($lang_code !== $this->default_lang
|| !$this->params->get('remove_default_prefix', 0))
{
$path = $this->lang_codes[$lang_code]->sef . '/' .
$path;
}
$uri->setPath($path);
if (!$this->app->get('sef_rewrite'))
{
$uri->setPath('index.php/' . $uri->getPath());
}
$redirectUri = $uri->base() .
$uri->toString(array('path', 'query',
'fragment'));
}
else
{
$uri->setVar('lang',
$this->lang_codes[$lang_code]->sef);
$redirectUri = $uri->base() . 'index.php?' .
$uri->getQuery();
}
// Set redirect HTTP code to "302 Found".
$redirectHttpCode = 302;
// If selected language is the default language redirect code is
"301 Moved Permanently".
if ($lang_code === $this->default_lang)
{
$redirectHttpCode = 301;
// We cannot cache this redirect in browser. 301 is cachable by default
so we need to force to not cache it in browsers.
$this->app->setHeader('Expires', 'Wed, 17 Aug 2005
00:00:00 GMT', true);
$this->app->setHeader('Last-Modified', gmdate('D,
d M Y H:i:s') . ' GMT', true);
$this->app->setHeader('Cache-Control', 'no-store,
no-cache, must-revalidate, post-check=0, pre-check=0', false);
$this->app->setHeader('Pragma', 'no-cache');
$this->app->sendHeaders();
}
// Redirect to language.
$this->app->redirect($redirectUri, $redirectHttpCode);
}
// We have found our language and now need to set the cookie and the
language value in our system
$array = array('lang' => $lang_code);
$this->current_lang = $lang_code;
// Set the request var.
$this->app->input->set('language', $lang_code);
$this->app->set('language', $lang_code);
$language = JFactory::getLanguage();
if ($language->getTag() !== $lang_code)
{
$language_new = JLanguage::getInstance($lang_code, (bool)
$this->app->get('debug_lang'));
foreach ($language->getPaths() as $extension => $files)
{
if (strpos($extension, 'plg_system') !== false)
{
$extension_name = substr($extension, 11);
$language_new->load($extension, JPATH_ADMINISTRATOR)
|| $language_new->load($extension, JPATH_PLUGINS .
'/system/' . $extension_name);
continue;
}
$language_new->load($extension);
}
JFactory::$language = $language_new;
$this->app->loadLanguage($language_new);
}
// Create a cookie.
if ($this->getLanguageCookie() !== $lang_code)
{
$this->setLanguageCookie($lang_code);
}
return $array;
}
/**
* Reports the privacy related capabilities for this plugin to site
administrators.
*
* @return array
*
* @since 3.9.0
*/
public function onPrivacyCollectAdminCapabilities()
{
$this->loadLanguage();
return array(
JText::_('PLG_SYSTEM_LANGUAGEFILTER') => array(
JText::_('PLG_SYSTEM_LANGUAGEFILTER_PRIVACY_CAPABILITY_LANGUAGE_COOKIE'),
)
);
}
/**
* Before store user method.
*
* Method is called before user data is stored in the database.
*
* @param array $user Holds the old user data.
* @param boolean $isnew True if a new user is stored.
* @param array $new Holds the new user data.
*
* @return void
*
* @since 1.6
*/
public function onUserBeforeSave($user, $isnew, $new)
{
if (array_key_exists('params', $user) &&
$this->params->get('automatic_change', 1) == 1)
{
$registry = new Registry($user['params']);
$this->user_lang_code = $registry->get('language');
if (empty($this->user_lang_code))
{
$this->user_lang_code = $this->current_lang;
}
}
}
/**
* After store user method.
*
* Method is called after user data is stored in the database.
*
* @param array $user Holds the new user data.
* @param boolean $isnew True if a new user is stored.
* @param boolean $success True if user was succesfully stored in the
database.
* @param string $msg Message.
*
* @return void
*
* @since 1.6
*/
public function onUserAfterSave($user, $isnew, $success, $msg)
{
if ($success && array_key_exists('params', $user)
&& $this->params->get('automatic_change', 1) == 1)
{
$registry = new Registry($user['params']);
$lang_code = $registry->get('language');
if (empty($lang_code))
{
$lang_code = $this->current_lang;
}
if ($lang_code === $this->user_lang_code ||
!isset($this->lang_codes[$lang_code]))
{
if ($this->app->isClient('site'))
{
$this->app->setUserState('com_users.edit.profile.redirect',
null);
}
}
else
{
if ($this->app->isClient('site'))
{
$this->app->setUserState('com_users.edit.profile.redirect',
'index.php?Itemid='
. $this->app->getMenu()->getDefault($lang_code)->id .
'&lang=' . $this->lang_codes[$lang_code]->sef
);
// Create a cookie.
$this->setLanguageCookie($lang_code);
}
}
}
}
/**
* Method to handle any login logic and report back to the subject.
*
* @param array $user Holds the user data.
* @param array $options Array holding options (remember,
autoregister, group).
*
* @return boolean True on success.
*
* @since 1.5
*/
public function onUserLogin($user, $options = array())
{
$menu = $this->app->getMenu();
if ($this->app->isClient('site'))
{
if ($this->params->get('automatic_change', 1))
{
$assoc = JLanguageAssociations::isEnabled();
$lang_code = $user['language'];
// If no language is specified for this user, we set it to the site
default language
if (empty($lang_code))
{
$lang_code = $this->default_lang;
}
jimport('joomla.filesystem.folder');
// The language has been deleted/disabled or the related content
language does not exist/has been unpublished
// or the related home page does not exist/has been unpublished
if (!array_key_exists($lang_code, $this->lang_codes)
|| !array_key_exists($lang_code,
JLanguageMultilang::getSiteHomePages())
|| !JFolder::exists(JPATH_SITE . '/language/' . $lang_code))
{
$lang_code = $this->current_lang;
}
// Try to get association from the current active menu item
$active = $menu->getActive();
$foundAssociation = false;
/**
* Looking for associations.
* If the login menu item form contains an internal URL redirection,
* This will override the automatic change to the user preferred site
language.
* In that case we use the redirect as defined in the menu item.
* Otherwise we redirect, when available, to the user preferred site
language.
*/
if ($active &&
!$active->params['login_redirect_url'])
{
if ($assoc)
{
$associations = MenusHelper::getAssociations($active->id);
}
// Retrieves the Itemid from a login form.
$uri = new
JUri($this->app->getUserState('users.login.form.return'));
if ($uri->getVar('Itemid'))
{
// The login form contains a menu item redirection. Try to get
associations from that menu item.
// If any association set to the user preferred site language,
redirect to that page.
if ($assoc)
{
$associations =
MenusHelper::getAssociations($uri->getVar('Itemid'));
}
if (isset($associations[$lang_code]) &&
$menu->getItem($associations[$lang_code]))
{
$associationItemid = $associations[$lang_code];
$this->app->setUserState('users.login.form.return',
'index.php?Itemid=' . $associationItemid);
$foundAssociation = true;
}
}
elseif (isset($associations[$lang_code]) &&
$menu->getItem($associations[$lang_code]))
{
/**
* The login form does not contain a menu item redirection.
* The active menu item has associations.
* We redirect to the user preferred site language associated page.
*/
$associationItemid = $associations[$lang_code];
$this->app->setUserState('users.login.form.return',
'index.php?Itemid=' . $associationItemid);
$foundAssociation = true;
}
elseif ($active->home)
{
// We are on a Home page, we redirect to the user preferred site
language Home page.
$item = $menu->getDefault($lang_code);
if ($item && $item->language !== $active->language
&& $item->language !== '*')
{
$this->app->setUserState('users.login.form.return',
'index.php?Itemid=' . $item->id);
$foundAssociation = true;
}
}
}
if ($foundAssociation && $lang_code !== $this->current_lang)
{
// Change language.
$this->current_lang = $lang_code;
// Create a cookie.
$this->setLanguageCookie($lang_code);
// Change the language code.
JFactory::getLanguage()->setLanguage($lang_code);
}
}
else
{
if
($this->app->getUserState('users.login.form.return'))
{
$this->app->setUserState('users.login.form.return',
JRoute::_($this->app->getUserState('users.login.form.return'),
false));
}
}
}
}
/**
* Method to add alternative meta tags for associated menu items.
*
* @return void
*
* @since 1.7
*/
public function onAfterDispatch()
{
$doc = JFactory::getDocument();
if ($this->app->isClient('site') &&
$this->params->get('alternate_meta', 1) &&
$doc->getType() === 'html')
{
$languages = $this->lang_codes;
$homes = JLanguageMultilang::getSiteHomePages();
$menu = $this->app->getMenu();
$active = $menu->getActive();
$levels =
JFactory::getUser()->getAuthorisedViewLevels();
$remove_default_prefix =
$this->params->get('remove_default_prefix', 0);
$server =
JUri::getInstance()->toString(array('scheme',
'host', 'port'));
$is_home = false;
$currentInternalUrl = 'index.php?' .
http_build_query($this->app->getRouter()->getVars());
if ($active)
{
$active_link = JRoute::_($active->link . '&Itemid=' .
$active->id);
$current_link = JRoute::_($currentInternalUrl);
// Load menu associations
if ($active_link === $current_link)
{
$associations = MenusHelper::getAssociations($active->id);
}
// Check if we are on the home page
$is_home = ($active->home
&& ($active_link === $current_link || $active_link ===
$current_link . 'index.php' || $active_link . '/' ===
$current_link));
}
// Load component associations.
$option = $this->app->input->get('option');
$cName = ucfirst(substr($option, 4)) . 'HelperAssociation';
JLoader::register($cName, JPath::clean(JPATH_SITE .
'/components/' . $option .
'/helpers/association.php'));
if (class_exists($cName) && is_callable(array($cName,
'getAssociations')))
{
$cassociations = call_user_func(array($cName,
'getAssociations'));
}
// For each language...
foreach ($languages as $i => $language)
{
switch (true)
{
// Language without frontend UI || Language without specific home menu
|| Language without authorized access level
case (!array_key_exists($i,
JLanguageHelper::getInstalledLanguages(0))):
case (!isset($homes[$i])):
case (isset($language->access) && $language->access
&& !in_array($language->access, $levels)):
unset($languages[$i]);
break;
// Home page
case ($is_home):
$language->link = JRoute::_('index.php?lang=' .
$language->sef . '&Itemid=' . $homes[$i]->id);
break;
// Current language link
case ($i === $this->current_lang):
$language->link = JRoute::_($currentInternalUrl);
break;
// Component association
case (isset($cassociations[$i])):
$language->link = JRoute::_($cassociations[$i] .
'&lang=' . $language->sef);
break;
// Menu items association
// Heads up! "$item = $menu" here below is an assignment,
*NOT* comparison
case (isset($associations[$i]) && ($item =
$menu->getItem($associations[$i]))):
$language->link = JRoute::_('index.php?Itemid=' .
$item->id . '&lang=' . $language->sef);
break;
// Too bad...
default:
unset($languages[$i]);
}
}
// If there are at least 2 of them, add the rel="alternate"
links to the <head>
if (count($languages) > 1)
{
// Remove the sef from the default language if "Remove URL
Language Code" is on
if ($remove_default_prefix &&
isset($languages[$this->default_lang]))
{
$languages[$this->default_lang]->link
= preg_replace('|/' .
$languages[$this->default_lang]->sef . '/|', '/',
$languages[$this->default_lang]->link, 1);
}
foreach ($languages as $i => $language)
{
$doc->addHeadLink($server . $language->link,
'alternate', 'rel', array('hreflang' =>
$i));
}
// Add x-default language tag
if ($this->params->get('xdefault', 1))
{
$xdefault_language =
$this->params->get('xdefault_language',
$this->default_lang);
$xdefault_language = ($xdefault_language === 'default') ?
$this->default_lang : $xdefault_language;
if (isset($languages[$xdefault_language]))
{
// Use a custom tag because addHeadLink is limited to one URI per tag
$doc->addCustomTag('<link href="' . $server .
$languages[$xdefault_language]->link . '"
rel="alternate" hreflang="x-default" />');
}
}
}
}
}
/**
* Set the language cookie
*
* @param string $languageCode The language code for which we want to
set the cookie
*
* @return void
*
* @since 3.4.2
*/
private function setLanguageCookie($languageCode)
{
// If is set to use language cookie for a year in plugin params, save the
user language in a new cookie.
if ((int) $this->params->get('lang_cookie', 0) === 1)
{
// Create a cookie with one year lifetime.
$this->app->input->cookie->set(
JApplicationHelper::getHash('language'),
$languageCode,
time() + 365 * 86400,
$this->app->get('cookie_path', '/'),
$this->app->get('cookie_domain', ''),
$this->app->isHttpsForced(),
true
);
}
// If not, set the user language in the session (that is already saved in
a cookie).
else
{
JFactory::getSession()->set('plg_system_languagefilter.language',
$languageCode);
}
}
/**
* Get the language cookie
*
* @return string
*
* @since 3.4.2
*/
private function getLanguageCookie()
{
// Is is set to use a year language cookie in plugin params, get the user
language from the cookie.
if ((int) $this->params->get('lang_cookie', 0) === 1)
{
$languageCode =
$this->app->input->cookie->get(JApplicationHelper::getHash('language'));
}
// Else get the user language from the session.
else
{
$languageCode =
JFactory::getSession()->get('plg_system_languagefilter.language');
}
// Let's be sure we got a valid language code. Fallback to null.
if (!array_key_exists($languageCode, $this->lang_codes))
{
$languageCode = null;
}
return $languageCode;
}
}
PK|��[aVOuss!languagefilter/languagefilter.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_languagefilter</name>
<author>Joomla! Project</author>
<creationDate>July 2010</creationDate>
<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_SYSTEM_LANGUAGEFILTER_XML_DESCRIPTION</description>
<files>
<filename
plugin="languagefilter">languagefilter.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_languagefilter.ini</language>
<language
tag="en-GB">en-GB.plg_system_languagefilter.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="detect_browser"
type="list"
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_DETECT_BROWSER_LABEL"
description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_DETECT_BROWSER_DESC"
default="0"
filter="integer"
>
<option
value="0">PLG_SYSTEM_LANGUAGEFILTER_SITE_LANGUAGE</option>
<option
value="1">PLG_SYSTEM_LANGUAGEFILTER_BROWSER_SETTINGS</option>
</field>
<field
name="automatic_change"
type="radio"
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_AUTOMATIC_CHANGE_LABEL"
description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_AUTOMATIC_CHANGE_DESC"
default="1"
filter="integer"
class="btn-group btn-group-yesno"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="item_associations"
type="radio"
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ITEM_ASSOCIATIONS_LABEL"
description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ITEM_ASSOCIATIONS_DESC"
default="1"
filter="integer"
class="btn-group btn-group-yesno"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="alternate_meta"
type="radio"
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ALTERNATE_META_LABEL"
description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ALTERNATE_META_DESC"
default="1"
filter="integer"
class="btn-group btn-group-yesno"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="xdefault"
type="radio"
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LABEL"
description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_DESC"
default="1"
filter="integer"
class="btn-group btn-group-yesno"
showon="alternate_meta:1"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="xdefault_language"
type="contentlanguage"
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LANGUAGE_LABEL"
description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LANGUAGE_DESC"
default="default"
showon="alternate_meta:1[AND]xdefault:1"
>
<option
value="default">PLG_SYSTEM_LANGUAGEFILTER_OPTION_DEFAULT_LANGUAGE</option>
</field>
<field
name="remove_default_prefix"
type="radio"
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_REMOVE_DEFAULT_PREFIX_LABEL"
description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_REMOVE_DEFAULT_PREFIX_DESC"
default="0"
filter="integer"
class="btn-group btn-group-yesno"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="lang_cookie"
type="list"
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_COOKIE_LABEL"
description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_COOKIE_DESC"
default="0"
filter="integer"
>
<option
value="1">PLG_SYSTEM_LANGUAGEFILTER_OPTION_YEAR</option>
<option
value="0">PLG_SYSTEM_LANGUAGEFILTER_OPTION_SESSION</option>
</field>
</fieldset>
</fields>
</config>
</extension>PK}��[~���log/log.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.log
*
* @copyright (C) 2007 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Joomla! System Logging Plugin.
*
* @since 1.5
*/
class PlgSystemLog extends JPlugin
{
/**
* Called if user fails to be logged in.
*
* @param array $response Array of response data.
*
* @return void
*
* @since 1.5
*/
public function onUserLoginFailure($response)
{
$errorlog = array();
switch ($response['status'])
{
case JAuthentication::STATUS_SUCCESS:
$errorlog['status'] = $response['type'] . '
CANCELED: ';
$errorlog['comment'] = $response['error_message'];
break;
case JAuthentication::STATUS_FAILURE:
$errorlog['status'] = $response['type'] . '
FAILURE: ';
if ($this->params->get('log_username', 0))
{
$errorlog['comment'] = $response['error_message']
. ' ("' . $response['username'] .
'")';
}
else
{
$errorlog['comment'] = $response['error_message'];
}
break;
default:
$errorlog['status'] = $response['type'] . '
UNKNOWN ERROR: ';
$errorlog['comment'] = $response['error_message'];
break;
}
JLog::addLogger(array(), JLog::INFO);
try
{
JLog::add($errorlog['comment'], JLog::INFO,
$errorlog['status']);
}
catch (Exception $e)
{
// If the log file is unwriteable during login then we should not go to
the error page
return;
}
}
}
PK}��[�$K��log/log.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_log</name>
<author>Joomla! Project</author>
<creationDate>April 2007</creationDate>
<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_LOG_XML_DESCRIPTION</description>
<files>
<filename plugin="log">log.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_log.ini</language>
<language
tag="en-GB">en-GB.plg_system_log.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="log_username"
type="radio"
label="PLG_SYSTEM_LOG_FIELD_LOG_USERNAME_LABEL"
description="PLG_SYSTEM_LOG_FIELD_LOG_USERNAME_DESC"
class="btn-group btn-group-yesno"
default="0"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
</fieldset>
</fields>
</config>
</extension>
PK}��[[�G%�
�
logout/logout.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.logout
*
* @copyright (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Plugin class for logout redirect handling.
*
* @since 1.6
*/
class PlgSystemLogout extends JPlugin
{
/**
* Application object.
*
* @var JApplicationCms
* @since 3.7.3
*/
protected $app;
/**
* Load the language file on instantiation.
*
* @var boolean
* @since 3.1
*/
protected $autoloadLanguage = true;
/**
* Constructor.
*
* @param object &$subject The object to observe -- event
dispatcher.
* @param object $config An optional associative array of
configuration settings.
*
* @since 1.6
*/
public function __construct(&$subject, $config)
{
parent::__construct($subject, $config);
// If we are on admin don't process.
if (!$this->app->isClient('site'))
{
return;
}
$hash = JApplicationHelper::getHash('PlgSystemLogout');
if ($this->app->input->cookie->getString($hash))
{
// Destroy the cookie.
$this->app->input->cookie->set($hash, '', 1,
$this->app->get('cookie_path', '/'),
$this->app->get('cookie_domain', ''));
// Set the error handler for E_ALL to be the class handleError method.
JError::setErrorHandling(E_ALL, 'callback',
array('PlgSystemLogout', 'handleError'));
}
}
/**
* Method to handle any logout logic and report back to the subject.
*
* @param array $user Holds the user data.
* @param array $options Array holding options (client, ...).
*
* @return boolean Always returns true.
*
* @since 1.6
*/
public function onUserLogout($user, $options = array())
{
if ($this->app->isClient('site'))
{
// Create the cookie.
$this->app->input->cookie->set(
JApplicationHelper::getHash('PlgSystemLogout'),
true,
time() + 86400,
$this->app->get('cookie_path', '/'),
$this->app->get('cookie_domain', ''),
$this->app->isHttpsForced(),
true
);
}
return true;
}
/**
* Method to handle an error condition.
*
* @param Exception &$error The Exception object to be handled.
*
* @return void
*
* @since 1.6
*/
public static function handleError(&$error)
{
// Get the application object.
$app = JFactory::getApplication();
// Make sure the error is a 403 and we are in the frontend.
if ($error->getCode() == 403 &&
$app->isClient('site'))
{
// Redirect to the home page.
$app->enqueueMessage(JText::_('PLG_SYSTEM_LOGOUT_REDIRECT'));
$app->redirect('index.php');
}
else
{
// Render the custom error page.
JError::customErrorPage($error);
}
}
}
PK}��[��C�logout/logout.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_logout</name>
<author>Joomla! Project</author>
<creationDate>April 2009</creationDate>
<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_SYSTEM_LOGOUT_XML_DESCRIPTION</description>
<files>
<filename plugin="logout">logout.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_logout.ini</language>
<language
tag="en-GB">en-GB.plg_system_logout.sys.ini</language>
</languages>
</extension>
PK}��[X�/9��logrotation/logrotation.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.logrotation
*
* @copyright (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;
/**
* Joomla! Log Rotation plugin
*
* Rotate the log files created by Joomla core
*
* @since 3.9.0
*/
class PlgSystemLogrotation extends JPlugin
{
/**
* Load the language file on instantiation.
*
* @var boolean
* @since 3.9.0
*/
protected $autoloadLanguage = true;
/**
* Application object.
*
* @var JApplicationCms
* @since 3.9.0
*/
protected $app;
/**
* Database object.
*
* @var JDatabaseDriver
* @since 3.9.0
*/
protected $db;
/**
* The log check and rotation code is triggered after the page has fully
rendered.
*
* @return void
*
* @since 3.9.0
*/
public function onAfterRender()
{
// Get the timeout as configured in plugin parameters
/** @var \Joomla\Registry\Registry $params */
$cache_timeout = (int) $this->params->get('cachetimeout',
30);
$cache_timeout = 24 * 3600 * $cache_timeout;
$logsToKeep = (int) $this->params->get('logstokeep',
1);
// Do we need to run? Compare the last run timestamp stored in the
plugin's options with the current
// timestamp. If the difference is greater than the cache timeout we
shall not execute again.
$now = time();
$last = (int) $this->params->get('lastrun', 0);
if ((abs($now - $last) < $cache_timeout))
{
return;
}
// Update last run status
$this->params->set('lastrun', $now);
$db = $this->db;
$query = $db->getQuery(true)
->update($db->qn('#__extensions'))
->set($db->qn('params') . ' = ' .
$db->q($this->params->toString('JSON')))
->where($db->qn('type') . ' = ' .
$db->q('plugin'))
->where($db->qn('folder') . ' = ' .
$db->q('system'))
->where($db->qn('element') . ' = ' .
$db->q('logrotation'));
try
{
// Lock the tables to prevent multiple plugin executions causing a race
condition
$db->lockTable('#__extensions');
}
catch (Exception $e)
{
// If we can't lock the tables it's too risky to continue
execution
return;
}
try
{
// Update the plugin parameters
$result = $db->setQuery($query)->execute();
$this->clearCacheGroups(array('com_plugins'), array(0, 1));
}
catch (Exception $exc)
{
// If we failed to execute
$db->unlockTables();
$result = false;
}
try
{
// Unlock the tables after writing
$db->unlockTables();
}
catch (Exception $e)
{
// If we can't lock the tables assume we have somehow failed
$result = false;
}
// Abort on failure
if (!$result)
{
return;
}
// Get the log path
$logPath = Path::clean($this->app->get('log_path'));
// Invalid path, stop processing further
if (!is_dir($logPath))
{
return;
}
$logFiles = $this->getLogFiles($logPath);
// Sort log files by version number in reserve order
krsort($logFiles, SORT_NUMERIC);
foreach ($logFiles as $version => $files)
{
if ($version >= $logsToKeep)
{
// Delete files which has version greater than or equals $logsToKeep
foreach ($files as $file)
{
File::delete($logPath . '/' . $file);
}
}
else
{
// For files which has version smaller than $logsToKeep, rotate
(increase version number)
foreach ($files as $file)
{
$this->rotate($logPath, $file, $version);
}
}
}
}
/**
* Get log files from log folder
*
* @param string $path The folder to get log files
*
* @return array The log files in the given path grouped by version
number (not rotated files has number 0)
*
* @since 3.9.0
*/
private function getLogFiles($path)
{
$logFiles = array();
$files = Folder::files($path, '\.php$');
foreach ($files as $file)
{
$parts = explode('.', $file);
/*
* Rotated log file has this filename format [VERSION].[FILENAME].php.
So if $parts has at least 3 elements
* and the first element is a number, we know that it's a rotated
file and can get it's current version
*/
if (count($parts) >= 3 && is_numeric($parts[0]))
{
$version = (int) $parts[0];
}
else
{
$version = 0;
}
if (!isset($logFiles[$version]))
{
$logFiles[$version] = array();
}
$logFiles[$version][] = $file;
}
return $logFiles;
}
/**
* Method to rotate (increase version) of a log file
*
* @param string $path Path to file to rotate
* @param string $filename Name of file to rotate
* @param int $currentVersion The current version number
*
* @return void
*
* @since 3.9.0
*/
private function rotate($path, $filename, $currentVersion)
{
if ($currentVersion === 0)
{
$rotatedFile = $path . '/1.' . $filename;
}
else
{
/*
* Rotated log file has this filename format [VERSION].[FILENAME].php.
To rotate it, we just need to explode
* the filename into an array, increase value of first element (keep
version) and implode it back to get the
* rotated file name
*/
$parts = explode('.', $filename);
$parts[0] = $currentVersion + 1;
$rotatedFile = $path . '/' . implode('.', $parts);
}
File::move($path . '/' . $filename, $rotatedFile);
}
/**
* Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
*
* @param array $clearGroups The cache groups to clean
* @param array $cacheClients The cache clients (site, admin) to clean
*
* @return void
*
* @since 3.9.0
*/
private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
{
$conf = JFactory::getConfig();
foreach ($clearGroups as $group)
{
foreach ($cacheClients as $client_id)
{
try
{
$options = array(
'defaultgroup' => $group,
'cachebase' => $client_id ? JPATH_ADMINISTRATOR .
'/cache' :
$conf->get('cache_path', JPATH_SITE .
'/cache')
);
$cache = JCache::getInstance('callback', $options);
$cache->clean();
}
catch (Exception $e)
{
// Ignore it
}
}
}
}
}
PK}��[�g�##logrotation/logrotation.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="system" method="upgrade">
<name>plg_system_logrotation</name>
<author>Joomla! Project</author>
<creationDate>May 2018</creationDate>
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.9.0</version>
<description>PLG_SYSTEM_LOGROTATION_XML_DESCRIPTION</description>
<files>
<filename
plugin="logrotation">logrotation.php</filename>
</files>
<languages folder="language">
<language
tag="en-GB">en-GB.plg_system_logrotation.ini</language>
<language
tag="en-GB">en-GB.plg_system_logrotation.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="cachetimeout"
type="integer"
label="PLG_SYSTEM_LOGROTATION_CACHETIMEOUT_LABEL"
description="PLG_SYSTEM_LOGROTATION_CACHETIMEOUT_DESC"
first="0"
last="120"
step="1"
default="30"
filter="int"
validate="number"
/>
<field
name="logstokeep"
type="integer"
label="PLG_SYSTEM_LOGROTATION_LOGSTOKEEP_LABEL"
description="PLG_SYSTEM_LOGROTATION_LOGSTOKEEP_DESC"
first="1"
last="10"
step="1"
default="1"
filter="int"
validate="number"
/>
<field
name="lastrun"
type="hidden"
default="0"
filter="integer"
/>
</fieldset>
</fields>
</config>
</extension>
PK}��[�g��p3p/p3p.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.p3p
*
* @copyright (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Joomla! P3P Header Plugin.
*
* @since 1.6
* @deprecate 4.0 Obsolete
*/
class PlgSystemP3p extends JPlugin
{
/**
* After initialise.
*
* @return void
*
* @since 1.6
* @deprecate 4.0 Obsolete
*/
public function onAfterInitialise()
{
// Get the header.
$header = $this->params->get('header', 'NOI ADM DEV
PSAi COM NAV OUR OTRo STP IND DEM');
$header = trim($header);
// Bail out on empty header (why would anyone do that?!).
if (empty($header))
{
return;
}
// Replace any existing P3P headers in the response.
JFactory::getApplication()->setHeader('P3P',
'CP="' . $header . '"', true);
}
}
PK}��[�!$$p3p/p3p.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_p3p</name>
<author>Joomla! Project</author>
<creationDate>September 2010</creationDate>
<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_P3P_XML_DESCRIPTION</description>
<files>
<filename plugin="p3p">p3p.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_p3p.ini</language>
<language
tag="en-GB">en-GB.plg_system_p3p.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="header"
type="text"
label="PLG_P3P_HEADER_LABEL"
description="PLG_P3P_HEADER_DESCRIPTION"
default="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
size="37"
/>
</fieldset>
</fields>
</config>
</extension>
PK}��[��ɢ�
�
privacyconsent/field/privacy.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.privacyconsent
*
* @copyright (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
JFormHelper::loadFieldClass('radio');
/**
* Provides input for privacy
*
* @since 3.9.0
*/
class JFormFieldprivacy extends JFormFieldRadio
{
/**
* The form field type.
*
* @var string
* @since 3.9.0
*/
protected $type = 'privacy';
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*
* @since 3.9.0
*/
protected function getInput()
{
// Display the message before the field
echo
$this->getRenderer('plugins.system.privacyconsent.message')->render($this->getLayoutData());
return parent::getInput();
}
/**
* Method to get the field label markup.
*
* @return string The field label markup.
*
* @since 3.9.0
*/
protected function getLabel()
{
if ($this->hidden)
{
return '';
}
return
$this->getRenderer('plugins.system.privacyconsent.label')->render($this->getLayoutData());
}
/**
* Method to get the data to be passed to the layout for rendering.
*
* @return array
*
* @since 3.9.4
*/
protected function getLayoutData()
{
$data = parent::getLayoutData();
$article = false;
$privacyArticle = $this->element['article'] > 0 ? (int)
$this->element['article'] : 0;
if ($privacyArticle &&
Factory::getApplication()->isClient('site'))
{
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select($db->quoteName(array('id', 'alias',
'catid', 'language')))
->from($db->quoteName('#__content'))
->where($db->quoteName('id') . ' = ' . (int)
$privacyArticle);
$db->setQuery($query);
$article = $db->loadObject();
JLoader::register('ContentHelperRoute', JPATH_BASE .
'/components/com_content/helpers/route.php');
$slug = $article->alias ? ($article->id . ':' .
$article->alias) : $article->id;
$article->link = ContentHelperRoute::getArticleRoute($slug,
$article->catid, $article->language);
}
$extraData = array(
'privacynote' =>
!empty($this->element['note']) ?
$this->element['note'] :
Text::_('PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DEFAULT'),
'options' => $this->getOptions(),
'value' => (string) $this->value,
'translateLabel' => $this->translateLabel,
'translateDescription' => $this->translateDescription,
'translateHint' => $this->translateHint,
'privacyArticle' => $privacyArticle,
'article' => $article,
);
return array_merge($data, $extraData);
}
}
PK}��[�h=::0privacyconsent/privacyconsent/privacyconsent.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<form>
<fields name="privacyconsent">
<fieldset
name="privacyconsent"
label="PLG_SYSTEM_PRIVACYCONSENT_LABEL"
>
<field
name="privacy"
type="privacy"
label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_LABEL"
description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_DESC"
default="0"
filter="integer"
required="true"
>
<option
value="1">PLG_SYSTEM_PRIVACYCONSENT_OPTION_AGREE</option>
<option
value="0">PLG_SYSTEM_PRIVACYCONSENT_OPTION_DO_NOT_AGREE</option>
</field>
</fieldset>
</fields>
</form>
PK}��[1���MM!privacyconsent/privacyconsent.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.privacyconsent
*
* @copyright (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\Utilities\ArrayHelper;
/**
* An example custom privacyconsent plugin.
*
* @since 3.9.0
*/
class PlgSystemPrivacyconsent extends JPlugin
{
/**
* Load the language file on instantiation.
*
* @var boolean
* @since 3.9.0
*/
protected $autoloadLanguage = true;
/**
* Application object.
*
* @var JApplicationCms
* @since 3.9.0
*/
protected $app;
/**
* Database object.
*
* @var JDatabaseDriver
* @since 3.9.0
*/
protected $db;
/**
* Constructor
*
* @param object &$subject The object to observe
* @param array $config An array that holds the plugin
configuration
*
* @since 3.9.0
*/
public function __construct(&$subject, $config)
{
parent::__construct($subject, $config);
JFormHelper::addFieldPath(__DIR__ . '/field');
}
/**
* Adds additional fields to the user editing form
*
* @param JForm $form The form to be altered.
* @param mixed $data The associated data for the form.
*
* @return boolean
*
* @since 3.9.0
*/
public function onContentPrepareForm($form, $data)
{
if (!($form instanceof JForm))
{
$this->_subject->setError('JERROR_NOT_A_FORM');
return false;
}
// Check we are manipulating a valid form - we only display this on user
registration form and user profile form.
$name = $form->getName();
if (!in_array($name, array('com_users.profile',
'com_users.registration')))
{
return true;
}
// We only display this if user has not consented before
if (is_object($data))
{
$userId = isset($data->id) ? $data->id : 0;
if ($userId > 0 && $this->isUserConsented($userId))
{
return true;
}
}
// Add the privacy policy fields to the form.
JForm::addFormPath(__DIR__ . '/privacyconsent');
$form->loadFile('privacyconsent');
$privacyArticleId = $this->getPrivacyArticleId();
$privacynote = $this->params->get('privacy_note');
// Push the privacy article ID into the privacy field.
$form->setFieldAttribute('privacy', 'article',
$privacyArticleId, 'privacyconsent');
$form->setFieldAttribute('privacy', 'note',
$privacynote, 'privacyconsent');
}
/**
* Method is called before user data is stored in the database
*
* @param array $user Holds the old user data.
* @param boolean $isNew True if a new user is stored.
* @param array $data Holds the new user data.
*
* @return boolean
*
* @since 3.9.0
* @throws InvalidArgumentException on missing required data.
*/
public function onUserBeforeSave($user, $isNew, $data)
{
// // Only check for front-end user creation/update profile
if ($this->app->isClient('administrator'))
{
return true;
}
$userId = ArrayHelper::getValue($user, 'id', 0,
'int');
// User already consented before, no need to check it further
if ($userId > 0 && $this->isUserConsented($userId))
{
return true;
}
// Check that the privacy is checked if required ie only in registration
from frontend.
$option = $this->app->input->getCmd('option');
$task = $this->app->input->get->getCmd('task');
$form = $this->app->input->post->get('jform',
array(), 'array');
if ($option == 'com_users' && in_array($task,
array('registration.register', 'profile.save'))
&&
empty($form['privacyconsent']['privacy']))
{
throw new
InvalidArgumentException(Text::_('PLG_SYSTEM_PRIVACYCONSENT_FIELD_ERROR'));
}
return true;
}
/**
* Saves user privacy confirmation
*
* @param array $data entered user data
* @param boolean $isNew true if this is a new user
* @param boolean $result true if saving the user worked
* @param string $error error message
*
* @return boolean
*
* @since 3.9.0
*/
public function onUserAfterSave($data, $isNew, $result, $error)
{
// Only create an entry on front-end user creation/update profile
if ($this->app->isClient('administrator'))
{
return true;
}
// Get the user's ID
$userId = ArrayHelper::getValue($data, 'id', 0,
'int');
// If user already consented before, no need to check it further
if ($userId > 0 && $this->isUserConsented($userId))
{
return true;
}
$option = $this->app->input->getCmd('option');
$task = $this->app->input->get->getCmd('task');
$form = $this->app->input->post->get('jform',
array(), 'array');
if ($option == 'com_users'
&&in_array($task, array('registration.register',
'profile.save'))
&&
!empty($form['privacyconsent']['privacy']))
{
$userId = ArrayHelper::getValue($data, 'id', 0,
'int');
// Get the user's IP address
$ip =
$this->app->input->server->get('REMOTE_ADDR',
'', 'string');
// Get the user agent string
$userAgent =
$this->app->input->server->get('HTTP_USER_AGENT',
'', 'string');
// Create the user note
$userNote = (object) array(
'user_id' => $userId,
'subject' =>
'PLG_SYSTEM_PRIVACYCONSENT_SUBJECT',
'body' =>
Text::sprintf('PLG_SYSTEM_PRIVACYCONSENT_BODY', $ip, $userAgent),
'created' => Factory::getDate()->toSql(),
);
try
{
$this->db->insertObject('#__privacy_consents',
$userNote);
}
catch (Exception $e)
{
// Do nothing if the save fails
}
$userId = ArrayHelper::getValue($data, 'id', 0,
'int');
$message = array(
'action' => 'consent',
'id' => $userId,
'title' => $data['name'],
'itemlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$userId,
'userid' => $userId,
'username' => $data['username'],
'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$userId,
);
JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_actionlogs/models',
'ActionlogsModel');
/* @var ActionlogsModelActionlog $model */
$model = JModelLegacy::getInstance('Actionlog',
'ActionlogsModel');
$model->addLog(array($message),
'PLG_SYSTEM_PRIVACYCONSENT_CONSENT',
'plg_system_privacyconsent', $userId);
}
return true;
}
/**
* Remove all user privacy consent information for the given user ID
*
* Method is called after user data is deleted from the database
*
* @param array $user Holds the user data
* @param boolean $success True if user was successfully stored in the
database
* @param string $msg Message
*
* @return boolean
*
* @since 3.9.0
*/
public function onUserAfterDelete($user, $success, $msg)
{
if (!$success)
{
return false;
}
$userId = ArrayHelper::getValue($user, 'id', 0,
'int');
if ($userId)
{
// Remove user's consent
try
{
$query = $this->db->getQuery(true)
->delete($this->db->quoteName('#__privacy_consents'))
->where($this->db->quoteName('user_id') . ' =
' . (int) $userId);
$this->db->setQuery($query);
$this->db->execute();
}
catch (Exception $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}
return true;
}
/**
* If logged in users haven't agreed to privacy consent, redirect
them to profile edit page, ask them to agree to
* privacy consent before allowing access to any other pages
*
* @return void
*
* @since 3.9.0
*/
public function onAfterRoute()
{
// Run this in frontend only
if ($this->app->isClient('administrator'))
{
return;
}
$userId = Factory::getUser()->id;
// Check to see whether user already consented, if not, redirect to user
profile page
if ($userId > 0)
{
// If user consented before, no need to check it further
if ($this->isUserConsented($userId))
{
return;
}
$option = $this->app->input->getCmd('option');
$task = $this->app->input->get('task');
$view = $this->app->input->getString('view',
'');
$layout = $this->app->input->getString('layout',
'');
$id = $this->app->input->getInt('id');
$privacyArticleId = $this->getPrivacyArticleId();
/*
* If user is already on edit profile screen or view privacy article
* or press update/apply button, or logout, do nothing to avoid infinite
redirect
*/
if ($option == 'com_users' && in_array($task,
array('profile.save', 'profile.apply',
'user.logout', 'user.menulogout'))
|| ($option == 'com_content' && $view ==
'article' && $id == $privacyArticleId)
|| ($option == 'com_users' && $view ==
'profile' && $layout == 'edit'))
{
return;
}
// Redirect to com_users profile edit
$this->app->enqueueMessage($this->getRedirectMessage(),
'notice');
$link =
'index.php?option=com_users&view=profile&layout=edit';
$this->app->redirect(\JRoute::_($link, false));
}
}
/**
* Event to specify whether a privacy policy has been published.
*
* @param array &$policy The privacy policy status data, passed by
reference, with keys "published", "editLink" and
"articlePublished".
*
* @return void
*
* @since 3.9.0
*/
public function onPrivacyCheckPrivacyPolicyPublished(&$policy)
{
// If another plugin has already indicated a policy is published, we
won't change anything here
if ($policy['published'])
{
return;
}
$articleId = $this->params->get('privacy_article');
if (!$articleId)
{
return;
}
// Check if the article exists in database and is published
$query = $this->db->getQuery(true)
->select($this->db->quoteName(array('id',
'state')))
->from($this->db->quoteName('#__content'))
->where($this->db->quoteName('id') . ' = '
. (int) $articleId);
$this->db->setQuery($query);
$article = $this->db->loadObject();
// Check if the article exists
if (!$article)
{
return;
}
// Check if the article is published
if ($article->state == 1)
{
$policy['articlePublished'] = true;
}
$policy['published'] = true;
$policy['editLink'] =
JRoute::_('index.php?option=com_content&task=article.edit&id='
. $articleId);
}
/**
* Returns the configured redirect message and falls back to the default
version.
*
* @return string redirect message
*
* @since 3.9.0
*/
private function getRedirectMessage()
{
$messageOnRedirect =
trim($this->params->get('messageOnRedirect',
''));
if (empty($messageOnRedirect))
{
return
Text::_('PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DEFAULT');
}
return $messageOnRedirect;
}
/**
* Method to check if the given user has consented yet
*
* @param integer $userId ID of uer to check
*
* @return boolean
*
* @since 3.9.0
*/
private function isUserConsented($userId)
{
$query = $this->db->getQuery(true);
$query->select('COUNT(*)')
->from('#__privacy_consents')
->where('user_id = ' . (int) $userId)
->where('subject = ' .
$this->db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
->where('state = 1');
$this->db->setQuery($query);
return (int) $this->db->loadResult() > 0;
}
/**
* Get privacy article ID. If the site is a multilingual website and there
is associated article for the
* current language, ID of the associated article will be returned
*
* @return integer
*
* @since 3.9.0
*/
private function getPrivacyArticleId()
{
$privacyArticleId =
$this->params->get('privacy_article');
if ($privacyArticleId > 0 &&
JLanguageAssociations::isEnabled())
{
$privacyAssociated =
JLanguageAssociations::getAssociations('com_content',
'#__content', 'com_content.item', $privacyArticleId);
$currentLang = JFactory::getLanguage()->getTag();
if (isset($privacyAssociated[$currentLang]))
{
$privacyArticleId = $privacyAssociated[$currentLang]->id;
}
}
return $privacyArticleId;
}
/**
* The privacy consent expiration check code is triggered after the page
has fully rendered.
*
* @return void
*
* @since 3.9.0
*/
public function onAfterRender()
{
if (!$this->params->get('enabled', 0))
{
return;
}
$cacheTimeout = (int) $this->params->get('cachetimeout',
30);
$cacheTimeout = 24 * 3600 * $cacheTimeout;
// Do we need to run? Compare the last run timestamp stored in the
plugin's options with the current
// timestamp. If the difference is greater than the cache timeout we
shall not execute again.
$now = time();
$last = (int) $this->params->get('lastrun', 0);
if ((abs($now - $last) < $cacheTimeout))
{
return;
}
// Update last run status
$this->params->set('lastrun', $now);
$db = $this->db;
$query = $db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('params') . ' = ' .
$db->quote($this->params->toString('JSON')))
->where($db->quoteName('type') . ' = ' .
$db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' .
$db->quote('system'))
->where($db->quoteName('element') . ' = ' .
$db->quote('privacyconsent'));
try
{
// Lock the tables to prevent multiple plugin executions causing a race
condition
$db->lockTable('#__extensions');
}
catch (Exception $e)
{
// If we can't lock the tables it's too risky to continue
execution
return;
}
try
{
// Update the plugin parameters
$result = $db->setQuery($query)->execute();
$this->clearCacheGroups(array('com_plugins'), array(0, 1));
}
catch (Exception $exc)
{
// If we failed to execute
$db->unlockTables();
$result = false;
}
try
{
// Unlock the tables after writing
$db->unlockTables();
}
catch (Exception $e)
{
// If we can't lock the tables assume we have somehow failed
$result = false;
}
// Abort on failure
if (!$result)
{
return;
}
// Delete the expired privacy consents
$this->invalidateExpiredConsents();
// Remind for privacy consents near to expire
$this->remindExpiringConsents();
}
/**
* Method to send the remind for privacy consents renew
*
* @return integer
*
* @since 3.9.0
*/
private function remindExpiringConsents()
{
// Load the parameters.
$expire = (int) $this->params->get('consentexpiration',
365);
$remind = (int) $this->params->get('remind', 30);
$now = JFactory::getDate()->toSql();
$period = '-' . ($expire - $remind);
$db = $this->db;
$query = $db->getQuery(true)
->select($db->quoteName(array('r.id',
'r.user_id', 'u.email')))
->from($db->quoteName('#__privacy_consents',
'r'))
->leftJoin($db->quoteName('#__users', 'u') .
' ON u.id = r.user_id')
->where($db->quoteName('subject') . ' = ' .
$db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
->where($db->quoteName('remind') . ' = 0');
$query->where($query->dateAdd($db->quote($now), $period,
'DAY') . ' > ' .
$db->quoteName('created'));
try
{
$users = $db->setQuery($query)->loadObjectList();
}
catch (JDatabaseException $exception)
{
return false;
}
$app = JFactory::getApplication();
$linkMode = $app->get('force_ssl', 0) == 2 ?
Route::TLS_FORCE : Route::TLS_IGNORE;
foreach ($users as $user)
{
$token =
JApplicationHelper::getHash(JUserHelper::genRandomPassword());
$hashedToken = JUserHelper::hashPassword($token);
// The mail
try
{
$substitutions = array(
'[SITENAME]' => $app->get('sitename'),
'[URL]' => JUri::root(),
'[TOKENURL]' => JRoute::link('site',
'index.php?option=com_privacy&view=remind&remind_token='
. $token, false, $linkMode, true),
'[FORMURL]' => JRoute::link('site',
'index.php?option=com_privacy&view=remind', false, $linkMode,
true),
'[TOKEN]' => $token,
'\\n' => "\n",
);
$emailSubject =
JText::_('PLG_SYSTEM_PRIVACYCONSENT_EMAIL_REMIND_SUBJECT');
$emailBody =
JText::_('PLG_SYSTEM_PRIVACYCONSENT_EMAIL_REMIND_BODY');
foreach ($substitutions as $k => $v)
{
$emailSubject = str_replace($k, $v, $emailSubject);
$emailBody = str_replace($k, $v, $emailBody);
}
$mailer = JFactory::getMailer();
$mailer->setSubject($emailSubject);
$mailer->setBody($emailBody);
$mailer->addRecipient($user->email);
$mailResult = $mailer->Send();
if ($mailResult instanceof JException)
{
return false;
}
elseif ($mailResult === false)
{
return false;
}
// Update the privacy_consents item to not send the reminder again
$query->clear()
->update($db->quoteName('#__privacy_consents'))
->set($db->quoteName('remind') . ' = 1 ')
->set($db->quoteName('token') . ' = ' .
$db->quote($hashedToken))
->where($db->quoteName('id') . ' = ' . (int)
$user->id);
$db->setQuery($query);
try
{
$db->execute();
}
catch (RuntimeException $e)
{
return false;
}
}
catch (phpmailerException $exception)
{
return false;
}
}
}
/**
* Method to delete the expired privacy consents
*
* @return boolean
*
* @since 3.9.0
*/
private function invalidateExpiredConsents()
{
// Load the parameters.
$expire = (int) $this->params->get('consentexpiration',
365);
$now = JFactory::getDate()->toSql();
$period = '-' . $expire;
$db = $this->db;
$query = $db->getQuery(true);
$query->select($db->quoteName(array('id',
'user_id')))
->from($db->quoteName('#__privacy_consents'))
->where($query->dateAdd($db->quote($now), $period,
'DAY') . ' > ' .
$db->quoteName('created'))
->where($db->quoteName('subject') . ' = ' .
$db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
->where($db->quoteName('state') . ' = 1');
$db->setQuery($query);
try
{
$users = $db->loadObjectList();
}
catch (RuntimeException $e)
{
return false;
}
// Do not process further if no expired consents found
if (empty($users))
{
return true;
}
// Push a notification to the site's super users
JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_messages/models', 'MessagesModel');
JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_messages/tables');
/** @var MessagesModelMessage $messageModel */
$messageModel = JModelLegacy::getInstance('Message',
'MessagesModel');
foreach ($users as $user)
{
$query = $db->getQuery(true)
->update($db->quoteName('#__privacy_consents'))
->set('state = 0')
->where($db->quoteName('id') . ' = ' . (int)
$user->id);
$db->setQuery($query);
try
{
$db->execute();
}
catch (RuntimeException $e)
{
return false;
}
$messageModel->notifySuperUsers(
JText::_('PLG_SYSTEM_PRIVACYCONSENT_NOTIFICATION_USER_PRIVACY_EXPIRED_SUBJECT'),
JText::sprintf('PLG_SYSTEM_PRIVACYCONSENT_NOTIFICATION_USER_PRIVACY_EXPIRED_MESSAGE',
JFactory::getUser($user->user_id)->username)
);
}
return true;
}
/**
* Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
*
* @param array $clearGroups The cache groups to clean
* @param array $cacheClients The cache clients (site, admin) to clean
*
* @return void
*
* @since 3.9.0
*/
private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
{
$conf = JFactory::getConfig();
foreach ($clearGroups as $group)
{
foreach ($cacheClients as $client_id)
{
try
{
$options = array(
'defaultgroup' => $group,
'cachebase' => $client_id ? JPATH_ADMINISTRATOR .
'/cache' :
$conf->get('cache_path', JPATH_SITE .
'/cache')
);
$cache = JCache::getInstance('callback', $options);
$cache->clean();
}
catch (Exception $e)
{
// Ignore it
}
}
}
}
}
PK}��[�UqGJ
J
!privacyconsent/privacyconsent.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="system" method="upgrade">
<name>plg_system_privacyconsent</name>
<author>Joomla! Project</author>
<creationDate>April 2018</creationDate>
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.9.0</version>
<description>PLG_SYSTEM_PRIVACYCONSENT_XML_DESCRIPTION</description>
<files>
<filename
plugin="privacyconsent">privacyconsent.php</filename>
<folder>privacyconsent</folder>
<folder>field</folder>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_privacyconsent.ini</language>
<language
tag="en-GB">en-GB.plg_system_privacyconsent.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic"
addfieldpath="/administrator/components/com_content/models/fields">
<field
name="privacy_note"
type="textarea"
label="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_LABEL"
description="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DESC"
hint="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DEFAULT"
class="span12"
rows="7"
cols="20"
filter="html"
/>
<field
name="privacy_article"
type="modal_article"
label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ARTICLE_LABEL"
description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ARTICLE_DESC"
select="true"
new="true"
edit="true"
clear="true"
filter="integer"
/>
<field
name="messageOnRedirect"
type="textarea"
label="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_LABEL"
description="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DESC"
hint="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DEFAULT"
class="span12"
rows="7"
cols="20"
filter="html"
/>
</fieldset>
<fieldset
name="expiration"
label="PLG_SYSTEM_PRIVACYCONSENT_EXPIRATION_FIELDSET_LABEL"
>
<field
name="enabled"
type="radio"
label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ENABLED_LABEL"
description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ENABLED_DESC"
class="btn-group btn-group-yesno"
default="0"
filter="integer"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="cachetimeout"
type="integer"
label="PLG_SYSTEM_PRIVACYCONSENT_CACHETIMEOUT_LABEL"
description="PLG_SYSTEM_PRIVACYCONSENT_CACHETIMEOUT_DESC"
first="0"
last="120"
step="1"
default="30"
filter="int"
validate="number"
/>
<field
name="consentexpiration"
type="integer"
label="PLG_SYSTEM_PRIVACYCONSENT_CONSENTEXPIRATION_LABEL"
description="PLG_SYSTEM_PRIVACYCONSENT_CONSENTEXPIRATION_DESC"
first="180"
last="720"
step="30"
default="360"
filter="int"
validate="number"
/>
<field
name="remind"
type="integer"
label="PLG_SYSTEM_PRIVACYCONSENT_REMINDBEFORE_LABEL"
description="PLG_SYSTEM_PRIVACYCONSENT_REMINDBEFORE_DESC"
first="0"
last="120"
step="1"
default="30"
filter="int"
validate="number"
/>
<field
name="lastrun"
type="hidden"
default="0"
filter="integer"
/>
</fieldset>
</fields>
</config>
</extension>
PK}��[1�r��redirect/form/excludes.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<form>
<fieldset>
<field
name="term"
type="text"
label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_TERM_LABEL"
description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_TERM_DESC"
required="true"
/>
<field
name="regexp"
type="checkbox"
label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_REGEXP_LABEL"
description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_REGEXP_DESC"
filter="integer"
/>
</fieldset>
</form>
PK}��[�6j�%&%&redirect/redirect.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.redirect
*
* @copyright (C) 2009 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\Registry\Registry;
use Joomla\String\StringHelper;
/**
* Plugin class for redirect handling.
*
* @since 1.6
*/
class PlgSystemRedirect extends JPlugin
{
/**
* Affects constructor behavior. If true, language files will be loaded
automatically.
*
* @var boolean
* @since 3.4
*/
protected $autoloadLanguage = false;
/**
* The global exception handler registered before the plugin was
instantiated
*
* @var callable
* @since 3.6
*/
private static $previousExceptionHandler;
/**
* Constructor.
*
* @param object &$subject The object to observe
* @param array $config An optional associative array of
configuration settings.
*
* @since 1.6
*/
public function __construct(&$subject, $config)
{
parent::__construct($subject, $config);
// Set the JError handler for E_ERROR to be the class' handleError
method.
JError::setErrorHandling(E_ERROR, 'callback',
array('PlgSystemRedirect', 'handleError'));
// Register the previously defined exception handler so we can forward
errors to it
self::$previousExceptionHandler =
set_exception_handler(array('PlgSystemRedirect',
'handleException'));
}
/**
* Method to handle an error condition from JError.
*
* @param JException $error The JException object to be handled.
*
* @return void
*
* @since 1.6
*/
public static function handleError(JException $error)
{
self::doErrorHandling($error);
}
/**
* Method to handle an uncaught exception.
*
* @param Exception|Throwable $exception The Exception or Throwable
object to be handled.
*
* @return void
*
* @since 3.5
* @throws InvalidArgumentException
*/
public static function handleException($exception)
{
// If this isn't a Throwable then bail out
if (!($exception instanceof Throwable) && !($exception instanceof
Exception))
{
throw new InvalidArgumentException(
sprintf('The error handler requires an Exception or Throwable
object, a "%s" object was given instead.',
get_class($exception))
);
}
self::doErrorHandling($exception);
}
/**
* Internal processor for all error handlers
*
* @param Exception|Throwable $error The Exception or Throwable object
to be handled.
*
* @return void
*
* @since 3.5
*/
private static function doErrorHandling($error)
{
$app = JFactory::getApplication();
if ($app->isClient('administrator') || ((int)
$error->getCode() !== 404))
{
// Proxy to the previous exception handler if available, otherwise just
render the error page
if (self::$previousExceptionHandler)
{
call_user_func_array(self::$previousExceptionHandler, array($error));
}
else
{
JErrorPage::render($error);
}
}
$uri = JUri::getInstance();
// These are the original URLs
$orgurl =
rawurldecode($uri->toString(array('scheme', 'host',
'port', 'path', 'query',
'fragment')));
$orgurlRel =
rawurldecode($uri->toString(array('path', 'query',
'fragment')));
// The above doesn't work for sub directories, so do this
$orgurlRootRel = str_replace(JUri::root(), '',
$orgurl);
// For when users have added / to the url
$orgurlRootRelSlash = str_replace(JUri::root(), '/',
$orgurl);
$orgurlWithoutQuery =
rawurldecode($uri->toString(array('scheme', 'host',
'port', 'path', 'fragment')));
$orgurlRelWithoutQuery =
rawurldecode($uri->toString(array('path',
'fragment')));
// These are the URLs we save and use
$url =
StringHelper::strtolower(rawurldecode($uri->toString(array('scheme',
'host', 'port', 'path', 'query',
'fragment'))));
$urlRel =
StringHelper::strtolower(rawurldecode($uri->toString(array('path',
'query', 'fragment'))));
// The above doesn't work for sub directories, so do this
$urlRootRel = str_replace(JUri::root(), '', $url);
// For when users have added / to the url
$urlRootRelSlash = str_replace(JUri::root(), '/', $url);
$urlWithoutQuery =
StringHelper::strtolower(rawurldecode($uri->toString(array('scheme',
'host', 'port', 'path',
'fragment'))));
$urlRelWithoutQuery =
StringHelper::strtolower(rawurldecode($uri->toString(array('path',
'fragment'))));
$plugin = JPluginHelper::getPlugin('system',
'redirect');
$params = new Registry($plugin->params);
$excludes = (array) $params->get('exclude_urls');
$skipUrl = false;
foreach ($excludes as $exclude)
{
if (empty($exclude->term))
{
continue;
}
if (!empty($exclude->regexp))
{
// Only check $url, because it includes all other sub urls
if (preg_match('/' . $exclude->term . '/i',
$orgurlRel))
{
$skipUrl = true;
break;
}
}
else
{
if (StringHelper::strpos($orgurlRel, $exclude->term) !== false)
{
$skipUrl = true;
break;
}
}
}
// Why is this (still) here?
if ($skipUrl || (strpos($url, 'mosConfig_') !== false) ||
(strpos($url, '=http://') !== false))
{
JErrorPage::render($error);
}
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('*')
->from($db->quoteName('#__redirect_links'))
->where(
'('
. $db->quoteName('old_url') . ' = ' .
$db->quote($url)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($urlRel)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($urlRootRel)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($urlRootRelSlash)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($urlWithoutQuery)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($urlRelWithoutQuery)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurl)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlRel)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlRootRel)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlRootRelSlash)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlWithoutQuery)
. ' OR '
. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlRelWithoutQuery)
. ')'
);
$db->setQuery($query);
$redirect = null;
try
{
$redirects = $db->loadAssocList();
}
catch (Exception $e)
{
JErrorPage::render(new
Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'),
500, $e));
}
$possibleMatches = array_unique(
array(
$url,
$urlRel,
$urlRootRel,
$urlRootRelSlash,
$urlWithoutQuery,
$urlRelWithoutQuery,
$orgurl,
$orgurlRel,
$orgurlRootRel,
$orgurlRootRelSlash,
$orgurlWithoutQuery,
$orgurlRelWithoutQuery,
)
);
foreach ($possibleMatches as $match)
{
if (($index = array_search($match, array_column($redirects,
'old_url'))) !== false)
{
$redirect = (object) $redirects[$index];
if ((int) $redirect->published === 1)
{
break;
}
}
}
// A redirect object was found and, if published, will be used
if ($redirect !== null && ((int) $redirect->published === 1))
{
if (!$redirect->header || (bool)
JComponentHelper::getParams('com_redirect')->get('mode',
false) === false)
{
$redirect->header = 301;
}
if ($redirect->header < 400 && $redirect->header >=
300)
{
$urlQuery = $uri->getQuery();
$oldUrlParts = parse_url($redirect->old_url);
$newUrl = $redirect->new_url;
if ($urlQuery !== '' &&
empty($oldUrlParts['query']))
{
$newUrl .= '?' . $urlQuery;
}
$dest = JUri::isInternal($newUrl) || strpos($newUrl, 'http')
=== false ?
JRoute::_($newUrl) : $newUrl;
// In case the url contains double // lets remove it
$destination = str_replace(JUri::root() . '/', JUri::root(),
$dest);
// Always count redirect hits
$redirect->hits++;
try
{
$db->updateObject('#__redirect_links', $redirect,
'id');
}
catch (Exception $e)
{
// We don't log issues for now
}
$app->redirect($destination, (int) $redirect->header);
}
JErrorPage::render(new RuntimeException($error->getMessage(),
$redirect->header, $error));
}
// No redirect object was found so we create an entry in the redirect
table
elseif ($redirect === null)
{
$params = new Registry(JPluginHelper::getPlugin('system',
'redirect')->params);
if ((bool) $params->get('collect_urls', 1))
{
if (!$params->get('includeUrl', 1))
{
$url = $urlRel;
}
$data = (object) array(
'id' => 0,
'old_url' => $url,
'referer' =>
$app->input->server->getString('HTTP_REFERER',
''),
'hits' => 1,
'published' => 0,
'created_date' => JFactory::getDate()->toSql()
);
try
{
$db->insertObject('#__redirect_links', $data,
'id');
}
catch (Exception $e)
{
JErrorPage::render(new
Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'),
500, $e));
}
}
}
// We have an unpublished redirect object, increment the hit counter
else
{
$redirect->hits++;
try
{
$db->updateObject('#__redirect_links', $redirect,
'id');
}
catch (Exception $e)
{
JErrorPage::render(new
Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'),
500, $e));
}
}
// Proxy to the previous exception handler if available, otherwise just
render the error page
if (self::$previousExceptionHandler)
{
call_user_func_array(self::$previousExceptionHandler, array($error));
}
else
{
JErrorPage::render($error);
}
}
}
PK}��[-LS�TTredirect/redirect.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_redirect</name>
<author>Joomla! Project</author>
<creationDate>April 2009</creationDate>
<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_SYSTEM_REDIRECT_XML_DESCRIPTION</description>
<files>
<folder>form</folder>
<filename plugin="redirect">redirect.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_redirect.ini</language>
<language
tag="en-GB">en-GB.plg_system_redirect.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="collect_urls"
type="radio"
label="PLG_SYSTEM_REDIRECT_FIELD_COLLECT_URLS_LABEL"
description="PLG_SYSTEM_REDIRECT_FIELD_COLLECT_URLS_DESC"
default="1"
filter="integer"
class="btn-group btn-group-yesno"
>
<option value="1">JENABLED</option>
<option value="0">JDISABLED</option>
</field>
<field
name="includeUrl"
type="radio"
label="PLG_SYSTEM_REDIRECT_FIELD_STORE_FULL_URL_LABEL"
description="PLG_SYSTEM_REDIRECT_FIELD_STORE_FULL_URL_DESC"
default="1"
filter="integer"
class="btn-group btn-group-yesno"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="exclude_urls"
type="subform"
label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_LABEL"
description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_DESC"
multiple="true"
formsource="plugins/system/redirect/form/excludes.xml"
/>
</fieldset>
</fields>
</config>
</extension>
PK}��[���
�
remember/remember.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.remember
*
* @copyright (C) 2007 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Joomla! System Remember Me Plugin
*
* @since 1.5
*/
class PlgSystemRemember extends JPlugin
{
/**
* Application object.
*
* @var JApplicationCms
* @since 3.2
*/
protected $app;
/**
* Remember me method to run onAfterInitialise
* Only purpose is to initialise the login authentication process if a
cookie is present
*
* @return void
*
* @since 1.5
* @throws InvalidArgumentException
*/
public function onAfterInitialise()
{
// Get the application if not done by JPlugin. This may happen during
upgrades from Joomla 2.5.
if (!$this->app)
{
$this->app = JFactory::getApplication();
}
// No remember me for admin.
if ($this->app->isClient('administrator'))
{
return;
}
// Check for a cookie if user is not logged in
if (JFactory::getUser()->get('guest'))
{
$cookieName = 'joomla_remember_me_' .
JUserHelper::getShortHashedUserAgent();
// Try with old cookieName (pre 3.6.0) if not found
if (!$this->app->input->cookie->get($cookieName))
{
$cookieName = JUserHelper::getShortHashedUserAgent();
}
// Check for the cookie
if ($this->app->input->cookie->get($cookieName))
{
$this->app->login(array('username' => ''),
array('silent' => true));
}
}
}
/**
* Imports the authentication plugin on user logout to make sure that the
cookie is destroyed.
*
* @param array $user Holds the user data.
* @param array $options Array holding options (remember,
autoregister, group).
*
* @return boolean
*/
public function onUserLogout($user, $options)
{
// No remember me for admin
if ($this->app->isClient('administrator'))
{
return true;
}
$cookieName = 'joomla_remember_me_' .
JUserHelper::getShortHashedUserAgent();
// Check for the cookie
if ($this->app->input->cookie->get($cookieName))
{
// Make sure authentication group is loaded to process onUserAfterLogout
event
JPluginHelper::importPlugin('authentication');
}
return true;
}
/**
* Method is called before user data is stored in the database
* Invalidate all existing remember-me cookies after a password change
*
* @param array $user Holds the old user data.
* @param boolean $isnew True if a new user is stored.
* @param array $data Holds the new user data.
*
* @return boolean
*
* @since 3.8.6
*/
public function onUserBeforeSave($user, $isnew, $data)
{
// Irrelevant on new users
if ($isnew)
{
return true;
}
// Irrelevant, because password was not changed by user
if (empty($data['password_clear']))
{
return true;
}
/*
* But now, we need to do something
* Delete all tokens for this user!
*/
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->delete('#__user_keys')
->where($db->quoteName('user_id') . ' = ' .
$db->quote($user['username']));
try
{
$db->setQuery($query)->execute();
}
catch (RuntimeException $e)
{
// Log an alert for the site admin
JLog::add(
sprintf('Failed to delete cookie token for user %s with the
following error: %s', $user['username'],
$e->getMessage()),
JLog::WARNING,
'security'
);
}
return true;
}
}
PK}��[�-��remember/remember.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_remember</name>
<author>Joomla! Project</author>
<creationDate>April 2007</creationDate>
<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_REMEMBER_XML_DESCRIPTION</description>
<files>
<filename plugin="remember">remember.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_remember.ini</language>
<language
tag="en-GB">en-GB.plg_system_remember.sys.ini</language>
</languages>
</extension>
PK}��[?>� ��sef/sef.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.sef
*
* @copyright (C) 2007 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Joomla! SEF Plugin.
*
* @since 1.5
*/
class PlgSystemSef extends JPlugin
{
/**
* Application object.
*
* @var JApplicationCms
* @since 3.5
*/
protected $app;
/**
* Add the canonical uri to the head.
*
* @return void
*
* @since 3.5
*/
public function onAfterDispatch()
{
$doc = $this->app->getDocument();
if (!$this->app->isClient('site') || $doc->getType()
!== 'html')
{
return;
}
$sefDomain = $this->params->get('domain', false);
// Don't add a canonical html tag if no alternative domain has added
in SEF plugin domain field.
if (empty($sefDomain))
{
return;
}
// Check if a canonical html tag already exists (for instance, added by a
component).
$canonical = '';
foreach ($doc->_links as $linkUrl => $link)
{
if (isset($link['relation']) &&
$link['relation'] === 'canonical')
{
$canonical = $linkUrl;
break;
}
}
// If a canonical html tag already exists get the canonical and change it
to use the SEF plugin domain field.
if (!empty($canonical))
{
// Remove current canonical link.
unset($doc->_links[$canonical]);
// Set the current canonical link but use the SEF system plugin domain
field.
$canonical = $sefDomain .
JUri::getInstance($canonical)->toString(array('path',
'query', 'fragment'));
}
// If a canonical html doesn't exists already add a canonical html
tag using the SEF plugin domain field.
else
{
$canonical = $sefDomain .
JUri::getInstance()->toString(array('path', 'query',
'fragment'));
}
// Add the canonical link.
$doc->addHeadLink(htmlspecialchars($canonical),
'canonical');
}
/**
* Convert the site URL to fit to the HTTP request.
*
* @return void
*/
public function onAfterRender()
{
if (!$this->app->isClient('site'))
{
return;
}
// Replace src links.
$base = JUri::base(true) . '/';
$buffer = $this->app->getBody();
// For feeds we need to search for the URL with domain.
$prefix = $this->app->getDocument()->getType() ===
'feed' ? JUri::root() : '';
// Replace index.php URI by SEF URI.
if (strpos($buffer, 'href="' . $prefix .
'index.php?') !== false)
{
preg_match_all('#href="' . $prefix .
'index.php\?([^"]+)"#m', $buffer, $matches);
foreach ($matches[1] as $urlQueryString)
{
$buffer = str_replace(
'href="' . $prefix . 'index.php?' .
$urlQueryString . '"',
'href="' . trim($prefix, '/') .
JRoute::_('index.php?' . $urlQueryString) . '"',
$buffer
);
}
$this->checkBuffer($buffer);
}
// Check for all unknown protocols (a protocol must contain at least one
alphanumeric character followed by a ":").
$protocols = '[a-zA-Z0-9\-]+:';
$attributes = array('href=', 'src=',
'poster=');
foreach ($attributes as $attribute)
{
if (strpos($buffer, $attribute) !== false)
{
$regex = '#\s' . $attribute . '"(?!/|' .
$protocols . '|\#|\')([^"]*)"#m';
$buffer = preg_replace($regex, ' ' . $attribute .
'"' . $base . '$1"', $buffer);
$this->checkBuffer($buffer);
}
}
if (strpos($buffer, 'srcset=') !== false)
{
$regex = '#\s+srcset="([^"]+)"#m';
$buffer = preg_replace_callback(
$regex,
function ($match) use ($base, $protocols)
{
preg_match_all('#(?:[^\s]+)\s*(?:[\d\.]+[wx])?(?:\,\s*)?#i',
$match[1], $matches);
foreach ($matches[0] as &$src)
{
$src = preg_replace('#^(?!/|' . $protocols .
'|\#|\')(.+)#', $base . '$1', $src);
}
return ' srcset="' . implode($matches[0]) .
'"';
},
$buffer
);
$this->checkBuffer($buffer);
}
// Replace all unknown protocols in javascript window open events.
if (strpos($buffer, 'window.open(') !== false)
{
$regex = '#onclick="window.open\(\'(?!/|' .
$protocols . '|\#)([^/]+[^\']*?\')#m';
$buffer = preg_replace($regex,
'onclick="window.open(\'' . $base . '$1',
$buffer);
$this->checkBuffer($buffer);
}
// Replace all unknown protocols in onmouseover and onmouseout
attributes.
$attributes = array('onmouseover=', 'onmouseout=');
foreach ($attributes as $attribute)
{
if (strpos($buffer, $attribute) !== false)
{
$regex = '#' . $attribute .
'"this.src=([\']+)(?!/|' . $protocols .
'|\#|\')([^"]+)"#m';
$buffer = preg_replace($regex, $attribute .
'"this.src=$1' . $base . '$2"', $buffer);
$this->checkBuffer($buffer);
}
}
// Replace all unknown protocols in CSS background image.
if (strpos($buffer, 'style=') !== false)
{
$regex_url =
'\s*url\s*\(([\'\"]|\&\#0?3[49];)?(?!/|\&\#0?3[49];|'
. $protocols .
'|\#)([^\)\'\"]+)([\'\"]|\&\#0?3[49];)?\)';
$regex = '#style=\s*([\'\"])(.*):' . $regex_url .
'#m';
$buffer = preg_replace($regex, 'style=$1$2: url($3' . $base .
'$4$5)', $buffer);
$this->checkBuffer($buffer);
}
// Replace all unknown protocols in OBJECT param tag.
if (strpos($buffer, '<param') !== false)
{
// OBJECT <param name="xx", value="yy"> -- fix
it only inside the <param> tag.
$regex =
'#(<param\s+)name\s*=\s*"(movie|src|url)"[^>]\s*value\s*=\s*"(?!/|'
. $protocols . '|\#|\')([^"]*)"#m';
$buffer = preg_replace($regex, '$1name="$2"
value="' . $base . '$3"', $buffer);
$this->checkBuffer($buffer);
// OBJECT <param value="xx", name="yy"> -- fix
it only inside the <param> tag.
$regex = '#(<param\s+[^>]*)value\s*=\s*"(?!/|' .
$protocols .
'|\#|\')([^"]*)"\s*name\s*=\s*"(movie|src|url)"#m';
$buffer = preg_replace($regex, '<param value="' .
$base . '$2" name="$3"', $buffer);
$this->checkBuffer($buffer);
}
// Replace all unknown protocols in OBJECT tag.
if (strpos($buffer, '<object') !== false)
{
$regex = '#(<object\s+[^>]*)data\s*=\s*"(?!/|' .
$protocols . '|\#|\')([^"]*)"#m';
$buffer = preg_replace($regex, '$1data="' . $base .
'$2"', $buffer);
$this->checkBuffer($buffer);
}
// Use the replaced HTML body.
$this->app->setBody($buffer);
}
/**
* Check the buffer.
*
* @param string $buffer Buffer to be checked.
*
* @return void
*/
private function checkBuffer($buffer)
{
if ($buffer === null)
{
switch (preg_last_error())
{
case PREG_BACKTRACK_LIMIT_ERROR:
$message = 'PHP regular expression limit reached
(pcre.backtrack_limit)';
break;
case PREG_RECURSION_LIMIT_ERROR:
$message = 'PHP regular expression limit reached
(pcre.recursion_limit)';
break;
case PREG_BAD_UTF8_ERROR:
$message = 'Bad UTF8 passed to PCRE function';
break;
default:
$message = 'Unknown PCRE error calling PCRE function';
}
throw new RuntimeException($message);
}
}
/**
* Replace the matched tags.
*
* @param array &$matches An array of matches (see
preg_match_all).
*
* @return string
*
* @deprecated 4.0 No replacement.
*/
protected static function route(&$matches)
{
JLog::add(__METHOD__ . ' is deprecated, no replacement.',
JLog::WARNING, 'deprecated');
$url = $matches[1];
$url = str_replace('&', '&', $url);
$route = JRoute::_('index.php?' . $url);
return 'href="' . $route;
}
}
PK}��[n*mf sef/sef.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
<name>plg_system_sef</name>
<author>Joomla! Project</author>
<creationDate>December 2007</creationDate>
<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_SEF_XML_DESCRIPTION</description>
<files>
<filename plugin="sef">sef.php</filename>
</files>
<languages>
<language
tag="en-GB">en-GB.plg_system_sef.ini</language>
<language
tag="en-GB">en-GB.plg_system_sef.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="domain"
type="url"
label="PLG_SEF_DOMAIN_LABEL"
description="PLG_SEF_DOMAIN_DESCRIPTION"
hint="https://www.example.com"
filter="url"
validate="url"
/>
</fieldset>
</fields>
</config>
</extension>
PK}��[ҽ�F��sessiongc/sessiongc.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.sessiongc
*
* @copyright (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Session\MetadataManager;
/**
* Garbage collection handler for session related data
*
* @since 3.8.6
*/
class PlgSystemSessionGc extends CMSPlugin
{
/**
* Application object
*
* @var CMSApplication
* @since 3.8.6
*/
protected $app;
/**
* Database driver
*
* @var JDatabaseDriver
* @since 3.8.6
*/
protected $db;
/**
* Runs after the HTTP response has been sent to the client and performs
garbage collection tasks
*
* @return void
*
* @since 3.8.6
*/
public function onAfterRespond()
{
$session = Factory::getSession();
if ($this->params->get('enable_session_gc', 1))
{
$probability = $this->params->get('gc_probability', 1);
$divisor = $this->params->get('gc_divisor', 100);
$random = $divisor * lcg_value();
if ($probability > 0 && $random < $probability)
{
$session->gc();
}
}
if ($this->app->get('session_handler', 'none')
!== 'database' &&
$this->params->get('enable_session_metadata_gc', 1))
{
$probability = $this->params->get('gc_probability', 1);
$divisor = $this->params->get('gc_divisor', 100);
$random = $divisor * lcg_value();
if ($probability > 0 && $random < $probability)
{
$metadataManager = new MetadataManager($this->app, $this->db);
$metadataManager->deletePriorTo(time() - $session->getExpire());
}
}
}
}
PK}��[sPw��sessiongc/sessiongc.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin"
group="system" method="upgrade">
<name>plg_system_sessiongc</name>
<author>Joomla! Project</author>
<creationDate>February 2018</creationDate>
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.8.6</version>
<description>PLG_SYSTEM_SESSIONGC_XML_DESCRIPTION</description>
<files>
<filename
plugin="sessiongc">sessiongc.php</filename>
</files>
<languages folder="language">
<language
tag="en-GB">en-GB/en-GB.plg_system_sessiongc.ini</language>
<language
tag="en-GB">en-GB/en-GB.plg_system_sessiongc.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="enable_session_gc"
type="radio"
label="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_GC_LABEL"
description="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_GC_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="uint"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="enable_session_metadata_gc"
type="radio"
label="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_METADATA_GC_LABEL"
description="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_METADATA_GC_DESC"
class="btn-group btn-group-yesno"
default="1"
filter="uint"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field
name="gc_probability"
type="number"
label="PLG_SYSTEM_SESSIONGC_GC_PROBABILITY_LABEL"
description="PLG_SYSTEM_SESSIONGC_GC_PROBABILITY_DESC"
filter="uint"
validate="number"
min="1"
default="1"
showon="enable_session_gc:1[OR]enable_session_metadata_gc:1"
/>
<field
name="gc_divisor"
type="number"
label="PLG_SYSTEM_SESSIONGC_GC_DIVISOR_LABEL"
description="PLG_SYSTEM_SESSIONGC_GC_DIVISOR_DESC"
filter="uint"
validate="number"
min="1"
default="100"
showon="enable_session_gc:1[OR]enable_session_metadata_gc:1"
/>
</fieldset>
</fields>
</config>
</extension>
PK}��[�V���stats/field/base.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.stats
*
* @copyright (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
/**
* Base field for the Stats Plugin.
*
* @since 3.5
*/
abstract class PlgSystemStatsFormFieldBase extends JFormField
{
/**
* Get the layouts paths
*
* @return array
*
* @since 3.5
*/
protected function getLayoutPaths()
{
$template = JFactory::getApplication()->getTemplate();
return array(
JPATH_ADMINISTRATOR . '/templates/' . $template .
'/html/layouts/plugins/system/stats',
dirname(__DIR__) . '/layouts',
JPATH_SITE . '/layouts'
);
}
}
PK}��[G!E���stats/field/data.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.stats
*
* @copyright (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
JLoader::register('PlgSystemStatsFormFieldBase', __DIR__ .
'/base.php');
/**
* Unique ID Field class for the Stats Plugin.
*
* @since 3.5
*/
class PlgSystemStatsFormFieldData extends PlgSystemStatsFormFieldBase
{
/**
* The form field type.
*
* @var string
* @since 3.5
*/
protected $type = 'Data';
/**
* Name of the layout being used to render the field
*
* @var string
* @since 3.5
*/
protected $layout = 'field.data';
/**
* Method to get the data to be passed to the layout for rendering.
*
* @return array
*
* @since 3.5
*/
protected function getLayoutData()
{
$data = parent::getLayoutData();
$dispatcher = JEventDispatcher::getInstance();
JPluginHelper::importPlugin('system', 'stats');
$result = $dispatcher->trigger('onGetStatsData',
array('stats.field.data'));
$data['statsData'] = $result ? reset($result) : array();
return $data;
}
}
PK}��[EN8��stats/field/uniqueid.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.stats
*
* @copyright (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
JLoader::register('PlgSystemStatsFormFieldBase', __DIR__ .
'/base.php');
/**
* Unique ID Field class for the Stats Plugin.
*
* @since 3.5
*/
class PlgSystemStatsFormFieldUniqueid extends PlgSystemStatsFormFieldBase
{
/**
* The form field type.
*
* @var string
* @since 3.5
*/
protected $type = 'Uniqueid';
/**
* Name of the layout being used to render the field
*
* @var string
* @since 3.5
*/
protected $layout = 'field.uniqueid';
}
PK��[�e����stats/layouts/field/data.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.stats
*
* @copyright (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
extract($displayData);
/**
* Layout variables
* -----------------
* @var string $autocomplete Autocomplete attribute for the field.
* @var boolean $autofocus Is autofocus enabled?
* @var string $class Classes for the input.
* @var string $description Description of the field.
* @var boolean $disabled Is this field disabled?
* @var string $group Group the field belongs to.
<fields> section in form XML.
* @var boolean $hidden Is this field hidden in the form?
* @var string $hint Placeholder for the field.
* @var string $id DOM id of the field.
* @var string $label Label of the field.
* @var string $labelclass Classes to apply to the label.
* @var boolean $multiple Does this field support multiple
values?
* @var string $name Name of the input field.
* @var string $onchange Onchange attribute for the field.
* @var string $onclick Onclick attribute for the field.
* @var string $pattern Pattern (Reg Ex) of value of the form
field.
* @var boolean $readonly Is this field read only?
* @var boolean $repeat Allows extensions to duplicate
elements.
* @var boolean $required Is this field required?
* @var integer $size Size attribute of the input.
* @var boolean $spellcheck Spellcheck state for the form field.
* @var string $validate Validation rules to apply.
* @var string $value Value attribute of the field.
* @var array $options Options available for this field.
* @var array $statsData Statistics that will be sent to the
stats server
*/
JHtml::_('jquery.framework');
?>
<a href="#" onclick="jQuery(this).next().toggle(200);
return false;"><?php echo
JText::_('PLG_SYSTEM_STATS_MSG_WHAT_DATA_WILL_BE_SENT');
?></a>
<?php
echo $field->render('stats', compact('statsData'));
PK��[oT=
stats/layouts/field/uniqueid.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.stats
*
* @copyright (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
extract($displayData);
/**
* Layout variables
* -----------------
* @var string $autocomplete Autocomplete attribute for the field.
* @var boolean $autofocus Is autofocus enabled?
* @var string $class Classes for the input.
* @var string $description Description of the field.
* @var boolean $disabled Is this field disabled?
* @var string $group Group the field belongs to.
<fields> section in form XML.
* @var boolean $hidden Is this field hidden in the form?
* @var string $hint Placeholder for the field.
* @var string $id DOM id of the field.
* @var string $label Label of the field.
* @var string $labelclass Classes to apply to the label.
* @var boolean $multiple Does this field support multiple
values?
* @var string $name Name of the input field.
* @var string $onchange Onchange attribute for the field.
* @var string $onclick Onclick attribute for the field.
* @var string $pattern Pattern (Reg Ex) of value of the form
field.
* @var boolean $readonly Is this field read only?
* @var boolean $repeat Allows extensions to duplicate
elements.
* @var boolean $required Is this field required?
* @var integer $size Size attribute of the input.
* @var boolean $spellcheck Spellcheck state for the form field.
* @var string $validate Validation rules to apply.
* @var string $value Value attribute of the field.
* @var array $options Options available for this field.
*/
?>
<input type="hidden" name="<?php echo $name;
?>" id="<?php echo $id; ?>" value="<?php
echo htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); ?>"
/>
<a class="btn"
onclick="document.getElementById('<?php echo $id;
?>').value='';Joomla.submitbutton('plugin.apply');">
<span class="icon-refresh"></span> <?php echo
JText::_('PLG_SYSTEM_STATS_RESET_UNIQUE_ID'); ?>
</a>PK��[֙Qstats/layouts/message.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.stats
*
* @copyright (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
extract($displayData);
/**
* Layout variables
* -----------------
* @var PlgSystemStats $plugin Plugin rendering this
layout
* @var \Joomla\Registry\Registry $pluginParams Plugin parameters
* @var array $statsData Array containing the
data that will be sent to the stats server
*/
?>
<div class="alert alert-info js-pstats-alert"
style="display:none;">
<button data-dismiss="alert" class="close"
type="button">×</button>
<h2><?php echo
JText::_('PLG_SYSTEM_STATS_LABEL_MESSAGE_TITLE');
?></h2>
<p>
<?php echo
JText::_('PLG_SYSTEM_STATS_MSG_JOOMLA_WANTS_TO_SEND_DATA'); ?>
<a href="#" class="js-pstats-btn-details
alert-link"><?php echo
JText::_('PLG_SYSTEM_STATS_MSG_WHAT_DATA_WILL_BE_SENT');
?></a>
</p>
<?php
echo $plugin->render('stats',
compact('statsData'));
?>
<p><?php echo
JText::_('PLG_SYSTEM_STATS_MSG_ALLOW_SENDING_DATA');
?></p>
<p class="actions">
<a href="#" class="btn
js-pstats-btn-allow-always"><?php echo
JText::_('PLG_SYSTEM_STATS_BTN_SEND_ALWAYS'); ?></a>
<a href="#" class="btn
js-pstats-btn-allow-once"><?php echo
JText::_('PLG_SYSTEM_STATS_BTN_SEND_NOW'); ?></a>
<a href="#" class="btn
js-pstats-btn-allow-never"><?php echo
JText::_('PLG_SYSTEM_STATS_BTN_NEVER_SEND'); ?></a>
</p>
</div>
PK��[_�mlffstats/layouts/stats.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.stats
*
* @copyright (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
extract($displayData);
/**
* Layout variables
* -----------------
* @var array $statsData Array containing the data that will be sent to
the stats server
*/
$versionFields = array('php_version', 'db_version',
'cms_version');
?>
<dl class="dl-horizontal js-pstats-data-details"
style="display:none;">
<?php foreach ($statsData as $key => $value) : ?>
<dt><?php echo JText::_('PLG_SYSTEM_STATS_LABEL_' .
strtoupper($key)); ?></dt>
<dd><?php echo in_array($key, $versionFields) ?
(preg_match('/\d+(?:\.\d+)+/', $value, $matches) ? $matches[0] :
$value) : $value; ?></dd>
<?php endforeach; ?>
</dl>
PK��[vc1��1�1stats/stats.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.stats
*
* @copyright (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
// Uncomment the following line to enable debug mode for testing purposes.
Note: statistics will be sent on every page load
// define('PLG_SYSTEM_STATS_DEBUG', 1);
/**
* Statistics system plugin. This sends anonymous data back to the Joomla!
Project about the
* PHP, SQL, Joomla and OS versions
*
* @since 3.5
*/
class PlgSystemStats extends JPlugin
{
/**
* Indicates sending statistics is always allowed.
*
* @var integer
* @since 3.5
*/
const MODE_ALLOW_ALWAYS = 1;
/**
* Indicates sending statistics is only allowed one time.
*
* @var integer
* @since 3.5
*/
const MODE_ALLOW_ONCE = 2;
/**
* Indicates sending statistics is never allowed.
*
* @var integer
* @since 3.5
*/
const MODE_ALLOW_NEVER = 3;
/**
* Application object
*
* @var JApplicationCms
* @since 3.5
*/
protected $app;
/**
* Database object
*
* @var JDatabaseDriver
* @since 3.5
*/
protected $db;
/**
* URL to send the statistics.
*
* @var string
* @since 3.5
*/
protected $serverUrl =
'https://developer.joomla.org/stats/submit';
/**
* Unique identifier for this site
*
* @var string
* @since 3.5
*/
protected $uniqueId;
/**
* Listener for the `onAfterInitialise` event
*
* @return void
*
* @since 3.5
*/
public function onAfterInitialise()
{
if (!$this->app->isClient('administrator') ||
!$this->isAllowedUser())
{
return;
}
if (!$this->isDebugEnabled() && !$this->isUpdateRequired())
{
return;
}
if (JUri::getInstance()->getVar('tmpl') ===
'component')
{
return;
}
// Load plugin language files only when needed (ex: they are not needed
in site client).
$this->loadLanguage();
JHtml::_('jquery.framework');
JHtml::_('script', 'plg_system_stats/stats.js',
array('version' => 'auto', 'relative'
=> true));
}
/**
* User selected to always send data
*
* @return void
*
* @since 3.5
*
* @throws Exception If user is not allowed.
* @throws RuntimeException If there is an error saving the params or
sending the data.
*/
public function onAjaxSendAlways()
{
if (!$this->isAllowedUser() || !$this->isAjaxRequest())
{
throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
}
$this->params->set('mode', static::MODE_ALLOW_ALWAYS);
if (!$this->saveParams())
{
throw new RuntimeException('Unable to save plugin settings',
500);
}
$this->sendStats();
echo json_encode(array('sent' => 1));
}
/**
* User selected to never send data.
*
* @return void
*
* @since 3.5
*
* @throws Exception If user is not allowed.
* @throws RuntimeException If there is an error saving the params.
*/
public function onAjaxSendNever()
{
if (!$this->isAllowedUser() || !$this->isAjaxRequest())
{
throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
}
$this->params->set('mode', static::MODE_ALLOW_NEVER);
if (!$this->saveParams())
{
throw new RuntimeException('Unable to save plugin settings',
500);
}
echo json_encode(array('sent' => 0));
}
/**
* User selected to send data once.
*
* @return void
*
* @since 3.5
*
* @throws Exception If user is not allowed.
* @throws RuntimeException If there is an error saving the params or
sending the data.
*/
public function onAjaxSendOnce()
{
if (!$this->isAllowedUser() || !$this->isAjaxRequest())
{
throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
}
$this->params->set('mode', static::MODE_ALLOW_ONCE);
if (!$this->saveParams())
{
throw new RuntimeException('Unable to save plugin settings',
500);
}
$this->sendStats();
echo json_encode(array('sent' => 1));
}
/**
* Send the stats to the server.
* On first load | on demand mode it will show a message asking users to
select mode.
*
* @return void
*
* @since 3.5
*
* @throws Exception If user is not allowed.
* @throws RuntimeException If there is an error saving the params or
sending the data.
*/
public function onAjaxSendStats()
{
if (!$this->isAllowedUser() || !$this->isAjaxRequest())
{
throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
}
// User has not selected the mode. Show message.
if ((int) $this->params->get('mode') !==
static::MODE_ALLOW_ALWAYS)
{
$data = array(
'sent' => 0,
'html' =>
$this->getRenderer('message')->render($this->getLayoutData())
);
echo json_encode($data);
return;
}
if (!$this->saveParams())
{
throw new RuntimeException('Unable to save plugin settings',
500);
}
$this->sendStats();
echo json_encode(array('sent' => 1));
}
/**
* Get the data through events
*
* @param string $context Context where this will be called from
*
* @return array
*
* @since 3.5
*/
public function onGetStatsData($context)
{
return $this->getStatsData();
}
/**
* Debug a layout of this plugin
*
* @param string $layoutId Layout identifier
* @param array $data Optional data for the layout
*
* @return string
*
* @since 3.5
*/
public function debug($layoutId, $data = array())
{
$data = array_merge($this->getLayoutData(), $data);
return $this->getRenderer($layoutId)->debug($data);
}
/**
* Get the data for the layout
*
* @return array
*
* @since 3.5
*/
protected function getLayoutData()
{
return array(
'plugin' => $this,
'pluginParams' => $this->params,
'statsData' => $this->getStatsData()
);
}
/**
* Get the layout paths
*
* @return array
*
* @since 3.5
*/
protected function getLayoutPaths()
{
$template = JFactory::getApplication()->getTemplate();
return array(
JPATH_ADMINISTRATOR . '/templates/' . $template .
'/html/layouts/plugins/' . $this->_type . '/' .
$this->_name,
__DIR__ . '/layouts',
);
}
/**
* Get the plugin renderer
*
* @param string $layoutId Layout identifier
*
* @return JLayout
*
* @since 3.5
*/
protected function getRenderer($layoutId = 'default')
{
$renderer = new JLayoutFile($layoutId);
$renderer->setIncludePaths($this->getLayoutPaths());
return $renderer;
}
/**
* Get the data that will be sent to the stats server.
*
* @return array
*
* @since 3.5
*/
private function getStatsData()
{
$data = array(
'unique_id' => $this->getUniqueId(),
'php_version' => PHP_VERSION,
'db_type' => $this->db->name,
'db_version' => $this->db->getVersion(),
'cms_version' => JVERSION,
'server_os' => php_uname('s') . ' ' .
php_uname('r')
);
// Check if we have a MariaDB version string and extract the proper
version from it
if
(preg_match('/^(?:5\.5\.5-)?(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/i',
$data['db_version'], $versionParts))
{
$data['db_version'] = $versionParts['major'] .
'.' . $versionParts['minor'] . '.' .
$versionParts['patch'];
}
return $data;
}
/**
* Get the unique id. Generates one if none is set.
*
* @return integer
*
* @since 3.5
*/
private function getUniqueId()
{
if (null === $this->uniqueId)
{
$this->uniqueId = $this->params->get('unique_id',
hash('sha1', JUserHelper::genRandomPassword(28) . time()));
}
return $this->uniqueId;
}
/**
* Check if current user is allowed to send the data
*
* @return boolean
*
* @since 3.5
*/
private function isAllowedUser()
{
return JFactory::getUser()->authorise('core.admin');
}
/**
* Check if the debug is enabled
*
* @return boolean
*
* @since 3.5
*/
private function isDebugEnabled()
{
return defined('PLG_SYSTEM_STATS_DEBUG');
}
/**
* Check if last_run + interval > now
*
* @return boolean
*
* @since 3.5
*/
private function isUpdateRequired()
{
$last = (int) $this->params->get('lastrun', 0);
$interval = (int) $this->params->get('interval', 12);
$mode = (int) $this->params->get('mode', 0);
if ($mode === static::MODE_ALLOW_NEVER)
{
return false;
}
// Never updated or debug enabled
if (!$last || $this->isDebugEnabled())
{
return true;
}
return (abs(time() - $last) > $interval * 3600);
}
/**
* Check valid AJAX request
*
* @return boolean
*
* @since 3.5
*/
private function isAjaxRequest()
{
return
strtolower($this->app->input->server->get('HTTP_X_REQUESTED_WITH',
'')) === 'xmlhttprequest';
}
/**
* Render a layout of this plugin
*
* @param string $layoutId Layout identifier
* @param array $data Optional data for the layout
*
* @return string
*
* @since 3.5
*/
public function render($layoutId, $data = array())
{
$data = array_merge($this->getLayoutData(), $data);
return $this->getRenderer($layoutId)->render($data);
}
/**
* Save the plugin parameters
*
* @return boolean
*
* @since 3.5
*/
private function saveParams()
{
// Update params
$this->params->set('lastrun', time());
$this->params->set('unique_id', $this->getUniqueId());
$interval = (int) $this->params->get('interval', 12);
$this->params->set('interval', $interval ?: 12);
$query = $this->db->getQuery(true)
->update($this->db->quoteName('#__extensions'))
->set($this->db->quoteName('params') . ' =
' .
$this->db->quote($this->params->toString('JSON')))
->where($this->db->quoteName('type') . ' =
' . $this->db->quote('plugin'))
->where($this->db->quoteName('folder') . ' =
' . $this->db->quote('system'))
->where($this->db->quoteName('element') . ' =
' . $this->db->quote('stats'));
try
{
// Lock the tables to prevent multiple plugin executions causing a race
condition
$this->db->lockTable('#__extensions');
}
catch (Exception $e)
{
// If we can't lock the tables it's too risky to continue
execution
return false;
}
try
{
// Update the plugin parameters
$result = $this->db->setQuery($query)->execute();
$this->clearCacheGroups(array('com_plugins'), array(0, 1));
}
catch (Exception $exc)
{
// If we failed to execute
$this->db->unlockTables();
$result = false;
}
try
{
// Unlock the tables after writing
$this->db->unlockTables();
}
catch (Exception $e)
{
// If we can't lock the tables assume we have somehow failed
$result = false;
}
return $result;
}
/**
* Send the stats to the stats server
*
* @return boolean
*
* @since 3.5
*
* @throws RuntimeException If there is an error sending the data.
*/
private function sendStats()
{
try
{
// Don't let the request take longer than 2 seconds to avoid page
timeout issues
$response = JHttpFactory::getHttp()->post($this->serverUrl,
$this->getStatsData(), null, 2);
}
catch (UnexpectedValueException $e)
{
// There was an error sending stats. Should we do anything?
throw new RuntimeException('Could not send site statistics to
remote server: ' . $e->getMessage(), 500);
}
catch (RuntimeException $e)
{
// There was an error connecting to the server or in the post request
throw new RuntimeException('Could not connect to statistics server:
' . $e->getMessage(), 500);
}
catch (Exception $e)
{
// An unexpected error in processing; don't let this failure kill
the site
throw new RuntimeException('Unexpected error connecting to
statistics server: ' . $e->getMessage(), 500);
}
if ($response->code !== 200)
{
$data = json_decode($response->body);
throw new RuntimeException('Could not send site statistics to
remote server: ' . $data->message, $response->code);
}
return true;
}
/**
* Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
*
* @param array $clearGroups The cache groups to clean
* @param array $cacheClients The cache clients (site, admin) to clean
*
* @return void
*
* @since 3.5
*/
private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
{
foreach ($clearGroups as $group)
{
foreach ($cacheClients as $client_id)
{
try
{
$options = array(
'defaultgroup' => $group,
'cachebase' => $client_id ? JPATH_ADMINISTRATOR .
'/cache' : $this->app->get('cache_path',
JPATH_SITE . '/cache')
);
$cache = JCache::getInstance('callback', $options);
$cache->clean();
}
catch (Exception $e)
{
// Ignore it
}
}
}
}
}
PK��[�+Nbbstats/stats.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin"
group="system" method="upgrade">
<name>plg_system_stats</name>
<author>Joomla! Project</author>
<creationDate>November 2013</creationDate>
<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.5.0</version>
<description>PLG_SYSTEM_STATS_XML_DESCRIPTION</description>
<files>
<folder>field</folder>
<folder>layouts</folder>
<filename plugin="stats">stats.php</filename>
</files>
<languages folder="language">
<language
tag="en-GB">en-GB/en-GB.plg_system_stats.ini</language>
<language
tag="en-GB">en-GB/en-GB.plg_system_stats.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="data"
type="plgsystemstats.data"
label=""
/>
<field
name="unique_id"
type="plgsystemstats.uniqueid"
label="PLG_SYSTEM_STATS_UNIQUE_ID_LABEL"
description="PLG_SYSTEM_STATS_UNIQUE_ID_DESC"
size="10"
/>
<field
name="interval"
type="number"
label="PLG_SYSTEM_STATS_INTERVAL_LABEL"
description="PLG_SYSTEM_STATS_INTERVAL_DESC"
filter="integer"
default="12"
/>
<field
name="mode"
type="list"
label="PLG_SYSTEM_STATS_MODE_LABEL"
description="PLG_SYSTEM_STATS_MODE_DESC"
default="1"
>
<option
value="1">PLG_SYSTEM_STATS_MODE_OPTION_ALWAYS_SEND</option>
<option
value="2">PLG_SYSTEM_STATS_MODE_OPTION_ON_DEMAND</option>
<option
value="3">PLG_SYSTEM_STATS_MODE_OPTION_NEVER_SEND</option>
</field>
<field
name="lastrun"
type="hidden"
default="0"
size="15"
/>
</fieldset>
</fields>
</config>
</extension>
PK��[�����2updatenotification/postinstall/updatecachetime.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.updatenotification
*
* @copyright (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
/**
* Checks if the com_installer config for the cache Hours are eq 0 and the
updatenotification Plugin is enabled
*
* @return boolean
*
* @since 3.6.3
*/
function updatecachetime_postinstall_condition()
{
$cacheTimeout = (int)
JComponentHelper::getComponent('com_installer')->params->get('cachetimeout',
6);
// Check if cachetimeout is eq zero
if ($cacheTimeout === 0 &&
JPluginHelper::isEnabled('system',
'updatenotification'))
{
return true;
}
return false;
}
/**
* Sets the cachetimeout back to the default (6 hours)
*
* @return void
*
* @since 3.6.3
*/
function updatecachetime_postinstall_action()
{
$installer = JComponentHelper::getComponent('com_installer');
// Sets the cachetimeout back to the default (6 hours)
$installer->params->set('cachetimeout', 6);
// Save the new parameters back to com_installer
$table = JTable::getInstance('extension');
$table->load($installer->id);
$table->bind(array('params' =>
$installer->params->toString()));
// Store the changes
if (!$table->store())
{
// If there is an error show it to the admin
JFactory::getApplication()->enqueueMessage($table->getError(),
'error');
}
}
PK��[��&�V-V-)updatenotification/updatenotification.phpnu�[���<?php
/**
* @package Joomla.Plugin
* @subpackage System.updatenotification
*
* @copyright (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
// Uncomment the following line to enable debug mode (update notification
email sent every single time)
// define('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG', 1);
/**
* Joomla! Update Notification plugin
*
* Sends out an email to all Super Users or a predefined email address when
a new Joomla! version is available.
*
* This plugin is a direct adaptation of the corresponding plugin in Akeeba
Ltd's Admin Tools. The author has
* consented to relicensing their plugin's code under GPLv2 or later
(the original version was licensed under
* GPLv3 or later) to allow its inclusion in the Joomla! CMS.
*
* @since 3.5
*/
class PlgSystemUpdatenotification extends JPlugin
{
/**
* Load plugin language files automatically
*
* @var boolean
* @since 3.6.3
*/
protected $autoloadLanguage = true;
/**
* The update check and notification email code is triggered after the
page has fully rendered.
*
* @return void
*
* @since 3.5
*/
public function onAfterRender()
{
// Get the timeout for Joomla! updates, as configured in
com_installer's component parameters
$component = JComponentHelper::getComponent('com_installer');
/** @var \Joomla\Registry\Registry $params */
$params = $component->params;
$cache_timeout = (int) $params->get('cachetimeout', 6);
$cache_timeout = 3600 * $cache_timeout;
// Do we need to run? Compare the last run timestamp stored in the
plugin's options with the current
// timestamp. If the difference is greater than the cache timeout we
shall not execute again.
$now = time();
$last = (int) $this->params->get('lastrun', 0);
if (!defined('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG') &&
(abs($now - $last) < $cache_timeout))
{
return;
}
// Update last run status
// If I have the time of the last run, I can update, otherwise insert
$this->params->set('lastrun', $now);
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->update($db->qn('#__extensions'))
->set($db->qn('params') . ' = ' .
$db->q($this->params->toString('JSON')))
->where($db->qn('type') . ' = ' .
$db->q('plugin'))
->where($db->qn('folder') . ' = ' .
$db->q('system'))
->where($db->qn('element') . ' = ' .
$db->q('updatenotification'));
try
{
// Lock the tables to prevent multiple plugin executions causing a race
condition
$db->lockTable('#__extensions');
}
catch (Exception $e)
{
// If we can't lock the tables it's too risky to continue
execution
return;
}
try
{
// Update the plugin parameters
$result = $db->setQuery($query)->execute();
$this->clearCacheGroups(array('com_plugins'), array(0, 1));
}
catch (Exception $exc)
{
// If we failed to execute
$db->unlockTables();
$result = false;
}
try
{
// Unlock the tables after writing
$db->unlockTables();
}
catch (Exception $e)
{
// If we can't lock the tables assume we have somehow failed
$result = false;
}
// Abort on failure
if (!$result)
{
return;
}
// This is the extension ID for Joomla! itself
$eid = 700;
// Get any available updates
$updater = JUpdater::getInstance();
$results = $updater->findUpdates(array($eid), $cache_timeout);
// If there are no updates our job is done. We need BOTH this check AND
the one below.
if (!$results)
{
return;
}
// Unfortunately Joomla! MVC doesn't allow us to autoload classes
JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_installer/models', 'InstallerModel');
// Get the update model and retrieve the Joomla! core updates
$model = JModelLegacy::getInstance('Update',
'InstallerModel');
$model->setState('filter.extension_id', $eid);
$updates = $model->getItems();
// If there are no updates we don't have to notify anyone about
anything. This is NOT a duplicate check.
if (empty($updates))
{
return;
}
// Get the available update
$update = array_pop($updates);
// Check the available version. If it's the same or less than the
installed version we have no updates to notify about.
if (version_compare($update->version, JVERSION, 'le'))
{
return;
}
// If we're here, we have updates. First, get a link to the Joomla!
Update component.
$baseURL = JUri::base();
$baseURL = rtrim($baseURL, '/');
$baseURL .= (substr($baseURL, -13) !== 'administrator') ?
'/administrator/' : '/';
$baseURL .= 'index.php?option=com_joomlaupdate';
$uri = new JUri($baseURL);
/**
* Some third party security solutions require a secret query parameter
to allow log in to the administrator
* backend of the site. The link generated above will be invalid and
could probably block the user out of their
* site, confusing them (they can't understand the third party
security solution is not part of Joomla! proper).
* So, we're calling the onBuildAdministratorLoginURL system plugin
event to let these third party solutions
* add any necessary secret query parameters to the URL. The plugins are
supposed to have a method with the
* signature:
*
* public function onBuildAdministratorLoginURL(JUri &$uri);
*
* The plugins should modify the $uri object directly and return null.
*/
JEventDispatcher::getInstance()->trigger('onBuildAdministratorLoginURL',
array(&$uri));
// Let's find out the email addresses to notify
$superUsers = array();
$specificEmail = $this->params->get('email',
'');
if (!empty($specificEmail))
{
$superUsers = $this->getSuperUsers($specificEmail);
}
if (empty($superUsers))
{
$superUsers = $this->getSuperUsers();
}
if (empty($superUsers))
{
return;
}
/*
* Load the appropriate language. We try to load English (UK), the
current user's language and the forced
* language preference, in this order. This ensures that we'll never
end up with untranslated strings in the
* update email which would make Joomla! seem bad. So, please, if you
don't fully understand what the
* following code does DO NOT TOUCH IT. It makes the difference between a
hobbyist CMS and a professional
* solution!
*/
$jLanguage = JFactory::getLanguage();
$jLanguage->load('plg_system_updatenotification',
JPATH_ADMINISTRATOR, 'en-GB', true, true);
$jLanguage->load('plg_system_updatenotification',
JPATH_ADMINISTRATOR, null, true, false);
// Then try loading the preferred (forced) language
$forcedLanguage = $this->params->get('language_override',
'');
if (!empty($forcedLanguage))
{
$jLanguage->load('plg_system_updatenotification',
JPATH_ADMINISTRATOR, $forcedLanguage, true, false);
}
// Set up the email subject and body
$email_subject =
JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT');
$email_body =
JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY');
// Replace merge codes with their values
$newVersion = $update->version;
$jVersion = new JVersion;
$currentVersion = $jVersion->getShortVersion();
$jConfig = JFactory::getConfig();
$sitename = $jConfig->get('sitename');
$mailFrom = $jConfig->get('mailfrom');
$fromName = $jConfig->get('fromname');
$substitutions = array(
'[NEWVERSION]' => $newVersion,
'[CURVERSION]' => $currentVersion,
'[SITENAME]' => $sitename,
'[URL]' => JUri::base(),
'[LINK]' => $uri->toString(),
'[RELEASENEWS]' =>
'https://www.joomla.org/announcements/release-news/',
'\\n' => "\n",
);
foreach ($substitutions as $k => $v)
{
$email_subject = str_replace($k, $v, $email_subject);
$email_body = str_replace($k, $v, $email_body);
}
// Send the emails to the Super Users
foreach ($superUsers as $superUser)
{
$mailer = JFactory::getMailer();
$mailer->setSender(array($mailFrom, $fromName));
$mailer->addRecipient($superUser->email);
$mailer->setSubject($email_subject);
$mailer->setBody($email_body);
$mailer->Send();
}
}
/**
* Returns the Super Users email information. If you provide a comma
separated $email list
* we will check that these emails do belong to Super Users and that they
have not blocked
* system emails.
*
* @param null|string $email A list of Super Users to email
*
* @return array The list of Super User emails
*
* @since 3.5
*/
private function getSuperUsers($email = null)
{
// Get a reference to the database object
$db = JFactory::getDbo();
// Convert the email list to an array
if (!empty($email))
{
$temp = explode(',', $email);
$emails = array();
foreach ($temp as $entry)
{
$entry = trim($entry);
$emails[] = $db->q($entry);
}
$emails = array_unique($emails);
}
else
{
$emails = array();
}
// Get a list of groups which have Super User privileges
$ret = array();
try
{
$rootId = JTable::getInstance('Asset',
'JTable')->getRootId();
$rules = JAccess::getAssetRules($rootId)->getData();
$rawGroups = $rules['core.admin']->getData();
$groups = array();
if (empty($rawGroups))
{
return $ret;
}
foreach ($rawGroups as $g => $enabled)
{
if ($enabled)
{
$groups[] = $db->q($g);
}
}
if (empty($groups))
{
return $ret;
}
}
catch (Exception $exc)
{
return $ret;
}
// Get the user IDs of users belonging to the SA groups
try
{
$query = $db->getQuery(true)
->select($db->qn('user_id'))
->from($db->qn('#__user_usergroup_map'))
->where($db->qn('group_id') . ' IN(' .
implode(',', $groups) . ')');
$db->setQuery($query);
$rawUserIDs = $db->loadColumn(0);
if (empty($rawUserIDs))
{
return $ret;
}
$userIDs = array();
foreach ($rawUserIDs as $id)
{
$userIDs[] = $db->q($id);
}
}
catch (Exception $exc)
{
return $ret;
}
// Get the user information for the Super Administrator users
try
{
$query = $db->getQuery(true)
->select(
array(
$db->qn('id'),
$db->qn('username'),
$db->qn('email'),
)
)->from($db->qn('#__users'))
->where($db->qn('id') . ' IN(' .
implode(',', $userIDs) . ')')
->where($db->qn('block') . ' = 0')
->where($db->qn('sendEmail') . ' = ' .
$db->q('1'));
if (!empty($emails))
{
$query->where('LOWER(' . $db->qn('email') .
') IN(' . implode(',',
array_map('strtolower', $emails)) . ')');
}
$db->setQuery($query);
$ret = $db->loadObjectList();
}
catch (Exception $exc)
{
return $ret;
}
return $ret;
}
/**
* Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
*
* @param array $clearGroups The cache groups to clean
* @param array $cacheClients The cache clients (site, admin) to clean
*
* @return void
*
* @since 3.5
*/
private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
{
$conf = JFactory::getConfig();
foreach ($clearGroups as $group)
{
foreach ($cacheClients as $client_id)
{
try
{
$options = array(
'defaultgroup' => $group,
'cachebase' => $client_id ? JPATH_ADMINISTRATOR .
'/cache' :
$conf->get('cache_path', JPATH_SITE .
'/cache')
);
$cache = JCache::getInstance('callback', $options);
$cache->clean();
}
catch (Exception $e)
{
// Ignore it
}
}
}
}
}
PK��[�Z::)updatenotification/updatenotification.xmlnu�[���<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin"
group="system" method="upgrade">
<name>plg_system_updatenotification</name>
<author>Joomla! Project</author>
<creationDate>May 2015</creationDate>
<copyright>(C) 2015 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.5.0</version>
<description>PLG_SYSTEM_UPDATENOTIFICATION_XML_DESCRIPTION</description>
<files>
<filename
plugin="updatenotification">updatenotification.php</filename>
</files>
<languages folder="language">
<language
tag="en-GB">en-GB.plg_system_updatenotification.ini</language>
<language
tag="en-GB">en-GB.plg_system_updatenotification.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="email"
type="text"
label="PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_LBL"
description="PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_DESC"
default=""
size="40"
/>
<field
name="language_override"
type="language"
label="PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_LBL"
description="PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_DESC"
default=""
client="administrator"
>
<option
value="">PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_NONE</option>
</field>
<field
name="lastrun"
type="hidden"
default="0"
size="15"
/>
</fieldset>
</fields>
</config>
</extension>
PKmE�[c
���message.phpnu�[���<?php
/**
* @package Joomla.Site
* @subpackage Layout
*
* @copyright (C) 2014 Open Source Matters, Inc.
<https://www.joomla.org>
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
defined('_JEXEC') or die;
$msgList = $displayData['msgList'];
?>
<div id="system-message-container">
<?php if (is_array($msgList) && !empty($msgList)) : ?>
<div id="system-message">
<?php foreach ($msgList as $type => $msgs) : ?>
<div class="alert alert-<?php echo $type; ?>">
<?php // This requires JS so we should add it through JS.
Progressive enhancement and stuff. ?>
<a class="close"
data-dismiss="alert">×</a>
<?php if (!empty($msgs)) : ?>
<h4 class="alert-heading"><?php echo
JText::_($type); ?></h4>
<div>
<?php foreach ($msgs as $msg) : ?>
<div class="alert-message"><?php echo $msg;
?></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
PKu�[��]��rating_star.pngnu�[���PKu�[W9����rating_star_blank.pngnu�[���PKu�[��V\��sort_asc.pngnu�[���PKu�[J!G`��
�sort_desc.pngnu�[���PK|��[���/�/�actionlogs/actionlogs.phpnu�[���PK|��[؞����3actionlogs/actionlogs.xmlnu�[���PK|��[��<__�8actionlogs/forms/actionlogs.xmlnu�[���PK|��[�����
t<actionlogs/forms/information.xmlnu�[���PK|��[�~�ccS>cache/cache.phpnu�[���PK|��[a6κ���Tcache/cache.xmlnu�[���PK|��[�+Gb�b��[debug/debug.phpnu�[���PK|��[�i�>>bdebug/debug.xmlnu�[���PK|��[��W8�2�2�=fields/fields.phpnu�[���PK|��[W���qfields/fields.xmlnu�[���PK|��[#�K<<dthighlight/highlight.phpnu�[���PK|��[;��f44�|highlight/highlight.xmlnu�[���PK|��[�����=b�languagecode/language/en-GB/en-GB.plg_system_languagecode.ininu�[���PK|��[o���Ap�languagecode/language/en-GB/en-GB.plg_system_languagecode.sys.ininu�[���PK|��[�}`c�languagecode/languagecode.phpnu�[���PK|��[�x�.����languagecode/languagecode.xmlnu�[���PK|��[�ա�b�b!��languagefilter/languagefilter.phpnu�[���PK|��[aVOuss!�languagefilter/languagefilter.xmlnu�[���PK}��[~����
log/log.phpnu�[���PK}��[�$K���log/log.xmlnu�[���PK}��[[�G%�
�
�logout/logout.phpnu�[���PK}��[��C��#logout/logout.xmlnu�[���PK}��[X�/9���&logrotation/logrotation.phpnu�[���PK}��[�g�##�?logrotation/logrotation.xmlnu�[���PK}��[�g��9Fp3p/p3p.phpnu�[���PK}��[�!$$�Ip3p/p3p.xmlnu�[���PK}��[��ɢ�
�
[Nprivacyconsent/field/privacy.phpnu�[���PK}��[�h=::0>Yprivacyconsent/privacyconsent/privacyconsent.xmlnu�[���PK}��[1���MM!�[privacyconsent/privacyconsent.phpnu�[���PK}��[�UqGJ
J
!/�privacyconsent/privacyconsent.xmlnu�[���PK}��[1�r��ʶredirect/form/excludes.xmlnu�[���PK}��[�6j�%&%&�redirect/redirect.phpnu�[���PK}��[-LS�TTT�redirect/redirect.xmlnu�[���PK}��[���
�
��remember/remember.phpnu�[���PK}��[�-����remember/remember.xmlnu�[���PK}��[?>�
���sef/sef.phpnu�[���PK}��[n*mf
�sef/sef.xmlnu�[���PK}��[ҽ�F��$sessiongc/sessiongc.phpnu�[���PK}��[sPw��4
sessiongc/sessiongc.xmlnu�[���PK}��[�V���[)stats/field/base.phpnu�[���PK}��[G!E����,stats/field/data.phpnu�[���PK}��[EN8��h1stats/field/uniqueid.phpnu�[���PK��[�e�����4stats/layouts/field/data.phpnu�[���PK��[oT=
�=stats/layouts/field/uniqueid.phpnu�[���PK��[֙Q Gstats/layouts/message.phpnu�[���PK��[_�mlff^Mstats/layouts/stats.phpnu�[���PK��[vc1��1�1Qstats/stats.phpnu�[���PK��[�+Nbb�stats/stats.xmlnu�[���PK��[�����2��updatenotification/postinstall/updatecachetime.phpnu�[���PK��[��&�V-V-)��updatenotification/updatenotification.phpnu�[���PK��[�Z::)F�updatenotification/updatenotification.xmlnu�[���PKmE�[c
�����message.phpnu�[���PK88U �