Browse Source

! cache accelerator changes
! move cache engine choice to the setting.php file, instead of saving the choice in a cached file?
! allow choosing from any installed cache engines
! clean_cache now cleans the other caches, not just smf cache
! re-layout the cache settings page

Spuds 12 years ago
parent
commit
8cdc309d30

+ 154 - 107
Sources/Load.php

@@ -2598,9 +2598,16 @@ function cache_quick_get($key, $file, $function, $params, $level = 1)
 
 /**
  * Puts value in the cache under key for ttl seconds.
- * It may "miss" so shouldn't be depended on, and may go to any of many
- * various caching servers.
- * It supports eAccelerator, Turck MMCache, APC, ZPS, and memcached.
+ * It may "miss" so shouldn't be depended on, and may go to any of many various caching servers.
+ * It supports:
+ *
+ * Turck MMCache: http://turck-mmcache.sourceforge.net/index_old.html#api
+ * Xcache: http://xcache.lighttpd.net/wiki/XcacheApi
+ * memcache: http://www.php.net/memcache
+ * APC: http://www.php.net/apc
+ * eAccelerator: http://bart.eaccelerator.net/doc/phpdoc/
+ * Zend: http://files.zend.com/help/Zend-Platform/output_cache_functions.htm
+ * Zend: http://files.zend.com/help/Zend-Platform/zend_cache_functions.htm
  *
  * @param string $key
  * @param mixed $value
@@ -2610,8 +2617,9 @@ function cache_put_data($key, $value, $ttl = 120)
 {
 	global $boardurl, $sourcedir, $modSettings, $memcached;
 	global $cache_hits, $cache_count, $db_show_debug, $cachedir;
+	global $cache_accelerator, $cache_enable;
 
-	if (empty($modSettings['cache_enable']) && !empty($modSettings))
+	if (empty($cache_enable))
 		return;
 
 	$cache_count = isset($cache_count) ? $cache_count + 1 : 1;
@@ -2624,74 +2632,94 @@ function cache_put_data($key, $value, $ttl = 120)
 	$key = md5($boardurl . filemtime($sourcedir . '/Load.php')) . '-SMF-' . strtr($key, ':', '-');
 	$value = $value === null ? null : serialize($value);
 
-	// The simple yet efficient memcached.
-	if (function_exists('memcached_set') || function_exists('memcache_set') && isset($modSettings['cache_memcached']) && trim($modSettings['cache_memcached']) != '')
+	switch ($cache_accelerator)
 	{
-		// Not connected yet?
-		if (empty($memcached))
-			get_memcached_server();
-		if (!$memcached)
-			return;
+		case 'memcached':
+			// The simple yet efficient memcached.
+			if (function_exists('memcached_set') || function_exists('memcache_set') && isset($modSettings['cache_memcached']) && trim($modSettings['cache_memcached']) != '')
+			{
+				// Not connected yet?
+				if (empty($memcached))
+					get_memcached_server();
+				if (!$memcached)
+					return;
 
-		memcache_set($memcached, $key, $value, 0, $ttl);
-	}
-	// eAccelerator...
-	elseif (function_exists('eaccelerator_put'))
-	{
-		if (mt_rand(0, 10) == 1)
-			eaccelerator_gc();
+				memcache_set($memcached, $key, $value, 0, $ttl);
+			}
+			break;
+		case 'eaccelerator':
+			// eAccelerator...
+			if (function_exists('eaccelerator_put'))
+			{
+				if (mt_rand(0, 10) == 1)
+					eaccelerator_gc();
 
-		if ($value === null)
-			@eaccelerator_rm($key);
-		else
-			eaccelerator_put($key, $value, $ttl);
-	}
-	// Turck MMCache?
-	elseif (function_exists('mmcache_put'))
-	{
-		if (mt_rand(0, 10) == 1)
-			mmcache_gc();
+				if ($value === null)
+					@eaccelerator_rm($key);
+				else
+					eaccelerator_put($key, $value, $ttl);
+			}
+			break;
+		case 'mmcache':
+			// Turck MMCache?
+			if (function_exists('mmcache_put'))
+			{
+				if (mt_rand(0, 10) == 1)
+					mmcache_gc();
 
-		if ($value === null)
-			@mmcache_rm($key);
-		else
-			mmcache_put($key, $value, $ttl);
-	}
-	// Alternative PHP Cache, ahoy!
-	elseif (function_exists('apc_store'))
-	{
-		// An extended key is needed to counteract a bug in APC.
-		if ($value === null)
-			apc_delete($key . 'smf');
-		else
-			apc_store($key . 'smf', $value, $ttl);
-	}
-	// Zend Platform/ZPS/etc.
-	elseif (function_exists('output_cache_put'))
-		output_cache_put($key, $value);
-	elseif (function_exists('xcache_set') && ini_get('xcache.var_size') > 0)
-	{
-		if ($value === null)
-			xcache_unset($key);
-		else
-			xcache_set($key, $value, $ttl);
-	}
-	// Otherwise custom cache?
-	else
-	{
-		if ($value === null)
-			@unlink($cachedir . '/data_' . $key . '.php');
-		else
-		{
-			$cache_data = '<' . '?' . 'php if (!defined(\'SMF\')) die; if (' . (time() + $ttl) . ' < time()) $expired = true; else{$expired = false; $value = \'' . addcslashes($value, '\\\'') . '\';}' . '?' . '>';
-			
-			// 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 . '/data_' . $key . '.php', $cache_data, LOCK_EX) !== strlen($cache_data))
+				if ($value === null)
+					@mmcache_rm($key);
+				else
+				{
+					mmcache_lock($key);
+					mmcache_put($key, $value, $ttl);
+					mmcache_unlock($key);
+				}
+			}
+			break;
+		case 'apc':
+			// Alternative PHP Cache, ahoy!
+			if (function_exists('apc_store'))
+			{
+				// An extended key is needed to counteract a bug in APC.
+				if ($value === null)
+					apc_delete($key . 'smf');
+				else
+					apc_store($key . 'smf', $value, $ttl);
+			}
+			break;
+		case 'zend':
+			// Zend Platform/ZPS/etc.
+			if (function_exists('zend_shm_cache_store'))
+				zend_shm_cache_store('SMF::' . $key, $value, $ttl);
+			elseif (function_exists('output_cache_put'))
+				output_cache_put($key, $value);
+			break;
+		case 'xcache':
+			if (function_exists('xcache_set') && ini_get('xcache.var_size') > 0)
+			{
+				if ($value === null)
+					xcache_unset($key);
+				else
+					xcache_set($key, $value, $ttl);
+			}
+			break;
+		default:
+			// Otherwise custom cache?
+			if ($value === null)
 				@unlink($cachedir . '/data_' . $key . '.php');
-		}
+			else
+			{
+				$cache_data = '<' . '?' . 'php if (!defined(\'SMF\')) die; if (' . (time() + $ttl) . ' < time()) $expired = true; else{$expired = false; $value = \'' . addcslashes($value, '\\\'') . '\';}' . '?' . '>';
+
+				// 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 . '/data_' . $key . '.php', $cache_data, LOCK_EX) !== strlen($cache_data))
+					@unlink($cachedir . '/data_' . $key . '.php');
+			}
+			break;
 	}
-	
+
 	if (function_exists('call_integration_hook'))
 		call_integration_hook('cache_put_data', array(&$key, &$value, &$ttl));
 
@@ -2700,8 +2728,7 @@ function cache_put_data($key, $value, $ttl = 120)
 }
 
 /**
- * Gets the value from the cache specified by key, so long as it is not older
- * than ttl seconds.
+ * Gets the value from the cache specified by key, so long as it is not older than ttl seconds.
  * It may often "miss", so shouldn't be depended on.
  * It supports the same as cache_put_data().
  *
@@ -2713,8 +2740,9 @@ function cache_get_data($key, $ttl = 120)
 {
 	global $boardurl, $sourcedir, $modSettings, $memcached;
 	global $cache_hits, $cache_count, $db_show_debug, $cachedir;
+	global $cache_accelerator, $cache_enable;
 
-	if (empty($modSettings['cache_enable']) && !empty($modSettings))
+	if (empty($cache_enable))
 		return;
 
 	$cache_count = isset($cache_count) ? $cache_count + 1 : 1;
@@ -2726,40 +2754,59 @@ function cache_get_data($key, $ttl = 120)
 
 	$key = md5($boardurl . filemtime($sourcedir . '/Load.php')) . '-SMF-' . strtr($key, ':', '-');
 
-	// Okay, let's go for it memcached!
-	if ((function_exists('memcache_get') || function_exists('memcached_get')) && isset($modSettings['cache_memcached']) && trim($modSettings['cache_memcached']) != '')
-	{
-		// Not connected yet?
-		if (empty($memcached))
-			get_memcached_server();
-		if (!$memcached)
-			return null;
-		
-		$value = (function_exists('memcache_get')) ? memcache_get($cache['connection'], $key) : memcached_get($cache['connection'], $key);
-	}
-	// Again, eAccelerator.
-	elseif (function_exists('eaccelerator_get'))
-		$value = eaccelerator_get($key);
-	// The older, but ever-stable, Turck MMCache...
-	elseif (function_exists('mmcache_get'))
-		$value = mmcache_get($key);
-	// This is the free APC from PECL.
-	elseif (function_exists('apc_fetch'))
-		$value = apc_fetch($key . 'smf');
-	// Zend's pricey stuff.
-	elseif (function_exists('output_cache_get'))
-		$value = output_cache_get($key, $ttl);
-	elseif (function_exists('xcache_get') && ini_get('xcache.var_size') > 0)
-		$value = xcache_get($key);
-	// Otherwise it's SMF data!
-	elseif (file_exists($cachedir . '/data_' . $key . '.php') && filesize($cachedir . '/data_' . $key . '.php') > 10)
-	{
-		require($cachedir . '/data_' . $key . '.php');
-		if (!empty($expired) && isset($value))
-		{
-			@unlink($cachedir . '/data_' . $key . '.php');
-			unset($value);
-		}
+	switch ($cache_accelerator)
+	{
+		case 'memcache':
+			// Okay, let's go for it memcached!
+			if ((function_exists('memcache_get') || function_exists('memcached_get')) && isset($modSettings['cache_memcached']) && trim($modSettings['cache_memcached']) != '')
+			{
+				// Not connected yet?
+				if (empty($memcached))
+					get_memcached_server();
+				if (!$memcached)
+					return null;
+
+				$value = (function_exists('memcache_get')) ? memcache_get($cache['connection'], $key) : memcached_get($cache['connection'], $key);
+			}
+			break;
+		case 'eaccelerator':
+			// Again, eAccelerator.
+			if (function_exists('eaccelerator_get'))
+				$value = eaccelerator_get($key);
+			break;
+		case 'mmcache':
+			// The older, but ever-stable, Turck MMCache...
+			if (function_exists('mmcache_get'))
+				$value = mmcache_get($key);
+			break;
+		case 'apc':
+			// This is the free APC from PECL.
+			if (function_exists('apc_fetch'))
+				$value = apc_fetch($key . 'smf');
+			break;
+		case 'zend':
+			// Zend's pricey stuff.
+			if (function_exists('zend_shm_cache_fetch'))
+				$value = zend_shm_cache_fetch('SMF::' . $key, $ttl);
+			elseif (function_exists('output_cache_get'))
+				$value = output_cache_get($key, $ttl);
+			break;
+		case 'xcache':
+			if (function_exists('xcache_get') && ini_get('xcache.var_size') > 0)
+				$value = xcache_get($key);
+			break;
+		default:
+			// Otherwise it's SMF data!
+			if (file_exists($cachedir . '/data_' . $key . '.php') && filesize($cachedir . '/data_' . $key . '.php') > 10)
+			{
+				require($cachedir . '/data_' . $key . '.php');
+				if (!empty($expired) && isset($value))
+				{
+					@unlink($cachedir . '/data_' . $key . '.php');
+					unset($value);
+				}
+			}
+			break;
 	}
 
 	if (isset($db_show_debug) && $db_show_debug === true)
@@ -2767,7 +2814,7 @@ function cache_get_data($key, $ttl = 120)
 		$cache_hits[$cache_count]['t'] = array_sum(explode(' ', microtime())) - array_sum(explode(' ', $st));
 		$cache_hits[$cache_count]['s'] = isset($value) ? strlen($value) : 0;
 	}
-	
+
 	if (function_exists('call_integration_hook'))
 		call_integration_hook('cache_get_data', array(&$key, &$ttl, &$value));
 
@@ -2778,15 +2825,15 @@ function cache_get_data($key, $ttl = 120)
  * Get memcache servers.
  * This function is used by cache_get_data() and cache_put_data().
  * It attempts to connect to a random server in the cache_memcached setting.
- * It recursively calls itself up to recursion_level times.
+ * It recursively calls itself up to $level times.
  *
  * @param int $level = 3
  */
 function get_memcached_server($level = 3)
 {
-	global $modSettings, $memcached, $db_persist;
+	global $modSettings, $memcached, $db_persist, $cache_memcached;
 
-	$servers = explode(',', $modSettings['cache_memcached']);
+	$servers = explode(',', $cache_memcached);
 	$server = explode(':', trim($servers[array_rand($servers)]));
 	$cache = (function_exists('memcache_get')) ? 'memcache' : ((function_exists('memcached_get') ? 'memcached' : ''));
 

+ 133 - 84
Sources/ManageServer.php

@@ -1,11 +1,11 @@
 <?php
 
 /**
- * Contains all the functionality required to be able to edit the
- * core server settings. This includes anything from which an error may
- * result in the forum destroying itself in a firey fury.
+ * Contains all the functionality required to be able to edit the core server 
+ * settings. This includes anything from which an error may result in the forum
+ * destroying itself in a firey fury.
  *
- * Adding options to one of the setting screens isn't hard. Call prepareDBSettingContext;
+ * Adding options to one of the setting screens isn't hard. Call prepareDBSettingsContext;
  * The basic format for a checkbox is:
  * 		array('check', 'nameInModSettingsAndSQL'),
  * And for a text box:
@@ -17,41 +17,33 @@
  *
  * Here's a quick explanation of how to add a new item:
  *
- * * A text input box.  For textual values.
- * ie.	array('text', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
- *
- * * A text input box.  For numerical values.
- * ie.	array('int', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
- *
- * * A text input box.  For floating point values.
- * ie.	array('float', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
- *
- * * A large text input box. Used for textual values spanning multiple lines.
- * ie.	array('large_text', 'nameInModSettingsAndSQL', 'OptionalNumberOfRows'),
- *
- * * A check box.  Either one or zero. (boolean)
- * ie.	array('check', 'nameInModSettingsAndSQL'),
- *
- * * A selection box.  Used for the selection of something from a list.
- * ie.	array('select', 'nameInModSettingsAndSQL', array('valueForSQL' => $txt['displayedValue'])),
- * Note that just saying array('first', 'second') will put 0 in the SQL for 'first'.
- *
- * * A password input box. Used for passwords, no less!
- * ie.	array('password', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
- *
- * * A permission - for picking groups who have a permission.
- * ie.	array('permissions', 'manage_groups'),
- *
- * * A BBC selection box.
- * ie.	array('bbc', 'sig_bbc'),
+ * - A text input box.  For textual values.
+ * 		array('text', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
+ * - A text input box.  For numerical values.
+ * 		array('int', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
+ * - A text input box.  For floating point values.
+ * 		array('float', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
+ * - A large text input box. Used for textual values spanning multiple lines.
+ * 		array('large_text', 'nameInModSettingsAndSQL', 'OptionalNumberOfRows'),
+ * - A check box.  Either one or zero. (boolean)
+ * 		array('check', 'nameInModSettingsAndSQL'),
+ * - A selection box.  Used for the selection of something from a list.
+ * 		array('select', 'nameInModSettingsAndSQL', array('valueForSQL' => $txt['displayedValue'])),
+ * 		Note that just saying array('first', 'second') will put 0 in the SQL for 'first'.
+ * - A password input box. Used for passwords, no less!
+ * 		array('password', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
+ * - A permission - for picking groups who have a permission.
+ * 		array('permissions', 'manage_groups'),
+ * - A BBC selection box.
+ * 		array('bbc', 'sig_bbc'),
  *
  * For each option:
- * 	type (see above), variable name, size/possible values.
- * 	OR	make type '' for an empty string for a horizontal rule.
- *  SET	preinput - to put some HTML prior to the input box.
- *  SET	postinput - to put some HTML following the input box.
- *  SET	invalid - to mark the data as invalid.
- *  PLUS you can override label and help parameters by forcing their keys in the array, for example:
+ * 	- type (see above), variable name, size/possible values.
+ * 	  OR make type '' for an empty string for a horizontal rule.
+ *  - SET preinput - to put some HTML prior to the input box.
+ *  - SET postinput - to put some HTML following the input box.
+ *  - SET invalid - to mark the data as invalid.
+ *  - PLUS you can override label and help parameters by forcing their keys in the array, for example:
  *  	array('text', 'invalidlabel', 3, 'label' => 'Actual Label')
  *
  * Simple Machines Forum (SMF)
@@ -69,7 +61,8 @@ if (!defined('SMF'))
 
 /**
  * This is the main dispatcher. Sets up all the available sub-actions, all the tabs and selects
- *  the appropriate one based on the sub-action.
+ * the appropriate one based on the sub-action.
+ *
  * Requires the admin_forum permission.
  * Redirects to the appropriate function based on the sub-action.
  *
@@ -205,10 +198,10 @@ function ModifyDatabaseSettings($return_config = false)
 	global $scripturl, $context, $settings, $txt, $boarddir;
 
 	/* If you're writing a mod, it's a bad idea to add things here....
-	For each option:
+		For each option:
 		variable name, description, type (constant), size/possible values, helptext.
-	OR	an empty string for a horizontal rule.
-	OR	a string for a titled section. */
+		OR an empty string for a horizontal rule.
+		OR a string for a titled section. */
 	$config_vars = array(
 		array('db_server', $txt['database_server'], 'file', 'text'),
 		array('db_user', $txt['database_user'], 'file', 'text'),
@@ -326,14 +319,67 @@ function ModifyCookieSettings($return_config = false)
  */
 function ModifyCacheSettings($return_config = false)
 {
-	global $context, $scripturl, $txt, $helptxt, $modSettings;
+	global $context, $scripturl, $txt, $helptxt, $cache_enable;
+	
+	// Detect all available optimizers
+	$detected = array();
+	if (function_exists('eaccelerator_put'))
+		$detected['eaccelerator'] = $txt['eAccelerator_cache'];
+	if (function_exists('mmcache_put'))
+		$detected['mmcache'] = $txt['mmcache_cache'];
+	if (function_exists('apc_store'))
+		$detected['apc'] = $txt['apc_cache'];
+	if (function_exists('output_cache_put') || function_exists('zend_shm_cache_store'))
+		$detected['zend'] = $txt['zend_cache'];
+	if (function_exists('memcache_set') || function_exists('memcached_set'))
+		$detected['memcached'] = $txt['memcached_cache'];
+	if (function_exists('xcache_set'))
+		$detected['xcache'] = $txt['xcache_cache'];
+		
+	// set a message to show what, if anything, we found
+	if (empty($detected))
+		$txt['cache_settings_message'] = $txt['detected_no_caching'];
+	else
+		$txt['cache_settings_message'] = sprintf($txt['detected_accelerators'], implode(', ', $detected));
+	
+	// This is always an option
+	$detected['smf'] = $txt['default_cache'];
 
 	// Define the variables we want to edit.
 	$config_vars = array(
-		// Only a couple of settings, but they are important
-		array('select', 'cache_enable', array($txt['cache_off'], $txt['cache_level1'], $txt['cache_level2'], $txt['cache_level3'])),
-		array('text', 'cache_memcached'),
+		// Only a few settings, but they are important
+		array('', $txt['cache_settings_message'], '', 'desc'),
+		array('cache_enable', $txt['cache_enable'], 'file', 'select', array($txt['cache_off'], $txt['cache_level1'], $txt['cache_level2'], $txt['cache_level3']), 'cache_enable'),
+		array('cache_accelerator', $txt['cache_accelerator'], 'file', 'select', $detected),
+		array('cache_memcached', $txt['cache_memcached'], 'file', 'text', $txt['cache_memcached'], 'cache_memcached'),
+		array('cachedir', $txt['cachedir'], 'file', 'text', 36, 'cache_cachedir'),
 	);
+	
+	// some javascript to enable / disable certain settings if the option is not selected
+	$context['settings_post_javascript'] = '
+		var cache_type = document.getElementById(\'cache_accelerator\');
+		mod_addEvent(cache_type, \'change\', toggleCache);
+		toggleCache();
+
+		function mod_addEvent(control, ev, fn)
+		{
+			if (control.addEventListener)
+			{
+				control.addEventListener(ev, fn, false); 
+			} 
+			else if (control.attachEvent)
+			{
+				control.attachEvent(\'on\'+ev, fn);
+			}
+		}
+		function toggleCache()
+		{
+			var select_elem1 = document.getElementById(\'cache_memcached\');
+			var select_elem2 = document.getElementById(\'cachedir\');
+			select_elem1.disabled = cache_type.value != "memcached";
+			select_elem2.disabled = cache_type.value != "smf";
+		}
+	';
 
 	call_integration_hook('integrate_modify_cache_settings', array(&$config_vars));
 
@@ -345,46 +391,31 @@ function ModifyCacheSettings($return_config = false)
 	{
 		call_integration_hook('integrate_save_cache_settings');
 
-		saveDBSettings($config_vars);
-
-		// We have to manually force the clearing of the cache otherwise the changed settings might not get noticed.
-		$cache_enable = $modSettings['cache_enable'];
-		$modSettings['cache_enable'] = 1;
-		cache_put_data('modSettings', null, 90);
-		$modSettings['cache_enable'] = $cache_enable;
+		saveSettings($config_vars);
+		
+		// we need to save the $cache_enable to $modSettings as well
+		updatesettings(array('cache_enable' => (int) $_POST['cache_enable']));
 
-		if ($modSettings['cache_enable'] == 0)
-		{
-			loadLanguage('ManageMaintenance');
-			createToken('admin-maint');
-			$context['template_layers'][] = 'clean_cache_button';
-		}
+		// exit so we reload our new settings on the page
+		redirectexit('action=admin;area=serversettings;sa=cache;' . $context['session_var'] . '=' . $context['session_id']);
+	}
+	
+	// if its off, allow them to clear it as well
+	// @todo why only when its off ?
+	if (empty($cache_enable))
+	{
+		loadLanguage('ManageMaintenance');
+		createToken('admin-maint');
+		$context['template_layers'][] = 'clean_cache_button';
 	}
 
 	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=cache;save';
 	$context['settings_title'] = $txt['caching_settings'];
 	$context['settings_message'] = $txt['caching_information'];
 
-	// Detect an optimizer?
-	if (function_exists('eaccelerator_put'))
-		$detected = 'eAccelerator';
-	elseif (function_exists('mmcache_put'))
-		$detected = 'MMCache';
-	elseif (function_exists('apc_store'))
-		$detected = 'APC';
-	elseif (function_exists('output_cache_put'))
-		$detected = 'Zend';
-	elseif (function_exists('memcache_set') || function_exists('memcached_set'))
-		$detected = 'Memcached';
-	elseif (function_exists('xcache_set'))
-		$detected = 'XCache';
-	else
-		$detected = 'no_caching';
-
-	$context['settings_message'] = sprintf($context['settings_message'], $txt['detected_' . $detected]);
-
 	// Prepare the template.
-	prepareDBSettingContext($config_vars);
+	createToken('admin-ssc');
+	prepareServerSettingsContext($config_vars);
 }
 
 /**
@@ -421,7 +452,7 @@ function ModifyLoadBalancingSettings($return_config = false)
 
 	// Start with a simple checkbox.
 	$config_vars = array(
-		array('check', 'loadavg_enable'),
+		array('check', 'loadavg_enable', 'disabled' => $disabled),
 	);
 
 	// Set the default values for each option.
@@ -472,7 +503,8 @@ function ModifyLoadBalancingSettings($return_config = false)
 		saveDBSettings($config_vars);
 		redirectexit('action=admin;area=serversettings;sa=loads;' . $context['session_var'] . '=' . $context['session_id']);
 	}
-
+	
+	createToken('admin-ssc');
 	prepareDBSettingContext($config_vars);
 }
 
@@ -518,12 +550,12 @@ function prepareServerSettingsContext(&$config_vars)
 				$config_var[1] = substr($config_var[1], 0, $divPos);
 			}
 
-			$context['config_vars'][] = array(
+			$context['config_vars'][$config_var[0]] = array(
 				'label' => $config_var[1],
 				'help' => isset($config_var[5]) ? $config_var[5] : '',
 				'type' => $config_var[3],
 				'size' => empty($config_var[4]) ? 0 : $config_var[4],
-				'data' => isset($config_var[4]) && is_array($config_var[4]) ? $config_var[4] : array(),
+				'data' => isset($config_var[4]) && is_array($config_var[4]) && $config_var[3] != 'select' ? $config_var[4] : array(),
 				'name' => $config_var[0],
 				'value' => $config_var[2] == 'file' ? htmlspecialchars($$varname) : (isset($modSettings[$config_var[0]]) ? htmlspecialchars($modSettings[$config_var[0]]) : (in_array($config_var[3], array('int', 'float')) ? 0 : '')),
 				'disabled' => !empty($context['settings_not_writable']) || !empty($config_var['disabled']),
@@ -533,10 +565,23 @@ function prepareServerSettingsContext(&$config_vars)
 				'preinput' => !empty($config_var['preinput']) ? $config_var['preinput'] : '',
 				'postinput' => !empty($config_var['postinput']) ? $config_var['postinput'] : '',
 			);
+			
+			// If this is a select box handle any data.
+			if (!empty($config_var[4]) && is_array($config_var[4]))
+			{
+				// If it's associative
+				if (isset($config_var[4][0]) && is_array($config_var[4][0]))
+					$context['config_vars'][$config_var[0]]['data'] = $config_var[4];
+				else
+				{
+					foreach ($config_var[4] as $key => $item)
+						$context['config_vars'][$config_var[0]]['data'][] = array($key, $item);
+				}
+			}
 		}
 	}
 
-	// Two tokens because save these settings require both saveSettings and saveDBSettings
+	// Two tokens because saving these settings requires both saveSettings and saveDBSettings
 	createToken('admin-ssc');
 	createToken('admin-dbsc');
 }
@@ -743,11 +788,15 @@ function saveSettings(&$config_vars)
 		'cookiename',
 		'webmaster_email',
 		'db_name', 'db_user', 'db_server', 'db_prefix', 'ssi_db_user',
-		'boarddir', 'sourcedir', 'cachedir',
+		'boarddir', 'sourcedir', 
+		'cachedir', 'cache_accelerator', 'cache_memcached',
 	);
+	
 	// All the numeric variables.
 	$config_ints = array(
+		'cache_enable',
 	);
+	
 	// All the checkboxes.
 	$config_bools = array(
 		'db_persist', 'db_error_send',
@@ -783,7 +832,7 @@ function saveSettings(&$config_vars)
 	require_once($sourcedir . '/Subs-Admin.php');
 	updateSettingsFile($new_settings);
 
-	// Now loopt through the remaining (database-based) settings.
+	// Now loop through the remaining (database-based) settings.
 	$new_settings = array();
 	foreach ($config_vars as $config_var)
 	{

+ 2 - 0
Sources/ManageSettings.php

@@ -63,6 +63,7 @@ function ModifyFeatureSettings()
 
 	call_integration_hook('integrate_modify_features', array(&$subActions));
 
+	// If Advanced Profile Fields are disabled don't show the setting page
 	if (!in_array('cp', $context['admin_features']))
 		unset($subActions['profile']);
 
@@ -394,6 +395,7 @@ function ModifyCoreFeatures($return_config = false)
 
 		// Make any setting changes!
 		updateSettings($setting_changes);
+
 		// This is needed to let menus appear if cache > 2
 		clean_cache('data');
 

+ 91 - 15
Sources/Subs.php

@@ -3497,28 +3497,104 @@ function create_button($name, $alt, $label = '', $custom = '', $force_use = fals
 }
 
 /**
- * Empty out the cache folder.
- * clean the cache directory ($cachedir, if any and in use)
+ * Empty out the cache in use as best it can
+ *
  * it may only remove the files of a certain type (if the $type parameter is given)
+ * Type can be user, data or left blank
+ * 	- user clears out user data
+ *  - data clears out system / opcode data
+ *  - If no type is specified will perfom a complete cache clearing
+ * For cache engines that do not distinguish on types, a full cache flush will be done
  *
- * @param string $type = ''
+ * @param string $type = '' 
  */
 function clean_cache($type = '')
 {
-	global $cachedir, $sourcedir;
-
-	// No directory = no game.
-	if (!is_dir($cachedir))
-		return;
-
-	// Remove the files in SMF's own disk cache, if any
-	$dh = opendir($cachedir);
-	while ($file = readdir($dh))
+	global $cachedir, $sourcedir, $cache_accelerator, $modSettings, $memcached;
+	
+	switch ($cache_accelerator)
 	{
-		if ($file != '.' && $file != '..' && $file != 'index.php' && $file != '.htaccess' && (!$type || substr($file, 0, strlen($type)) == $type))
-			@unlink($cachedir . '/' . $file);
+		case 'memcached':
+			if (function_exists('memcache_flush') || function_exists('memcached_flush') && isset($modSettings['cache_memcached']) && trim($modSettings['cache_memcached']) != '')
+			{
+				// Not connected yet?
+				if (empty($memcached))
+					get_memcached_server();
+				if (!$memcached)
+					return;
+
+				// clear it out
+				if (function_exists('memcache_flush'))
+					memcache_flush($memcached);
+				else
+					memcached_flush($memcached);
+			}
+			break;
+		case 'eaccelerator':
+			if (function_exists('eaccelerator_clear') && function_exists('eaccelerator_clean') )
+			{ 
+				// Clean out the already expired items
+				@eaccelerator_clean();
+				
+				// Remove all unused scripts and data from shared memory and disk cache, 
+				// e.g. all data that isn't used in the current requests.
+				eaccelerator_clear();
+			}
+		case 'mmcache':
+			if (function_exists('mmcache_gc'))
+			{
+				// removes all expired keys from shared memory, this is not a complete cache flush :(
+				// @todo there is no clear function, should we try to find all of the keys and delete those? with mmcache_rm
+				mmcache_gc();
+			}
+			break;
+		case 'apc':
+			if (function_exists('apc_clear_cache'))
+			{
+				// if passed a type, clear that type out
+				if ($type === '' || $type === 'data')
+				{
+					apc_clear_cache('user');
+					apc_clear_cache('system');
+				}
+				elseif ($type === 'user')
+					apc_clear_cache('user');
+			}
+			break;
+		case 'zend':
+			if (function_exists('zend_shm_cache_clear'))
+				zend_shm_cache_clear('SMF');
+			break;
+		case 'xcache':
+			if (function_exists('xcache_clear_cache'))
+			{
+				// 
+				if ($type === '')
+				{
+					xcache_clear_cache(XC_TYPE_VAR, 0);
+					xcache_clear_cache(XC_TYPE_PHP, 0);
+				}
+				if ($type === 'user')
+					xcache_clear_cache(XC_TYPE_VAR, 0);
+				if ($type === 'data')
+					xcache_clear_cache(XC_TYPE_PHP, 0);
+			}
+			break;
+		default:
+			// No directory = no game.
+			if (!is_dir($cachedir))
+				return;
+
+			// Remove the files in SMF's own disk cache, if any
+			$dh = opendir($cachedir);
+			while ($file = readdir($dh))
+			{
+				if ($file != '.' && $file != '..' && $file != 'index.php' && $file != '.htaccess' && (!$type || substr($file, 0, strlen($type)) == $type))
+					@unlink($cachedir . '/' . $file);
+			}
+			closedir($dh);
+			break;
 	}
-	closedir($dh);
 
 	// Invalidate cache, to be sure!
 	// ... as long as Load.php can be modified, anyway.

+ 3 - 0
Themes/default/languages/Help.english.php

@@ -279,6 +279,9 @@ $helptxt['disableTemplateEval'] = 'By default, templates are evaluated instead o
 $helptxt['databaseSession_enable'] = 'This option makes use of the database for session storage - it is best for load balanced servers, but helps with all timeout issues and can make the forum faster.';
 $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 &quot;timed out&quot;.  Anything higher than 2400 is recommended.';
+$helptxt['cache_enable'] = 'SMF 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:<br /><br/>	&quot;server1,server2,server3:port,server4&quot;<br /><br />Note that if no port is specified SMF will use port 11211. SMF will attempt to perform rough/random load balancing across the specified servers.';
+$helptxt['cache_cachedir'] = 'This setting This is only for the smf file 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['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.<br /><br /><strong>Note:  This will affect the ability to filter the error log by the error message.</strong>';
 $helptxt['allow_disableAnnounce'] = 'This will allow users to opt out of notification of topics you announce by checking the &quot;announce topic&quot; checkbox when posting.';

+ 21 - 28
Themes/default/languages/ManageSettings.english.php

@@ -96,35 +96,20 @@ $txt['karmaLabel'] = 'Karma label';
 $txt['karmaApplaudLabel'] = 'Karma applaud label';
 $txt['karmaSmiteLabel'] = 'Karma smite label';
 
-$txt['caching_information'] = '<div class="aligncenter underline"><strong>Important! Read this first before enabling these features.</strong></div><br />
-	SMF supports caching through the use of accelerators. The currently supported accelerators include:<br />
-	<ul class="normallist">
-		<li>APC</li>
-		<li>eAccelerator</li>
-		<li>Turck MMCache</li>
-		<li>Memcached</li>
-		<li>Zend Platform/Performance Suite (Not Zend Optimizer)</li>
-		<li>XCache</li>
-	</ul>
-	Caching will work best if you have PHP compiled with one of the above optimizers, or have memcache
-	available. If you do not have any optimizer installed SMF will do file based caching.<br /><br />
-	SMF 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.
-	<br /><br />
-	Note that if you use memcached you need to provide the server details in the setting below. This should be entered as a comma separated list
-	as shown in the example below:<br />
-	&quot;server1,server2,server3:port,server4&quot;<br /><br />
-	Note that if no port is specified SMF will use port 11211. SMF will attempt to perform rough/random load balancing across the servers.
-	<br /><br />
-	%1$s';
+$txt['caching_information'] = '<div class="aligncenter underline"><strong>Important! Read this first before enabling these features.</strong></div>
+SMF supports caching through the use of accelerators. The currently supported accelerators include:
+<ul class="normallist">
+	<li>APC</li>
+	<li>eAccelerator</li>
+	<li>Turck MMCache</li>
+	<li>Memcached</li>
+	<li>Zend Platform/Performance Suite (Not Zend Optimizer)</li>
+	<li>XCache</li>
+</ul>
+Caching will work best if you have PHP compiled with one of the above optimizers, or have memcache available. If you do not have any optimizer installed SMF will do file based caching.';
+$txt['detected_no_caching'] = '<strong class="alert">SMF has not been able to detect a compatible accelerator on your server.  File based caching can be used instead.</strong>';
+$txt['detected_accelerators'] = '<strong class="success">SMF has detected the following accelerators: %1$s</strong>';
 
-$txt['detected_no_caching'] = '<strong class="alert">SMF has not been able to detect a compatible accelerator on your server.</strong>';
-$txt['detected_APC'] = '<strong style="color: green">SMF has detected that your server has APC installed.</strong>';
-$txt['detected_eAccelerator'] = '<strong style="color: green">SMF has detected that your server has eAccelerator installed.</strong>';
-$txt['detected_MMCache'] = '<strong style="color: green">SMF has detected that your server has MMCache installed.</strong>';
-$txt['detected_Zend'] = '<strong style="color: green">SMF has detected that your server has Zend installed.</strong>';
-$txt['detected_Memcached'] = '<strong style="color: green">SMF has detected that your server has Memcached installed.</strong>';
-$txt['detected_XCache'] = '<strong style="color: green">SMF has detected that your server has XCache installed.</strong>';
 
 $txt['cache_enable'] = 'Caching Level';
 $txt['cache_off'] = 'No caching';
@@ -132,6 +117,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'] = 'Memcache settings';
+$txt['cache_accelerator'] = 'Caching Accelerator';
+$txt['default_cache'] = 'SMF file based caching';
+$txt['apc_cache'] = 'APC';
+$txt['eAccelerator_cache'] = 'eAccelerator';
+$txt['mmcache_cache'] = 'Turck MMCache';
+$txt['memcached_cache'] = 'Memcached';
+$txt['zend_cache'] = 'Zend Platform/Performance Suite';
+$txt['xcache_cache'] = 'XCache';
 
 $txt['loadavg_warning'] = '<span class="error">Please note: the settings below are to be edited with care. Setting any of them too low may render your forum <strong>unusable</strong>! The current load average is <strong>%01.2f</strong></span>';
 $txt['loadavg_enable'] = 'Enable load balancing by load averages';

+ 26 - 6
other/Settings.php

@@ -114,7 +114,32 @@ $db_persist = 0;
  * 
  * @var int|bool
  */
-$db_error_send = 1;
+$db_error_send = 0;
+
+########## Cache Info ##########
+/**
+ * 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, smf, or xcache 
+ * (you can add more with a mod).
+ * @var string
+ */
+$cache_accelerator = '';
+/**
+ * The level at which you would like to cache. Between 0 (off) through 3 (cache a lot).
+ * @var int
+ */
+$cache_enable = 0;
+/**
+ * This is only used for memcache / memcached. Should be a string of 'server:port,server:port'
+ * @var array
+ */
+$cache_memcached = '';
+/**
+ * This is only for the 'smf' file 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
+ */
+$cachedir = dirname(__FILE__) . '/cache';
 
 ########## Directories/Files ##########
 # Note: These directories do not have to be changed unless you move things.
@@ -128,11 +153,6 @@ $boarddir = dirname(__FILE__);
  * @var string
  */
 $sourcedir = dirname(__FILE__) . '/Sources';
-/**
- * Path to the cache directory.
- * @var string
- */
-$cachedir = dirname(__FILE__) . '/cache';
 
 ########## Error-Catching ##########
 # Note: You shouldn't touch these settings.