diff --git a/Settings.sample.php b/Settings.sample.php
index 3bbb551ef8..3f10e46e93 100644
--- a/Settings.sample.php
+++ b/Settings.sample.php
@@ -5,21 +5,18 @@
* The maintenance "mode"
* Set to 1 to enable Maintenance Mode, 2 to make the forum untouchable. (you'll have to make it 0 again manually!)
* 0 is default and disables maintenance mode.
- * @var int 0, 1, 2
* @global int $maintenance
*/
$maintenance = 0;
/**
* Title for the Maintenance Mode message.
- * @var string
* @global string $mtitle
*/
$mtitle = 'Maintenance Mode';
/**
* Description of why the forum is in maintenance mode.
- * @var string
* @global string $mmessage
*/
$mmessage = 'Okay faithful users...we\'re attempting to restore an older backup of the database...news will be posted once we\'re back!';
@@ -27,31 +24,31 @@
########## Forum Info ##########
/**
* The name of your forum.
- * @var string
+ * @global string $mbname
*/
$mbname = 'My Community';
/**
* The default language file set for the forum.
- * @var string
+ * @global string $language
*/
$language = 'English';
/**
* URL to your forum's folder. (without the trailing /!)
- * @var string
+ * @global string $boardurl
*/
$boardurl = 'http://127.0.0.1/elkarte';
/**
* Email address to send emails from. (like noreply@yourdomain.com.)
- * @var string
+ * @global string $webmaster_email
*/
$webmaster_email = 'noreply@myserver.com';
/**
* Name of the cookie to set for authentication.
- * @var string
+ * @global string $cookiename
*/
$cookiename = 'ElkArteCookie11';
@@ -59,68 +56,68 @@
/**
* The database type
* Default options: mysql, sqlite, postgresql
- * @var string
+ * @global string $db_type
*/
$db_type = 'mysql';
/**
* The server to connect to (or a Unix socket)
- * @var string
+ * @global string $db_server
*/
$db_server = 'localhost';
/**
* The port for the database server
- * @var string
+ * @global string $db_port
*/
$db_port = '';
/**
* The database name
- * @var string
+ * @global string $db_name
*/
$db_name = 'elkarte';
/**
* Database username
- * @var string
+ * @global string $db_user
*/
$db_user = 'root';
/**
* Database password
- * @var string
+ * @global string $db_passwd
*/
$db_passwd = '';
/**
* Database user for when connecting with SSI
- * @var string
+ * @global string $ssi_db_user
*/
$ssi_db_user = '';
/**
* Database password for when connecting with SSI
- * @var string
+ * @global string $ssi_db_passwd
*/
$ssi_db_passwd = '';
/**
* A prefix to put in front of your table names.
* This helps to prevent conflicts
- * @var string
+ * @global string $db_prefix
*/
$db_prefix = 'elkarte_';
/**
* Use a persistent database connection
- * @var int|bool
+ * @global int|bool $db_persist
*/
$db_persist = 0;
/**
*
- * @var int|bool
+ * @global int|bool $db_error_send
*/
$db_error_send = 0;
@@ -129,51 +126,63 @@
* Select a cache system. You want to leave this up to the cache area of the admin panel for
* proper detection of apc, eaccelerator, memcache, mmcache, output_cache or filesystem-based
* (you can add more with a mod).
- * @var string
+ * @global string $cache_accelerator
*/
$cache_accelerator = '';
/**
* The level at which you would like to cache. Between 0 (off) through 3 (cache a lot).
- * @var int
+ * @global int $cache_enable
*/
$cache_enable = 0;
/**
- * This is only used for memcache / memcached. Should be a string of 'server:port,server:port'
- * @var array
+ * This is only used for memcache / memcached / redis. Should be a string of 'server:port,server:port'
+ * @global string $cache_servers
*/
-$cache_memcached = '';
+$cache_servers = '';
/**
* This is only for the 'filebased' cache system. It is the path to the cache directory.
* It is also recommended that you place this in /tmp/ if you are going to use this.
- * @var string
+ * @global string $cachedir
*/
$cachedir = __DIR__ . '/cache';
+/**
+ * Cache accelerator userid / dbname, required by some engines
+ * @global string $cache_uid
+ */
+$cache_uid = '';
+
+/**
+ * Cache accelerator password for connecting, required by somme engines
+ * @global string $cache_password
+ */
+$cache_password = '';
+
########## Directories/Files ##########
# Note: These directories do not have to be changed unless you move things.
/**
* The absolute path to the forum's folder. (not just '.'!)
- * @var string
+ * @global string $boarddir
*/
$boarddir = __DIR__;
/**
* Path to the sources directory.
- * @var string
+ * @global string $sourcedir
*/
$sourcedir = __DIR__ . '/sources';
/**
- * Path to the external resources directory.
- * @var string
+ * Path to the external resources' directory.
+ * @global string $extdir
*/
$extdir = __DIR__ . '/sources/ext';
/**
* Path to the languages directory.
- * @var string
+ * @global string
*/
$languagedir = __DIR__ . '/sources/ElkArte/Languages';
diff --git a/Settings_bak.sample.php b/Settings_bak.sample.php
index e88b9df3f5..b60d0f1e8b 100644
--- a/Settings_bak.sample.php
+++ b/Settings_bak.sample.php
@@ -5,21 +5,18 @@
* The maintenance "mode"
* Set to 1 to enable Maintenance Mode, 2 to make the forum untouchable. (you'll have to make it 0 again manually!)
* 0 is default and disables maintenance mode.
- * @var int 0, 1, 2
* @global int $maintenance
*/
$maintenance = 0;
/**
* Title for the Maintenance Mode message.
- * @var string
- * @global int $mtitle
+ * @global string $mtitle
*/
$mtitle = 'Maintenance Mode';
/**
* Description of why the forum is in maintenance mode.
- * @var string
* @global string $mmessage
*/
$mmessage = 'Okay faithful users...we\'re attempting to restore an older backup of the database...news will be posted once we\'re back!';
@@ -27,31 +24,31 @@
########## Forum Info ##########
/**
* The name of your forum.
- * @var string
+ * @global string $mbname
*/
$mbname = 'My Community';
/**
* The default language file set for the forum.
- * @var string
+ * @global string $language
*/
$language = 'English';
/**
* URL to your forum's folder. (without the trailing /!)
- * @var string
+ * @global string $boardurl
*/
$boardurl = 'http://127.0.0.1/elkarte';
/**
* Email address to send emails from. (like noreply@yourdomain.com.)
- * @var string
+ * @global string $webmaster_email
*/
$webmaster_email = 'noreply@myserver.com';
/**
* Name of the cookie to set for authentication.
- * @var string
+ * @global string $cookiename
*/
$cookiename = 'ElkArteCookie11';
@@ -59,68 +56,68 @@
/**
* The database type
* Default options: mysql, sqlite, postgresql
- * @var string
+ * @global string $db_type
*/
$db_type = 'mysql';
/**
* The server to connect to (or a Unix socket)
- * @var string
+ * @global string $db_server
*/
$db_server = 'localhost';
/**
* The port for the database server
- * @var string
+ * @global string $db_port
*/
$db_port = '';
/**
* The database name
- * @var string
+ * @global string $db_name
*/
$db_name = 'elkarte';
/**
* Database username
- * @var string
+ * @global string $db_user
*/
$db_user = 'root';
/**
* Database password
- * @var string
+ * @global string $db_passwd
*/
$db_passwd = '';
/**
* Database user for when connecting with SSI
- * @var string
+ * @global string $ssi_db_user
*/
$ssi_db_user = '';
/**
* Database password for when connecting with SSI
- * @var string
+ * @global string $ssi_db_passwd
*/
$ssi_db_passwd = '';
/**
* A prefix to put in front of your table names.
* This helps to prevent conflicts
- * @var string
+ * @global string $db_prefix
*/
$db_prefix = 'elkarte_';
/**
* Use a persistent database connection
- * @var int|bool
+ * @global int|bool $db_persist
*/
$db_persist = 0;
/**
*
- * @var int|bool
+ * @global int|bool $db_error_send
*/
$db_error_send = 0;
@@ -129,51 +126,63 @@
* Select a cache system. You want to leave this up to the cache area of the admin panel for
* proper detection of apc, eaccelerator, memcache, mmcache, output_cache or filesystem-based
* (you can add more with a mod).
- * @var string
+ * @global string $cache_accelerator
*/
$cache_accelerator = '';
/**
* The level at which you would like to cache. Between 0 (off) through 3 (cache a lot).
- * @var int
+ * @global int $cache_enable
*/
$cache_enable = 0;
/**
- * This is only used for memcache / memcached. Should be a string of 'server:port,server:port'
- * @var array
+ * This is only used for memcache / memcached / redis. Should be a string of 'server:port,server:port'
+ * @global string $cache_servers
*/
-$cache_memcached = '';
+$cache_servers = '';
/**
* This is only for the 'filebased' cache system. It is the path to the cache directory.
* It is also recommended that you place this in /tmp/ if you are going to use this.
- * @var string
+ * @global string $cachedir
*/
$cachedir = __DIR__ . '/cache';
+/**
+ * Cache accelerator userid / dbname, required by some engines
+ * @global string $cache_uid
+ */
+$cache_uid = '';
+
+/**
+ * Cache accelerator password for connecting, required by somme engines
+ * @global string $cache_password
+ */
+$cache_password = '';
+
########## Directories/Files ##########
# Note: These directories do not have to be changed unless you move things.
/**
* The absolute path to the forum's folder. (not just '.'!)
- * @var string
+ * @global string $boarddir
*/
$boarddir = __DIR__;
/**
* Path to the sources directory.
- * @var string
+ * @global string $sourcedir
*/
$sourcedir = __DIR__ . '/sources';
/**
* Path to the external resources directory.
- * @var string
+ * @global string $extdir
*/
$extdir = __DIR__ . '/sources/ext';
/**
* Path to the languages directory.
- * @var string
+ * @global string $languagedir
*/
$languagedir = __DIR__ . '/sources/ElkArte/Languages';
diff --git a/bootstrap.php b/bootstrap.php
index c035b0d920..1c2f37bde2 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -143,9 +143,9 @@ private function loadSettingsFile()
// All those wonderful things found in settings
global $maintenance, $mtitle, $msubject, $mmessage, $mbname, $language, $boardurl, $webmaster_email;
global $cookiename, $db_type, $db_server, $db_port, $db_name, $db_user, $db_passwd;
- global $ssi_db_user, $ssi_db_passwd, $db_prefix, $db_persist, $db_error_send, $cache_accelerator;
- global $cache_uid, $cache_password, $cache_enable, $cache_memcached, $db_show_debug, $url_format;
- global $cachedir, $boarddir, $sourcedir, $extdir, $languagedir;
+ global $ssi_db_user, $ssi_db_passwd, $db_prefix, $db_persist, $db_error_send;
+ global $cache_uid, $cache_password, $cache_enable, $cache_servers, $cache_accelerator;
+ global $db_show_debug, $url_format, $cachedir, $boarddir, $sourcedir, $extdir, $languagedir;
// Where the Settings.php file is located
$settings_loc = __DIR__ . '/Settings.php';
diff --git a/sources/ElkArte/AdminController/ManageServer.php b/sources/ElkArte/AdminController/ManageServer.php
index d455b32a70..50d5f2b6e9 100644
--- a/sources/ElkArte/AdminController/ManageServer.php
+++ b/sources/ElkArte/AdminController/ManageServer.php
@@ -20,6 +20,7 @@
use ElkArte\AbstractController;
use ElkArte\Action;
+use ElkArte\Cache\CacheMethod\AbstractCacheMethod;
use ElkArte\Exceptions\Exception;
use ElkArte\SettingsForm\SettingsForm;
use ElkArte\Languages\Txt;
@@ -404,11 +405,18 @@ public function action_cacheSettings_display()
{
call_integration_hook('integrate_save_cache_settings');
+ // Move accelerator servers to the cache_servers value
+ $var = 'cache_servers_' . $this->_req->post->cache_accelerator;
+ if (isset($this->_req->post->$var))
+ {
+ $this->_req->post->cache_servers = $this->_req->post->$var;
+ }
+
$settingsForm->setConfigValues((array) $this->_req->post);
$settingsForm->save();
// we need to save the $cache_enable to $modSettings as well
- updateSettings(array('cache_enable' => (int) $this->_req->post->cache_enable));
+ updateSettings(['cache_enable' => (int) $this->_req->post->cache_enable]);
// exit so we reload our new settings on the page
redirectexit('action=admin;area=serversettings;sa=cache;' . $context['session_var'] . '=' . $context['session_id']);
@@ -423,8 +431,6 @@ public function action_cacheSettings_display()
let cache_type = document.getElementById(\'cache_accelerator\');
cache_type.addEventListener("change", showCache);
-
- createEventListener(cache_type);
cache_type.addEventListener("change", toggleCache);
let event = new Event("change");
@@ -451,12 +457,13 @@ private function _cacheSettings()
{
global $txt, $cache_accelerator, $context;
- // Detect all available optimizers
+ // Detect all available cache engines
require_once(SUBSDIR . '/Cache.subs.php');
$detected = loadCacheEngines(false);
$detected_names = [];
$detected_supported = [];
+ /** @var $value AbstractCacheMethod */
foreach ($detected as $key => $value)
{
$detected_names[] = $value->title();
@@ -484,12 +491,13 @@ private function _cacheSettings()
['cache_accelerator', $txt['cache_accelerator'], 'file', 'select', $detected_supported],
];
- // If the cache engine has specific settings, add them in
- foreach ($detected as $value)
+ // If the cache engine has any specific settings, add them in
+ foreach ($detected as $engine)
{
- if ($value->isAvailable())
+ /** @var $engine AbstractCacheMethod */
+ if ($engine->isAvailable())
{
- $value->settings($config_vars);
+ $engine->settings($config_vars);
}
}
diff --git a/sources/ElkArte/Cache/Cache.php b/sources/ElkArte/Cache/Cache.php
index 942198674b..fe2078f48e 100644
--- a/sources/ElkArte/Cache/Cache.php
+++ b/sources/ElkArte/Cache/Cache.php
@@ -16,6 +16,7 @@
namespace ElkArte\Cache;
+use ElkArte\Cache\CacheMethod\AbstractCacheMethod;
use ElkArte\Debug;
use ElkArte\Helper\FileFunctions;
use ElkArte\Helper\Util;
@@ -46,7 +47,7 @@ class Cache
/** @var string[] Cached keys */
protected $_cached_keys = [];
- /** @var object|bool The caching object */
+ /** @var AbstractCacheMethod|null The caching engine object */
protected $_cache_obj;
/**
@@ -65,7 +66,7 @@ public function __construct($level, $accelerator, $options)
{
$accelerator = 'filebased';
}
- $this->_accelerator = $accelerator;
+ $this->_accelerator = ucfirst($accelerator);
$this->setLevel($level);
if ($level > 0)
@@ -100,7 +101,7 @@ public function enable($enable)
*/
protected function _init()
{
- $cache_class = '\\ElkArte\\Cache\\CacheMethod\\' . ucfirst($this->_accelerator);
+ $cache_class = '\\ElkArte\\Cache\\CacheMethod\\' . $this->_accelerator;
if (class_exists($cache_class))
{
@@ -109,8 +110,7 @@ protected function _init()
}
else
{
- $this->_cache_obj = false;
-
+ $this->_cache_obj = null;
$this->enabled = false;
}
@@ -142,23 +142,41 @@ public function isEnabled()
return $this->enabled;
}
+ /**
+ * Return the current cache_obj
+ *
+ * @return AbstractCacheMethod|null
+ */
+ public function getCacheEngine()
+ {
+ return $this->_cache_obj;
+ }
+
+ /**
+ * Return the cache accelerator in use
+ *
+ * @return string
+ */
+ public function getAccelerator()
+ {
+ return $this->_accelerator;
+ }
+
/**
* Find and return the instance of the Cache class if it exists,
- * or create it if it doesn't exist
+ * otherwise start a new instance
*/
public static function instance()
{
if (self::$_instance === null)
{
- global $cache_accelerator, $cache_enable, $cache_memcached;
+ global $cache_accelerator, $cache_enable, $cache_uid, $cache_password, $cache_servers;
- $options = [];
- if (strpos($cache_accelerator ?? '', 'memcache') === 0)
- {
- $options = [
- 'servers' => explode(',', $cache_memcached),
- ];
- }
+ $options = [
+ 'servers' => empty($cache_servers) ? [] : explode(',', $cache_servers),
+ 'cache_uid' => empty($cache_uid) ? '' : $cache_uid,
+ 'cache_password' => empty($cache_password) ? '' : $cache_password,
+ ];
self::$_instance = new Cache($cache_enable, $cache_accelerator, $options);
}
@@ -243,12 +261,11 @@ protected function _key($key)
* - It may "miss" so shouldn't be depended on
* - Uses the cache engine chosen in the ACP and saved in settings.php
* - It supports:
- * - memcache: http://www.php.net/memcache
- * - memcached: http://www.php.net/memcached
- * - APC: http://www.php.net/apc
- * - APCu: http://us3.php.net/manual/en/book.apcu.php
- * - Zend: http://files.zend.com/help/Zend-Platform/output_cache_functions.htm
- * - Zend: http://files.zend.com/help/Zend-Platform/zend_cache_functions.htm
+ * - Memcache: https://www.php.net/memcache
+ * - MemcacheD: https://www.php.net/memcached
+ * - APCu: https://us3.php.net/manual/en/book.apcu.php
+ * - Zend: https://help.zend.com/zend/current/content/data_cache_component.htm
+ * - Redis: https://redis.io/learn/develop/php
*
* @param string $key
* @param string|int|array|null $value
diff --git a/sources/ElkArte/Cache/CacheMethod/AbstractCacheMethod.php b/sources/ElkArte/Cache/CacheMethod/AbstractCacheMethod.php
index 17693c3dd8..ae46a546c5 100644
--- a/sources/ElkArte/Cache/CacheMethod/AbstractCacheMethod.php
+++ b/sources/ElkArte/Cache/CacheMethod/AbstractCacheMethod.php
@@ -33,7 +33,7 @@ abstract class AbstractCacheMethod implements CacheMethodInterface
/** @var string This is prefixed to all cache entries so that different applications won't interfere with each other. */
protected $prefix = 'elkarte';
- /** @var \ElkArte\Helper\FileFunctions instance of file functions for use in cache methods */
+ /** @var FileFunctions instance of file functions for use in cache methods */
protected $fileFunc;
/**
diff --git a/sources/ElkArte/Cache/CacheMethod/Apc.php b/sources/ElkArte/Cache/CacheMethod/Apc.php
index 5a835654c0..2f9f1bfe31 100644
--- a/sources/ElkArte/Cache/CacheMethod/Apc.php
+++ b/sources/ElkArte/Cache/CacheMethod/Apc.php
@@ -59,7 +59,7 @@ public function getStats()
$results['version'] = phpversion('apcu');
// Seems start_time is really up_time, at least going by its value ?
- $elapsed = max($cache['start_time'], 1);
+ $elapsed = max($cache['start_time'], 1)/ 60;
$results['hit_rate'] = sprintf("%.2f", $cache['num_hits'] / $elapsed);
$results['miss_rate'] = sprintf("%.2f", $cache['num_misses'] / $elapsed);
diff --git a/sources/ElkArte/Cache/CacheMethod/Filebased.php b/sources/ElkArte/Cache/CacheMethod/Filebased.php
index bc45a39fe7..e881e4612c 100644
--- a/sources/ElkArte/Cache/CacheMethod/Filebased.php
+++ b/sources/ElkArte/Cache/CacheMethod/Filebased.php
@@ -75,11 +75,13 @@ public function put($key, $value, $ttl = 120)
// Write out the cache file, check that the cache write was successful; all the data must be written
// If it fails due to low diskspace, or other, remove the cache file
- if (@file_put_contents(CACHEDIR . '/' . $fName, $cache_data, LOCK_EX) !== strlen($cache_data))
+ if (file_put_contents(CACHEDIR . '/' . $fName, $cache_data, LOCK_EX) !== strlen($cache_data))
{
$this->fileFunc->delete(CACHEDIR . '/' . $fName);
}
}
+
+ $this->opcacheReset($fName);
}
/**
@@ -115,6 +117,30 @@ public function get($key, $ttl = 120)
return $return;
}
+ /**
+ * Resets the opcache for a specific file.
+ *
+ * If opcache is switched on, and we can use it, immediately invalidates that opcode cache
+ * after a file is written so that future includes are not using a stale opcode cached file.
+ *
+ * @param string $fName The name of the cached file.
+ */
+ private function opcacheReset($fName)
+ {
+ if (extension_loaded('Zend OPcache') && ini_get('opcache.enable'))
+ {
+ $opcache = ini_get('opcache.restrict_api');
+ if ($opcache === false || $opcache === '')
+ {
+ opcache_invalidate(CACHEDIR . '/' . $fName, true);
+ }
+ elseif (stripos(BOARDDIR, $opcache) !== 0)
+ {
+ opcache_invalidate(CACHEDIR . '/' . $fName, true);
+ }
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/sources/ElkArte/Cache/CacheMethod/Memcache.php b/sources/ElkArte/Cache/CacheMethod/Memcache.php
index fa5861f21e..8571f024cd 100644
--- a/sources/ElkArte/Cache/CacheMethod/Memcache.php
+++ b/sources/ElkArte/Cache/CacheMethod/Memcache.php
@@ -24,7 +24,7 @@ class Memcache extends AbstractCacheMethod
/** @var \Memcache Creates a Memcache instance representing the connection to the memcache servers. */
protected $obj;
- /** @var bool If the daemon has valid servers in it pool */
+ /** @var bool If the daemon has valid servers in its pool */
protected $_is_running;
/**
@@ -128,8 +128,8 @@ protected function setOptions($server, $port)
* - 'get_misses': The number of cache lookups that did not find a matching item.
* - 'curr_connections': The number of currently open connections to the cache server.
* - 'version': The version of the cache server.
- * - 'hit_rate': The rate of successful cache lookups per second.
- * - 'miss_rate': The rate of cache lookups that did not find a matching item per second.
+ * - 'hit_rate': The rate of successful cache lookups per minute.
+ * - 'miss_rate': The rate of cache lookups that did not find a matching item per minute.
*
* If the statistics cannot be obtained, an empty array is returned.
*/
@@ -146,7 +146,7 @@ public function getStats()
// Only user the first server
reset($cache);
$server = current($cache);
- $elapsed = max($server['uptime'], 1);
+ $elapsed = max($server['uptime'], 1) / 60;
$results['curr_items'] = comma_format($server['curr_items'] ?? 0, 0);
$results['get_hits'] = comma_format($server['get_hits'] ?? 0, 0);
@@ -242,16 +242,12 @@ public function settings(&$config_vars)
global $txt;
$var = [
- 'cache_memcached', $txt['cache_memcache'], 'file', 'text', 30, 'cache_memcached',
- 'force_div_id' => 'memcache_cache_memcache',
+ 'cache_servers', $txt['cache_memcache'], 'file', 'text', 30, 'cache_memcached', 'force_div_id' => 'memcache_cache_memcache',
];
- $serversmList = $this->getServers();
-
- if (!empty($serversmList))
- {
- $var['postinput'] = $txt['cache_memcached_servers'] . implode('
';
$config_vars[] = $var;
}
diff --git a/sources/ElkArte/Cache/CacheMethod/Memcached.php b/sources/ElkArte/Cache/CacheMethod/Memcached.php
index d373b4413e..b75e6eab2f 100644
--- a/sources/ElkArte/Cache/CacheMethod/Memcached.php
+++ b/sources/ElkArte/Cache/CacheMethod/Memcached.php
@@ -13,6 +13,8 @@
namespace ElkArte\Cache\CacheMethod;
+use ElkArte\Helper\HttpReq;
+
/**
* Memcached
*/
@@ -165,7 +167,7 @@ public function getStats()
// Only user the first server
reset($cache);
$server = current($cache);
- $elapsed = max($server['uptime'], 1);
+ $elapsed = max($server['uptime'], 1) / 60;
$results['curr_items'] = comma_format($server['curr_items'] ?? 0, 0);
$results['get_hits'] = comma_format($server['get_hits'] ?? 0, 0);
@@ -217,7 +219,7 @@ public function put($key, $value, $ttl = 120)
*/
public function clean($type = '')
{
- // Clear it out, really invalidate whats there
+ // Clear it out, really invalidate what is there
$this->obj->flush();
}
@@ -243,13 +245,18 @@ public function details()
*/
public function settings(&$config_vars)
{
- global $txt;
+ global $txt, $cache_servers, $cache_servers_memcached;
$var = [
- 'cache_memcached', $txt['cache_memcached'], 'file', 'text', 30, 'cache_memcached',
- 'force_div_id' => 'memcached_cache_memcached',
+ 'cache_servers_memcached', $txt['cache_memcached'], 'file', 'text', 30, 'cache_memcached', 'force_div_id' => 'memcached_cache_memcached',
];
+ // Use generic global cache_servers value to load the initial form value
+ if (HttpReq::instance()->getQuery('save') === null)
+ {
+ $cache_servers_memcached = $cache_servers;
+ }
+
$serversList = $this->getServers();
$serversList = empty($serversList) ? [$txt['admin_search_results_none']] : $serversList;
$var['postinput'] = $txt['cache_memcached_servers'] . implode('
', $serversList) . '
';
diff --git a/sources/ElkArte/Cache/CacheMethod/Predis.php b/sources/ElkArte/Cache/CacheMethod/Predis.php
new file mode 100644
index 0000000000..ee80b7104a
--- /dev/null
+++ b/sources/ElkArte/Cache/CacheMethod/Predis.php
@@ -0,0 +1,235 @@
+isAvailable())
+ {
+ parent::__construct($options);
+ $this->addServers();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isAvailable()
+ {
+ return class_exists('\Predis\Client');
+ }
+
+ /**
+ * Add Redis servers.
+ *
+ * Don't add servers if they already exist. Ideal for persistent connections.
+ *
+ * @return bool True if there are servers in the daemon, false if not.
+ */
+ protected function addServers()
+ {
+ if (!empty($this->_options['servers']))
+ {
+ $server = reset($this->_options['servers']);
+ $server = explode(':', trim($server));
+ $server[0] = !empty($server[0]) ? $server[0] : 'localhost';
+ $server[1] = !empty($server[1]) ? $server[1] : 6379;
+
+ $params = [
+ 'scheme' => 'tcp',
+ 'host' => $server[0],
+ 'port' => $server[1],
+ ];
+
+ try
+ {
+ $this->obj = new \Predis\Client($params);
+ $this->obj->connect();
+ $this->server[] = "tcp://{$server[0]}:{$server[1]}";
+ }
+ catch (\Predis\Connection\ConnectionException $e)
+ {
+ // Clear the object, should we log an error here?
+ $this->obj = null;
+ }
+ }
+ }
+
+ /**
+ * Get redis servers.
+ *
+ * @return array A list of servers in the daemon.
+ */
+ protected function getServers()
+ {
+ return $this->server;
+ }
+
+ /**
+ * Retrieves statistics about the cache.
+ *
+ * @return array An associative array containing the cache statistics.
+ * The array has the following keys:
+ * - curr_items: The number of items currently stored in the cache.
+ * - get_hits: The number of successful cache hits.
+ * - get_misses: The number of cache misses.
+ * - curr_connections: The number of current open connections to the cache server.
+ * - version: The version of the cache server.
+ * - hit_rate: The cache hit rate as a decimal value with two decimal places.
+ * - miss_rate: The cache miss rate as a decimal value with two decimal places.
+ *
+ * If the statistics cannot be obtained, an empty array is returned.
+ */
+ public function getStats()
+ {
+ $results = [];
+
+ $cache = $this->obj->info();
+
+ if ($cache === false)
+ {
+ return $results;
+ }
+
+ $elapsed = max($cache['Server']['uptime_in_seconds'], 1) / 60;
+ $cache['Stats']['tracking_total_keys'] = count($this->obj->keys('*'));
+
+ $results['curr_items'] = comma_format($cache['Stats']['tracking_total_keys'] ?? 0, 0);
+ $results['get_hits'] = comma_format($cache['Stats']['keyspace_hits'] ?? 0, 0);
+ $results['get_misses'] = comma_format($cache['Stats']['keyspace_misses'] ?? 0, 0);
+ $results['curr_connections'] = $cache['Server']['connected_clients'] ?? 0;
+ $results['version'] = $cache['Server']['redis_version'] ?? '0.0.0';
+ $results['hit_rate'] = sprintf("%.2f", $cache['keyspace_hits'] / $elapsed);
+ $results['miss_rate'] = sprintf("%.2f", $cache['keyspace_misses'] / $elapsed);
+
+ return $results;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function exists($key)
+ {
+ $this->get($key);
+
+ return !$this->is_miss;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($key, $ttl = 120)
+ {
+ if (!is_object($this->obj))
+ {
+ return '';
+ }
+
+ $result = $this->obj->get($key);
+ $this->is_miss = $result == null;
+
+ return $result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function put($key, $value, $ttl = 120)
+ {
+ if (!is_object($this->obj))
+ {
+ return '';
+ }
+
+ if ($value === null)
+ {
+ $this->obj->del($key);
+ }
+
+ $this->obj->set($key, $value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clean($type = '')
+ {
+ if (!is_object($this->obj))
+ {
+ return '';
+ }
+
+ // Clear it out, really invalidate whats there
+ $this->obj->flush();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function details()
+ {
+ if (!is_object($this->obj))
+ {
+ return '';
+ }
+
+ $version = $this->obj->info()['Server'];
+
+ return array(
+ 'title' => $this->title(),
+ 'version' => !empty($version['redis_version']) ? $version['redis_version'] : '0.0.0'
+ );
+ }
+
+ /**
+ * Adds the settings to the settings page.
+ *
+ * Used by integrate_modify_cache_settings added in the title method
+ *
+ * @param array $config_vars
+ */
+ public function settings(&$config_vars)
+ {
+ global $txt;
+
+ $var = [
+ 'cache_servers_redis', $txt['cache_redis'], 'file', 'text', 30, 'cache_redis', 'force_div_id' => 'redis_cache_redis',
+ ];
+
+ $serversmList = $this->getServers();
+ $serversmList = empty($serversmList) ? [$txt['admin_search_results_none']] : $serversmList;
+ $var['postinput'] = $txt['cache_redis_servers'] . implode('
', $serversmList) . '
';
+
+ $config_vars[] = $var;
+ }
+}
diff --git a/sources/ElkArte/Cache/CacheMethod/Redis.php b/sources/ElkArte/Cache/CacheMethod/Redis.php
new file mode 100644
index 0000000000..b3f517390c
--- /dev/null
+++ b/sources/ElkArte/Cache/CacheMethod/Redis.php
@@ -0,0 +1,348 @@
+isAvailable())
+ {
+ $this->obj = new \Redis();
+ $this->addServers();
+ $this->setOptions();
+ $this->setSerializerValue();
+ $this->isConnected();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function isAvailable()
+ {
+ return class_exists(\Redis::class);
+ }
+
+ /**
+ * Check if the connection to Redis server is active.
+ *
+ * @return bool Returns true if the connection is active, false otherwise.
+ */
+ public function isConnected()
+ {
+ try
+ {
+ $this->isConnected = $this->obj->ping();
+ }
+ catch (\RedisException $e)
+ {
+ $this->isConnected = false;
+ }
+
+ return $this->isConnected;
+ }
+
+ /**
+ * If this should be done as a persistent connection
+ *
+ * @return string|null
+ */
+ private function _is_persist()
+ {
+ global $db_persist;
+
+ return empty($db_persist) ? null : $this->prefix . '_redis';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function setOptions()
+ {
+ try
+ {
+ if (!empty($this->_options['cache_password']))
+ {
+ $this->obj->auth($this->_options['cache_password']);
+ }
+
+ if (!empty($this->_options['cache_uid']))
+ {
+ $this->obj->select($this->_options['cache_uid']);
+ }
+ }
+ catch (\RedisException $e)
+ {
+ $this->isConnected = false;
+ }
+ }
+
+ /**
+ * Returns the redis serializer value based on certain conditions.
+ */
+ private function setSerializerValue()
+ {
+ $serializer = $this->obj::SERIALIZER_PHP;
+ if (defined('Redis::SERIALIZER_IGBINARY') && extension_loaded('igbinary'))
+ {
+ $serializer = $this->obj::SERIALIZER_IGBINARY;
+ }
+
+ try
+ {
+ $this->obj->setOption($this->obj::OPT_SERIALIZER, $serializer);
+ }
+ catch (\RedisException $e)
+ {
+ $this->isConnected = false;
+ }
+ }
+
+ /**
+ * Add redis server. Currently, does not support RedisArray / RedisCluster
+ *
+ * @return bool True if there are servers in the daemon, false if not.
+ */
+ protected function addServers()
+ {
+ $retVal = false;
+
+ $server = reset($this->_options['servers']);
+ if ($server !== false)
+ {
+ $server = explode(':', trim($server));
+ $host = empty($server[0]) ? 'localhost' : $server[0];
+ $port = empty($server[1]) ? 6379 : (int) $server[1];
+
+ set_error_handler(static function () { /* ignore php_network_getaddresses errors */ });
+ try
+ {
+ if ($this->_is_persist())
+ {
+ $retVal = $this->obj->pconnect($host, $port, 0.0, $this->_is_persist());
+ }
+ else
+ {
+ $retVal = $this->obj->connect($host, $port, 0.0);
+ }
+ }
+ catch (\RedisException $e)
+ {
+ $retVal = false;
+ }
+ finally
+ {
+ restore_error_handler();
+ }
+ }
+
+ return $retVal;
+ }
+
+ /**
+ * Get redis servers.
+ *
+ * @return string A server name if we are attached.
+ */
+ protected function getServers()
+ {
+ $server = '';
+
+ if ($this->isConnected())
+ {
+ $server = reset($this->_options['servers']);
+ }
+
+ return $server;
+ }
+
+ /**
+ * Retrieves statistics about the cache.
+ *
+ * @return array An associative array containing the cache statistics.
+ * The array has the following keys:
+ * - curr_items: The number of items currently stored in the cache.
+ * - get_hits: The number of successful cache hits.
+ * - get_misses: The number of cache misses.
+ * - curr_connections: The number of current open connections to the cache server.
+ * - version: The version of the cache server.
+ * - hit_rate: The cache hit rate as a decimal value with two decimal places.
+ * - miss_rate: The cache miss rate as a decimal value with two decimal places.
+ *
+ * If the statistics cannot be obtained, an empty array is returned.
+ */
+ public function getStats()
+ {
+ $results = [];
+
+ try
+ {
+ $cache = $this->obj->info();
+ }
+ catch (\RedisException $e)
+ {
+ $cache = false;
+ }
+
+ if ($cache === false)
+ {
+ return $results;
+ }
+
+ $elapsed = max($cache['uptime_in_seconds'], 1) / 60;
+ $cache['tracking_total_keys'] = count($this->obj->keys('*'));
+
+ $results['curr_items'] = comma_format($cache['tracking_total_keys'] ?? 0, 0);
+ $results['get_hits'] = comma_format($cache['keyspace_hits'] ?? 0, 0);
+ $results['get_misses'] = comma_format($cache['keyspace_misses'] ?? 0, 0);
+ $results['curr_connections'] = $cache['connected_clients'] ?? 0;
+ $results['version'] = $cache['redis_version'] ?? '0.0.0';
+ $results['hit_rate'] = sprintf("%.2f", $cache['keyspace_hits'] / $elapsed);
+ $results['miss_rate'] = sprintf("%.2f", $cache['keyspace_misses'] / $elapsed);
+
+ return $results;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function exists($key)
+ {
+ return $this->obj->exists($key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function get($key, $ttl = 120)
+ {
+ if (!$this->isConnected)
+ {
+ return false;
+ }
+
+ try
+ {
+ $result = $this->obj->get($key);
+ }
+ catch (\RedisException $e)
+ {
+ $result = null;
+ }
+
+ $this->is_miss = $result === null || $result === false;
+
+ return $result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function put($key, $value, $ttl = 120)
+ {
+ if (!$this->isConnected)
+ {
+ return false;
+ }
+
+ try
+ {
+ if ($value === null)
+ {
+ $this->obj->del($key);
+ }
+
+ if ($ttl > 0)
+ {
+ return $this->obj->setex($key, $ttl, $value);
+ }
+
+ return $this->obj->set($key, $value);
+ }
+ catch (\RedisException $e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clean($type = '')
+ {
+ // Clear it out
+ $this->obj->flushDB();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function details()
+ {
+ return [
+ 'title' => $this->title(),
+ 'version' => phpversion('redis')
+ ];
+ }
+
+ /**
+ * Adds the settings to the settings page.
+ *
+ * Used by integrate_modify_cache_settings added in the title method
+ *
+ * @param array $config_vars
+ */
+ public function settings(&$config_vars)
+ {
+ global $txt, $cache_servers, $cache_servers_redis;
+
+ $var = [
+ 'cache_servers_redis', $txt['cache_redis'], 'file', 'text', 30, 'cache_redis', 'force_div_id' => 'redis_cache_redis',
+ ];
+
+ // Use generic global cache_servers value to load the initial form value
+ if (HttpReq::instance()->getQuery('save') === null)
+ {
+ $cache_servers_redis = $cache_servers;
+ }
+
+ $serversList = $this->getServers();
+ $serversList = empty($serversList) ? $txt['admin_search_results_none'] : $serversList;
+ $var['postinput'] = $txt['cache_redis_servers'] . $serversList . '';
+
+ $config_vars[] = $var;
+ $config_vars[] = ['cache_uid', $txt['cache_uid'], 'file', 'text', $txt['cache_uid'], 'cache_uid', 'force_div_id' => 'redis_cache_uid'];
+ $config_vars[] = ['cache_password', $txt['cache_password'], 'file', 'password', $txt['cache_password'], 'cache_password', 'force_div_id' => 'redis_cache_password', 'skip_verify_pass' => true];
+ }
+}
diff --git a/sources/ElkArte/Languages/Help/English.php b/sources/ElkArte/Languages/Help/English.php
index 0714ec1e7e..7b95f94636 100644
--- a/sources/ElkArte/Languages/Help/English.php
+++ b/sources/ElkArte/Languages/Help/English.php
@@ -268,8 +268,12 @@
$helptxt['databaseSession_loose'] = 'Turning this on will decrease the bandwidth your forum uses, and make it so clicking back will not reload the page - the downside is that the (new) icons won\'t update, among other things. (unless you click to that page instead of going back to it.)';
$helptxt['databaseSession_lifetime'] = 'This is the number of seconds for sessions to last after they haven\'t been accessed. If a session is not accessed for too long, it is said to have "timed out". Anything higher than 2400 is recommended.';
$helptxt['cache_enable'] = 'ElkArte performs caching at a variety of levels. The higher the level of caching enabled the more CPU time will be spent retrieving cached information. If caching is available on your machine it is recommended that you try caching at level 1 first.';
-$helptxt['cache_memcached'] = 'If you are using memcached you need to provide the server details. This should be entered as a comma separated list as shown in the example below:
"server1,server2,server3:port,server4"
Note that if no port is specified the software will use port 11211, set this to 0 when using UNIX domain sockets.';
+$helptxt['cache_memcached'] = 'If you are using memcached you need to provide the server details. This should be entered as a comma separated list as shown in this example:
"server1,server2,server3:port,server4"
Note that if no port is specified the software will use port 11211, set this to 0 when using UNIX domain sockets.';
+$helptxt['cache_redis'] = 'If you are using redis you need to provide the server details. This should be entered as a comma separated list as shown in this example:
"server1,server2,server3:port,server4"
Note that if no port is specified the software will use port 6379, set this to 0 when using UNIX domain sockets.';
$helptxt['cache_cachedir'] = 'This setting is only for the filesystem based cache system. It specifies the path to the cache directory. It is recommended that you place this in /tmp/ if you are going to use this, although it will work in any directory';
+$helptxt['cache_uid'] = 'Some cache systems, for example Redis, may require a user ID to allow ElkArte access the cache.';
+$helptxt['cache_password'] = 'Some cache systems, for example Redis, may require a password to allow ElkArte access the cache.';
+
$helptxt['enableErrorLogging'] = 'This will log any errors, like a failed login, so you can see what went wrong.';
$helptxt['enableErrorQueryLogging'] = 'This will include the full query sent to the database in the error log. Requires error logging to be turned on.
Note: This will affect the ability to filter the error log by the error message.';
$helptxt['allow_disableAnnounce'] = 'This will allow users to opt out of notification of topics you announce by checking the "announce topic" checkbox when posting.';
diff --git a/sources/ElkArte/Languages/Maintenance/English.php b/sources/ElkArte/Languages/Maintenance/English.php
index 636d9de4a5..d90309eb62 100644
--- a/sources/ElkArte/Languages/Maintenance/English.php
+++ b/sources/ElkArte/Languages/Maintenance/English.php
@@ -145,8 +145,8 @@
$txt['maintain_cache_get_misses'] = 'The number of cache item retrievals that did not find a matching item.';
$txt['maintain_cache_curr_connections'] = 'The number of currently open connections to the caching daemon.';
$txt['maintain_cache_version'] = 'The version number of the caching server.';
-$txt['maintain_cache_hit_rate'] = 'Hit Rate in requests/second';
-$txt['maintain_cache_miss_rate'] = 'Miss Rate in requests/second';
+$txt['maintain_cache_hit_rate'] = 'Hit Rate in requests/minute';
+$txt['maintain_cache_miss_rate'] = 'Miss Rate in requests/minute';
$txt['maintain_backup'] = 'Backup Database';
$txt['maintain_backup_info'] = 'Download a backup copy of your forums database in case of emergency.';
diff --git a/sources/ElkArte/Languages/ManageSettings/English.php b/sources/ElkArte/Languages/ManageSettings/English.php
index 3b4ae8ef4f..23686c200a 100644
--- a/sources/ElkArte/Languages/ManageSettings/English.php
+++ b/sources/ElkArte/Languages/ManageSettings/English.php
@@ -123,10 +123,14 @@
$txt['cache_level1'] = 'Level 1 Caching (Recommended)';
$txt['cache_level2'] = 'Level 2 Caching';
$txt['cache_level3'] = 'Level 3 Caching (Not Recommended)';
-$txt['cache_memcached'] = 'Memcached settings';
-$txt['cache_memcache'] = 'Memcache settings';
+$txt['cache_memcached'] = 'Memcached Server(s)';
+$txt['cache_memcache'] = 'Memcache Server(s)';
$txt['cache_memcached_servers'] = ' Added servers:
';
$txt['cache_accelerator'] = 'Caching Accelerator';
+$txt['cache_uid'] = 'Cache Accelerator ID';
+$txt['cache_password'] = 'Cache Accelerator Password';
$txt['loadavg_warning'] = 'Please note: the settings below are to be edited with care. Setting any of them too low may render your forum unusable! The current load average is %01.2f';
$txt['loadavg_enable'] = 'Enable load management by load averages';
diff --git a/sources/ElkArte/SettingsForm/SettingsFormAdapter/File.php b/sources/ElkArte/SettingsForm/SettingsFormAdapter/File.php
index 353d851901..07ef2541ab 100644
--- a/sources/ElkArte/SettingsForm/SettingsFormAdapter/File.php
+++ b/sources/ElkArte/SettingsForm/SettingsFormAdapter/File.php
@@ -50,8 +50,7 @@ class File extends Db
* 1 label - the text to show on the settings page
* 2 saveto - file or db, where to save the variable name - value pair
* 3 type - type of data to display int, float, text, check, select, password
- * 4 size - false or field size, if type is select, this needs to be an array of
- * select options
+ * 4 size - false or field size, if type is select, this needs to be an array of select options
* 5 help - '' or helptxt variable name
* )
* - The following named keys are also permitted
@@ -59,6 +58,8 @@ class File extends Db
* 'postinput' =>
* 'preinput' =>
* 'subtext' =>
+ * 'force_div_id' =>
+ * 'skip_verify_pass' =>
*/
public function prepare()
{
@@ -184,6 +185,7 @@ private function _cleanSettings()
$config_passwords = [
'db_passwd',
'ssi_db_passwd',
+ 'cache_password',
];
// All the strings to write.
@@ -201,8 +203,9 @@ private function _cleanSettings()
'db_prefix',
'ssi_db_user',
'cache_accelerator',
- 'cache_memcached',
+ 'cache_servers',
'url_format',
+ 'cache_uid',
];
// These need HTML encoded. Be sure they all exist in $config_strs!
@@ -224,14 +227,77 @@ private function _cleanSettings()
'maintenance',
];
- // Now sort everything into a big array, and figure out arrays and etc.
+ // Now sort everything into a big array, and figure out arrays etc.
+ $this->cleanPasswords($config_passwords);
+
+ // Escape and update Setting strings
+ $this->cleanStrings($config_strs, $safe_strings);
+
+ // Ints are saved as integers
+ $this->cleanInts($config_ints);
+
+ // Convert checkbox selections to 0 / 1
+ $this->cleanBools($config_bools);
+ }
+
+ /**
+ * Fix the cookie name by removing invalid characters
+ */
+ private function _fixCookieName()
+ {
+ // Fix the darn stupid cookiename! (more may not be allowed, but these for sure!)
+ if (isset($this->configValues['cookiename']))
+ {
+ $this->configValues['cookiename'] = preg_replace('~[,;\s\.$]+~u', '', $this->configValues['cookiename']);
+ }
+ }
+
+ /**
+ * Fix the forum's URL if necessary so that it is a valid root url
+ */
+ private function _fixBoardUrl()
+ {
+ if (isset($this->configValues['boardurl']))
+ {
+ if (substr($this->configValues['boardurl'], -10) === '/index.php')
+ {
+ $this->configValues['boardurl'] = substr($this->configValues['boardurl'], 0, -10);
+ }
+ elseif (substr($this->configValues['boardurl'], -1) === '/')
+ {
+ $this->configValues['boardurl'] = substr($this->configValues['boardurl'], 0, -1);
+ }
+
+ $this->configValues['boardurl'] = addProtocol($this->configValues['boardurl'], ['http://', 'https://', 'file://']);
+ }
+ }
+
+ /**
+ * Clean passwords and add them to the new settings array
+ *
+ * @param array $config_passwords The array of config passwords to clean
+ */
+ public function cleanPasswords(array $config_passwords)
+ {
foreach ($config_passwords as $configVar)
{
+ // Handle skip_verify_pass. Only password[0] will exist from the form
+ $key = $this->_array_key_exists__recursive($this->configVars, $configVar, 0);
+ if ($key !== false
+ && !empty($this->configVars[$key]['skip_verify_pass'])
+ && $this->configValues[$configVar][0] !== '*#fakepass#*')
+ {
+ $this->new_settings[$configVar] = "'" . addcslashes($this->configValues[$configVar][0], '\'\\') . "'";
+ continue;
+ }
+
+ // Validate the _confirm password box exists
if (!isset($this->configValues[$configVar][1]))
{
continue;
}
+ // And that it has the same password
if ($this->configValues[$configVar][0] !== $this->configValues[$configVar][1])
{
continue;
@@ -239,13 +305,22 @@ private function _cleanSettings()
$this->new_settings[$configVar] = "'" . addcslashes($this->configValues[$configVar][0], '\'\\') . "'";
}
+ }
- // Escape and update Setting strings
+ /**
+ * Clean strings in the configuration values by escaping characters and applying safe transformations
+ * and add them to the new settings array
+ *
+ * @param array $config_strs The configuration strings to clean
+ * @param array $safe_strings The safe strings that should receive additional transformations
+ */
+ public function cleanStrings(array $config_strs, array $safe_strings)
+ {
foreach ($config_strs as $configVar)
{
if (isset($this->configValues[$configVar]))
{
- if (in_array($configVar, $safe_strings))
+ if (in_array($configVar, $safe_strings, true))
{
$this->new_settings[$configVar] = "'" . addcslashes(Util::htmlspecialchars(strtr($this->configValues[$configVar], ["\n" => ' ', "\r" => '']), ENT_QUOTES), '\'\\') . "'";
}
@@ -255,8 +330,17 @@ private function _cleanSettings()
}
}
}
+ }
- // Ints are saved as integers
+ /**
+ * Clean/cast integer values in the configuration array and add them to the new settings array
+ *
+ * @param array $config_ints The array of configuration variables to clean
+ *
+ * @return void
+ */
+ public function cleanInts(array $config_ints): void
+ {
foreach ($config_ints as $configVar)
{
if (isset($this->configValues[$configVar]))
@@ -264,47 +348,23 @@ private function _cleanSettings()
$this->new_settings[$configVar] = (int) $this->configValues[$configVar];
}
}
-
- // Convert checkbox selections to 0 / 1
- foreach ($config_bools as $key)
- {
- // Check boxes need to be part of this settings form
- if ($this->_array_value_exists__recursive($key, $this->getConfigVars()))
- {
- $this->new_settings[$key] = (int) !empty($this->configValues[$key]);
- }
- }
}
/**
- * Fix the cookie name by removing invalid characters
- */
- private function _fixCookieName()
- {
- // Fix the darn stupid cookiename! (more may not be allowed, but these for sure!)
- if (isset($this->configValues['cookiename']))
- {
- $this->configValues['cookiename'] = preg_replace('~[,;\s\.$]+~u', '', $this->configValues['cookiename']);
- }
- }
-
- /**
- * Fix the forum's URL if necessary so that it is a valid root url
+ * Clean boolean values in the provided config array to be 0 or 1 and add them to the new settings array
+ *
+ * @param array $config_bools The array of boolean keys to clean.
+ * @return void
*/
- private function _fixBoardUrl()
+ public function cleanBools(array $config_bools): void
{
- if (isset($this->configValues['boardurl']))
+ foreach ($config_bools as $key)
{
- if (substr($this->configValues['boardurl'], -10) === '/index.php')
- {
- $this->configValues['boardurl'] = substr($this->configValues['boardurl'], 0, -10);
- }
- elseif (substr($this->configValues['boardurl'], -1) === '/')
+ // Check boxes need to be part of this settings form
+ if ($this->_array_value_exists__recursive($key, $this->getConfigVars()))
{
- $this->configValues['boardurl'] = substr($this->configValues['boardurl'], 0, -1);
+ $this->new_settings[$key] = (int) !empty($this->configValues[$key]);
}
-
- $this->configValues['boardurl'] = addProtocol($this->configValues['boardurl'], ['http://', 'https://', 'file://']);
}
}
@@ -329,6 +389,34 @@ private function _array_value_exists__recursive($needle, $haystack)
return false;
}
+ /**
+ * Recursively search for a value in a multidimensional array and return the key
+ *
+ * @param array $haystack The array to search in
+ * @param mixed $needle The value to search for
+ * @param mixed $index The index to compare against (optional)
+ * @return string|int|false The key of the found value, false if array search completed without finding value
+ */
+ private function _array_key_exists__recursive($haystack, $needle, $index = null)
+ {
+ $aIt = new \RecursiveArrayIterator($haystack);
+ $it = new \RecursiveIteratorIterator($aIt);
+
+ while ($it->valid())
+ {
+ if (((isset($index) && $it->key() === $index) || (!isset($index)))
+ && $it->current() === $needle)
+ {
+ return $aIt->key();
+ }
+
+ $it->next();
+ }
+
+ // If the loop completed without finding the value, return false
+ return false;
+ }
+
/**
* Updates / Validates the Settings array for later output.
*
@@ -350,7 +438,7 @@ private function _prepareSettings()
$this->settingsArray[$k] = strtr($dummy, ["\r" => '']) . "\n";
}
- // go line by line and see whats changing
+ // go line by line and see what's changing
for ($i = 0, $n = count($this->settingsArray); $i < $n; $i++)
{
// Don't trim or bother with it if it's not a variable.
diff --git a/sources/subs/Cache.subs.php b/sources/subs/Cache.subs.php
index 625c301de5..bcf0186dc7 100644
--- a/sources/subs/Cache.subs.php
+++ b/sources/subs/Cache.subs.php
@@ -44,10 +44,7 @@ function cache_quick_get($key, $file, $function, $params, $level = 1)
*
* - It may "miss" so shouldn't be depended on
* - Uses the cache engine chosen in the ACP and saved in settings.php
- * - It supports:
- * memcache: http://www.php.net/memcache
- * APC: http://www.php.net/apc
- * Zend: http://files.zend.com/help/Zend-Platform/zend_cache_functions.htm
+ * - It supports Memcache, Memcached, APCu, Zend, Redis & Filebased engines
*
* @param string $key
* @param string|int|array|null $value
@@ -117,12 +114,19 @@ function clean_cache($type = '')
*/
function loadCacheEngines($supported_only = true)
{
- global $cache_memcached;
+ global $cache_servers, $cache_uid, $cache_password;
$engines = [];
$classes = new GlobIterator(SOURCEDIR . '/ElkArte/Cache/CacheMethod/*.php', FilesystemIterator::SKIP_DOTS);
+ $current = '';
+ $cache = Cache::instance();
+ if ($cache->isEnabled())
+ {
+ $current = $cache->getAccelerator();
+ }
+
foreach ($classes as $file_path)
{
// Get the engine name from the file name
@@ -137,15 +141,22 @@ function loadCacheEngines($supported_only = true)
// Validate the class name exists
if (class_exists($class))
{
- $options = [];
- if (strpos($engine_name, 'Memcache') === 0)
+ $options = [
+ 'servers' => empty($cache_servers) ? [] : explode(',', $cache_servers),
+ 'cache_uid' => empty($cache_uid) ? '' : $cache_uid,
+ 'cache_password' => empty($cache_password) ? '' : $cache_password,
+ ];
+
+ // Use the current Cache object if its been enabled
+ if ($engine_name === $current)
+ {
+ $obj = $cache->getCacheEngine();
+ }
+ else
{
- $options = [
- 'servers' => explode(',', $cache_memcached),
- ];
+ $obj = new $class($options);
}
- $obj = new $class($options);
if ($obj instanceof AbstractCacheMethod)
{
if ($supported_only && $obj->isAvailable())
diff --git a/themes/default/Admin.template.php b/themes/default/Admin.template.php
index c46554431d..b642b0e213 100644
--- a/themes/default/Admin.template.php
+++ b/themes/default/Admin.template.php
@@ -569,7 +569,7 @@ function template_show_settings()
else
{
echo '
-