| Current Path : /var/www/html/libraries/kunena/src/Config/ |
| Current File : /var/www/html/libraries/kunena/src/Config/KunenaConfig.php |
<?php
/**
* Kunena Component
*
* @package Kunena.Framework
*
* @copyright Copyright (C) 2008 - @currentyear@ Kunena Team. All rights reserved.
* @license https://www.gnu.org/copyleft/gpl.html GNU/GPL
* @link https://www.kunena.org
**/
namespace Kunena\Forum\Libraries\Config;
\defined('_JEXEC') or die();
use Joomla\CMS\Cache\CacheController;
use Joomla\CMS\Cache\Controller\CallbackController;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
/**
* Kunena Config class
*
* Propertylist generated via KunenaConfig::getIdeProperties()
*
* @property string $XConsumerKey The X consumer key
* @property string $XConsumerSecret The X consumer secret
* @property string $accessComponent Direct Component Access
* @property string $activeMenuItem Active menu class name
* @property string $allowAvatarGallery Use Avatars Gallery
* @property string $allowAvatarUpload Allow Avatar Upload
* @property string $allowChangeSubject Let users edit the subject
* @property string $allowFavorites Allow Favorites
* @property string $allowSubscriptions Allow Subscriptions
* @property string $allowUserEditPoll Set if you want allow the user to edit the poll when someone has voted
* @property string $articleDisplay Choose how to display article by default
* @property string $askEmail Require E-mail
* @property string $attachEnd Number of characters from end for shorten filename
* @property string $attachStart Number of characters from start for shorten filename
* @property string $attachmentLimit Limit Attachments
* @property string $attachmentProtection Protect Attachments
* @property string $attachmentUtf8 Enable utf8 characters on attachments
* @property string $autoEmbedEbay Auto Embed eBay Items
* @property string $autoEmbedInstagram Auto Embed Instagram Items
* @property string $autoEmbedSoundcloud Auto Embed Soundcloud items
* @property string $autoEmbedYoutube Auto Embed YouTube Videos
* @property string $autoLink Auto-Link URLs
* @property string $avatarCrop Avatar Cropping
* @property string $avatarEdit Edit avatar by clicking on avatar
* @property string $avatarOnCategory Show Avatar on Category Index and Recent Topics
* @property string $avatarQuality Avatar Quality (%)
* @property string $avatarSize Max. Avatar File Size (KB)
* @property string $avatarType Default avatar type
* @property string $avatarTypes Allowed avatar types
* @property string $bbcodeImgSecure Display Images With Non-standard File Extensions
* @property string $blueskyappHandleOfApp BlueSky App ID
* @property string $blueskyappPasswordOfApp The BlueSky consumer secret
* @property string $boardOffline Forum Offline
* @property string $boardTitle Forum Title
* @property string $boxGhostMessage Check Shadow Topic Box
* @property string $cache Caching
* @property string $cacheTime Cache Time
* @property string $captcha Display Captcha for :
* @property string $captchaPostLimit CAPTCHA Challenge for Users
* @property string $categorySubscriptions Category Subscriptions
* @property string $checkMimeTypes Check MIME Types
* @property string $datePickerFormat Date format for datepicker
* @property string $debug Enable Debug Mode
* @property string $defaultAvatar Default avatar
* @property string $defaultAvatarSmall Default small avatar
* @property string $defaultPage The Default Page
* @property string $defaultSort Message Ordering
* @property string $disableRe Disable Re: on subject
* @property string $displayFilenameAttachment Display attachment filename
* @property string $ebayAffiliateId eBay Affiliate ID
* @property string $ebayApiKey eBay AppID key
* @property string $ebayCertId eBay Cert ID (Client Secret)
* @property string $ebayLanguage eBay Widget Language Code
* @property string $editMarkup Show Edited Mark Up
* @property string $email Forum E-mail Address
* @property string $emailHeader Email Header Image
* @property string $emailHeaderSizeX Header Width
* @property string $emailHeaderSizeY Header Height
* @property string $emailRecipientCount E-mail to Multiple Recipients
* @property string $emailRecipientPrivacy E-mail Recipient Privacy
* @property string $emailSenderName Sender name for mail
* @property string $emailVisibleAddress Visible E-mail Recipient
* @property string $enableForumJump Enable Category Jump
* @property string $enableRss Enable RSS Feeds
* @property string $fallbackEnglish Use English On Missing Strings
* @property string $fileSize Maximum File Size (KB)
* @property string $fileTypes Allowed File Types
* @property string $fileUpload Allow File Uploads
* @property string $floodProtection Flood Protection
* @property string $googleMapApiKey Google maps API key to get better stats usage of google API
* @property string $hideIp Hide IP Addresses From Moderators
* @property string $highlightCode Enable Code Highlighting
* @property string $historyLimit History Limit
* @property string $holdGuestPosts Moderate Guests
* @property string $holdNewUsersPosts Moderate New Users
* @property string $homeId Home ID
* @property string $imageHeight Maximum Image Height (px)
* @property string $imageMimeTypes Legal MIME Types
* @property string $imageQuality Image Quality for JPG Resizing (%)
* @property string $imageSize Maximum Image File Size (KB)
* @property string $imageTypes Allowed Image Types
* @property string $imageUpload Allow Image Uploads
* @property string $imageWidth Maximum Image Width (px)
* @property string $indexId Index ID
* @property string $ipTracking IP Address Tracking
* @property array $latestCategory Category List in Recent Topics
* @property string $latestCategoryIn Category Filter in Recent Topics
* @property string $lightbox Enable Lightbox for Images
* @property string $listCatShowModerators Show Moderators in Category Index
* @property string $logModeration Define if you want to log action or moderation
* @property string $mailAdministrators E-mail Administrators
* @property string $mailBodyUserBanned Set the body of the mail when the user is banned
* @property string $mailBodyUserUnBanned Set the body of the mail when the user is unbanned
* @property string $mailFull Include Post Contents
* @property string $mailModerators E-mail Moderators
* @property string $mainMenuId Mainmenu
* @property string $maxLinks Max Links in message
* @property string $maxSig Max. Signature Length
* @property string $messagesPerPage Messages Per Page
* @property string $messagesPerPageSearch Search Results
* @property string $minimalUserPostsAddUrlImage Set the number minimum of user posts to able to add url and image
* @property string $miscId MISC ID
* @property string $modSeeDeleted Show Deleted Messages
* @property string $moderatorPermDelete Allow moderators to permdelete
* @property string $moderatorsId Moderators ID
* @property string $newUsersPreventPostUrlImages Prevent that new users are able to add url and image in his messages or profile
* @property string $offlineMessage Forum Offline Message
* @property string $orderingSystem Reply Numbering Inside Topic
* @property string $personal Personal
* @property string $pickupCategory Force users to pickup a category
* @property string $plainEmail Plain Text Emails
* @property string $pollAllowVoteOne Single Vote Only
* @property string $pollEnabled Enable Polls
* @property string $pollNbOptions Maximum Number Poll Options
* @property string $pollNbVotesByUser Maximum Number of Votes Per User
* @property string $pollResultsUserslist Show Voters
* @property string $pollTimeBtVotes Time Between Consecutive Votes
* @property string $popPollsCount Number of Popular Polls
* @property string $popSubjectCount Number of Popular Subjects
* @property string $popThanksCount Number of Popular Thank Yous
* @property string $popUserCount Number of Popular Users
* @property string $postDateFormat Message Time Format
* @property string $postDateFormatHover Hover Message Time Format
* @property string $privateMessage Enable private message
* @property string $profileId Profile ID
* @property string $profiler Enable profiler
* @property string $pubProfile Allow Guests to see User Profiles
* @property string $pubWrite Allow Guests to Post/Write
* @property string $quickReply Show Quick Reply
* @property string $rankImages Show Rank
* @property string $ratingEnabled Allow rating
* @property string $readOnly Read Only Mode
* @property string $regOnly Registered Users Only
* @property string $reportMsg Message Reporting
* @property string $rssAllowHtml Render HTML & BBCode in RSS feeds
* @property string $rssAuthorFormat Author Format
* @property string $rssAuthorInTitle Render Author in Title
* @property string $rssCache Caching Interval
* @property array $rssExcludedCategories Exclude Categories
* @property string $rssFeedBurnerUrl The URL of the basic RSS feed into FeedBurner.
* @property array $rssIncludedCategories Include Categories
* @property string $rssLimit RSS Limit
* @property string $rssOldTitles Use Oldstyle Titles
* @property string $rssSpecification RSS Specification
* @property string $rssTimeLimit RSS History (timelimit)
* @property string $rssType RSS Feed type
* @property string $rssWordCount Limit Number of Characters Per Item
* @property string $rules Permissions
* @property string $searchId Search ID
* @property string $searchTime Search Time
* @property string $sef Search Engine Friendly URLs
* @property string $sefRedirect SEF Redirect
* @property string $sendEmails Send E-mails to Users
* @property string $sendMailUserBanned Send a mail to the user when he is banned and unbanned
* @property string $sessionTimeOut Session Lifetime
* @property string $showAnnouncement Show Announcement
* @property string $showBannedReason Show Banned Reason
* @property string $showChildCatIcon Show Sub-Category Image
* @property string $showEmail Show E-mail
* @property string $showFileForGuest Show Attachments for Guests
* @property string $showGenStats Show General Statistics
* @property string $showHistory Show History
* @property string $showImgFilesManageProfile Display profile tab to manage attachments
* @property string $showImgForGuest Show Images for Guests
* @property string $showKarma Show Karma Indicator
* @property string $showListTime Recent Topics Time Period
* @property string $showNew Show New posts
* @property string $showPopPollStats Show Popular Poll Statistics
* @property string $showPopSubjectStats Show Popular Subject Statistics
* @property string $showPopThankYouStats Show Popular Thank You Statistics
* @property string $showPopUserStats Show Popular User Statistics
* @property string $showRanking Ranking
* @property string $showSessionStartTime Online Users Time Limit
* @property string $showSessionType Online Users Contains
* @property string $showStats Show Statistics
* @property string $showThankYou Enable Thank You Feature
* @property string $showUserStats Show User Statistics
* @property string $showWhoIsOnline Show Who is Online
* @property string $signature Signatures
* @property string $smartLinking Smart Auto Linking
* @property string $statsLinkAllowed Allow Guests to see Stats link
* @property string $stopForumSpamKey API key
* @property string $stopForumSpamNewUserCheck Check New User
* @property string $subscriptionsChecked Check Subscription Box
* @property string $superAdminUserlist Hide Super Users in user list
* @property string $teaser Hide Replies For Guests
* @property string $template Template
* @property string $thankYouMax Visible Thank You Limit
* @property string $threadsPerPage Topics Per Page
* @property string $thumbHeight Thumbnail Height (px)
* @property string $thumbWidth Thumbnail Width (px)
* @property string $timeToCreatePage Display Page Creation Time
* @property string $topicIcons Selectable Topic Icons
* @property string $topicLayout Default topic layout
* @property string $topicListId Topiclist ID
* @property string $topicSubscriptions Topic Subscriptions
* @property string $trimLongUrls Trim Long URLs
* @property string $trimLongUrlsBack Back Portion of Trimmed URLs
* @property string $trimLongUrlsFront Front Portion of Trimmed URLs
* @property string $urlSubjectTopic Prevent posting topic or reply with URL in title
* @property string $useSystemEmails Treat as System Email
* @property string $userDeleteMessage User Can Delete Own Post
* @property string $userEdit User Edits
* @property string $userEditTime User Edit Time
* @property string $userEditTimeGrace User Edit Grace Time
* @property string $userListUserType Show User Types
* @property string $userReport User can report himself
* @property string $userStatus Show User Status
* @property string $userlistAllowed Allow Guests to see Userlist
* @property string $userlistAvatar Display Avatar
* @property string $userlistCountUsers User Count Contains
* @property string $userlistEmail Show E-mail
* @property string $userlistJoinDate Show Join Date
* @property string $userlistKarma Show Karma
* @property string $userlistLastVisitDate Show Last Visit Date
* @property string $userlistOnline Online Status
* @property string $userlistPosts Show Number of Posts
* @property string $userlistRows Users Per Page
* @property string $userlistUserHits Show Profile Hits
* @property string $username Display User Name
* @property string $utmSource UTM Source
*
* @since 7.0.0
*/
class KunenaConfig
{
/**
* @var string
*/
private const COMPONENT = 'com_kunena';
/**
* @var KunenaConfig|null
*/
private static ?KunenaConfig $instance = \null;
/**
* @var array
*/
private array $config = [];
/**
* Private constructor to prevent direct instantiation of this utility class.
* This class is intended to be used statically.
*
* @since 7.0.0
*/
private function __construct()
{
// Prevent direct instantiation
}
/**
* Public clone method to prevent cloning of this utility class.
* Throw an exception to make it explicit that cloning is not allowed.
*
* @since 7.0.0
*/
public function __clone()
{
throw new \BadMethodCallException('Cloning of ' . __CLASS__ . ' is not allowed.');
}
/**
* Public wakeup method to prevent unserialization of this utility class.
* Throw an exception to make it explicit that unserialization is not allowed.
*
* @since 7.0.0
*/
public function __wakeup()
{
throw new \BadMethodCallException('Unserialization of ' . __CLASS__ . ' is not allowed.');
}
/**
* Magic method to check if the key exists in the protected array.
* This allows empty() and isset() to work correctly.
*
* @param string $key The key requested (e.g., 'name' for $class->name)
* @return bool true if the key exists
* @since 7.0.2
*/
public function __isset(string $key): bool
{
return isset($this->config[$key]);
}
/**
* Magic method to get protected properties by key.
* This is called when reading data from inaccessible properties.
*
* @param string $key The key requested (e.g., 'name' for $class->name)
* @return mixed|null The value from the $param array or null if the key doesn't exist
* @since 7.0.0
*/
public function __get(string $key): mixed
{
// Check if the key exists in the protected array
if (\array_key_exists($key, $this->config)) {
// Ensure array when nothing using default value
if (\in_array($key, ['latestCategory', 'rssExcludedCategories', 'rssIncludedCategories'])) {
if (!\is_array($this->config[$key])) {
$this->config[$key] = [$this->config[$key]];
}
}
// Ensure minimum value
if (\in_array($key, ['messagesPerPage', 'messagesPerPageSearch', 'threadsPerPage'])) {
$this->config[$key] = max($this->config[$key], 1);
}
if ($key === 'email') {
return !empty($this->config[$key]) ? $this->config[$key] : Factory::getApplication()->get('mailfrom', '');
}
// Return the value
return $this->config[$key];
}
throw new \Exception('Trying to get non-existing property: ' . $key, 500);
}
/**
* Magic method to set inaccessible properties.
* This is called when writing data to inaccessible properties.
* It allows setting a configuration value only if the key already exists
* in the loaded configuration array.
*
* @param string $key The key requested (e.g., 'name' for $class->name)
* @param mixed $value The value to set
* @return void
* @since 7.0.0
*/
public function __set(string $key, mixed $value): void
{
// Only set the value if the key is already present in the config array
if (\array_key_exists($key, $this->config)) {
$this->config[$key] = $value;
return;
}
throw new \Exception('Trying to set non-existing property: ' . $key, 500);
}
/**
* Get an instance of KunenaConfig
*
* @return ?KunenaConfig
* @since 7.0.0
*/
public static function getInstance(): ?KunenaConfig
{
if (\null === self::$instance) {
$instance = new KunenaConfig();
$instance->config = self::getCachedConfig();
self::$instance = $instance;
}
return self::$instance;
}
/**
* Function to build the configuration values with default values from config.xml
*
* @return array
* @since 7.0.0
*/
private static function buildConfig(): array
{
$config = [];
$params = ComponentHelper::getParams(self::COMPONENT);
$defaults = self::getXmlDefaults(JPATH_ADMINISTRATOR . '/components/' . self::COMPONENT . '/config.xml');
foreach ($defaults as $name => $default) {
$config[$name] = $params->get($name, $default);
}
return $config;
}
/**
* Function to build the configuration values with default values from config.xml and fill it with values
*
* @return array
* @since 7.0.2
*/
public function getConfigReport(): array
{
return $this->buildConfig();
}
/**
* Function to get the cached (or create when not existing) configuration settings
*
* @return array
* @since 7.0.0
*/
private static function getCachedConfig(): array
{
/** @var CallbackController $cache */
$cache = self::getConfigCacheController();
$config = $cache->get(
fn() => self::buildConfig(),
[],
'config'
);
return $config;
}
/**
* Function to store the configuration settings in to Joomla configured cache
*
* @param array $config The config object to store.
*
* @return void
* @since 7.0.0
*/
private static function storeCachedConfig(array $config): void
{
/** @var CallbackController $cache */
$cache = self::getConfigCacheController();
$cache->store($config, 'config');
}
/**
* Function to get the Configuration cache Controller
*
* @return CacheController
* @since 7.0.0
*/
private static function getConfigCacheController(): CacheController
{
$options = [
'defaultgroup' => self::COMPONENT . '_configuration',
'caching' => \true, // Force caching
'lifetime' => 5259600 // Config cache never expires
];
/** @var CallbackController $cache */
$cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class)->createCacheController('callback', $options);
return $cache;
}
/**
* get the XML file
*
* @param string $path Path to the XML file
*
* @return SimpleXMLElement|false
* @since 7.0.0
*/
private static function getXml(string $path): \SimpleXMLElement|false
{
if (!\is_file($path)) {
return \false;
}
$xml = new \SimpleXMLElement(\file_get_contents($path));
return $xml;
}
/**
* Extract default values from config.xml using Joomla Form API
*
* @param string $path Path to the XML file
*
* @return array<string, mixed>
* @since 7.0.0
*/
private static function getXmlDefaults(string $path): array
{
$xml = self::getXml($path);
if (!$xml) {
return [];
}
$defaults = [];
// Assuming typical Joomla form XML structure: <config><fields name="params"><fieldset><field ...>
// Adjust XPath if your config.xml structure is different.
foreach ($xml->xpath('//field') as $field) {
$attributes = $field->attributes();
$name = (string) ($attributes['name'] ?? '');
$type = (string) ($attributes['type'] ?? '');
$config = (string) ($attributes['config'] ?? '');
if (
!empty($name)
&& !\str_starts_with($name, '@')
&& $type !== 'spacer'
&& $config !== 'false'
) {
$defaults[$name] = (string) ($attributes['default'] ?? '');
}
}
return $defaults;
}
/**
* Print all properties on screen to create a docblock property list we can use in this class
*
* @param string $path Path to the XML file
*
* @return never
* @since 7.0.0
*/
public static function getIdeProperties(): never
{
$xml = self::getXml(JPATH_ADMINISTRATOR . '/components/' . self::COMPONENT . '/config.xml');
if (!$xml) {
die('- nothing to list -');
}
$properties = [];
$params = ComponentHelper::getParams(self::COMPONENT);
// Assuming typical Joomla form XML structure: <config><fields name="params"><fieldset><field ...>
// Adjust XPath if your config.xml structure is different.
foreach ($xml->xpath('//field') as $field) {
$attributes = $field->attributes();
$name = (string) ($attributes['name'] ?? '');
$type = (string) ($attributes['type'] ?? '');
$config = (string) ($attributes['config'] ?? '');
if (
!empty($name)
&& !\str_starts_with($name, '@')
&& $type !== 'spacer'
&& $config !== 'false'
) {
$type = \is_array($params->get($name, '')) ? 'array ' : 'string';
$label = Text::_((string) ($attributes['label'] ?? ''));
$properties[$name] = ['label' => $label, 'type' => $type];
}
}
$maxLength = 0;
foreach ($properties as $property => $value) {
$length = \strlen($property . $value['type']);
if ($length > $maxLength) {
$maxLength = $length;
}
}
// Ensure the array is sorted by key
\ksort($properties);
// Step 2: Iterate and pad the property key to align the label
foreach ($properties as $property => $value) {
// Pad the property key with spaces on the right side
$paddedProperty = \str_pad($property, $maxLength);
$label = $value['label'];
$type = $value['type'];
// Output the string, aligning the label
echo " * @property $type \$$paddedProperty $label\r\n";
}
die;
}
/**
* Function to save a key value in the component configuration
*
* @return boolean
* @since 7.0.0
*/
public function save(): bool
{
$params = ComponentHelper::getParams(self::COMPONENT);
foreach ($params as $key => $value) {
if ($this->config[$key] === $value) {
continue;
}
$params->set($key, $this->config[$key]);
}
/** @var DatabaseDriver $db */
$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->createQuery()
->update($db->quoteName('#__extensions'))
->set($db->quoteName('params') . ' = ' . $db->quote(\json_encode($params)))
->where($db->quoteName('name') . ' = ' . $db->quote(self::COMPONENT));
$db->setQuery($query);
$result = $db->execute();
// Clean out the Cache and start with new value(s)
$this->reset();
return $result;
}
/**
* Function to clear the local cached $config variable
*
* @return void
* @since 7.0.0
*/
public function reset(): void
{
$cache = self::getConfigCacheController();
// Clean the Kunena configuration cache and the _system cache as that is where Joomla itself caches the component cache
$cache->clean(self::COMPONENT . '_configuration');
$cache->clean('_system');
self::$instance = \null;
}
}