Completed
Pull Request — release-2.1 (#4069)
by Jeremy
08:39
created

ManageServer.php ➔ ModifyGeneralSettings()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 69
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 35
nc 4
nop 1
dl 0
loc 69
rs 8.56
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Contains all the functionality required to be able to edit the core server
5
 * settings. This includes anything from which an error may result in the forum
6
 * destroying itself in a firey fury.
7
 *
8
 * Adding options to one of the setting screens isn't hard. Call prepareDBSettingsContext;
9
 * The basic format for a checkbox is:
10
 * 		array('check', 'nameInModSettingsAndSQL'),
11
 * And for a text box:
12
 * 		array('text', 'nameInModSettingsAndSQL')
13
 * (NOTE: You have to add an entry for this at the bottom!)
14
 *
15
 * In these cases, it will look for $txt['nameInModSettingsAndSQL'] as the description,
16
 * and $helptxt['nameInModSettingsAndSQL'] as the help popup description.
17
 *
18
 * Here's a quick explanation of how to add a new item:
19
 *
20
 * - A text input box.  For textual values.
21
 * 		array('text', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
22
 * - A text input box.  For numerical values.
23
 * 		array('int', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
24
 * - A text input box.  For floating point values.
25
 * 		array('float', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
26
 * - A large text input box. Used for textual values spanning multiple lines.
27
 * 		array('large_text', 'nameInModSettingsAndSQL', 'OptionalNumberOfRows'),
28
 * - A check box.  Either one or zero. (boolean)
29
 * 		array('check', 'nameInModSettingsAndSQL'),
30
 * - A selection box.  Used for the selection of something from a list.
31
 * 		array('select', 'nameInModSettingsAndSQL', array('valueForSQL' => $txt['displayedValue'])),
32
 * 		Note that just saying array('first', 'second') will put 0 in the SQL for 'first'.
33
 * - A password input box. Used for passwords, no less!
34
 * 		array('password', 'nameInModSettingsAndSQL', 'OptionalInputBoxWidth'),
35
 * - A permission - for picking groups who have a permission.
36
 * 		array('permissions', 'manage_groups'),
37
 * - A BBC selection box.
38
 * 		array('bbc', 'sig_bbc'),
39
 * - A list of boards to choose from
40
 *  	array('boards', 'likes_boards'),
41
 *  	Note that the storage in the database is as 1,2,3,4
42
 *
43
 * For each option:
44
 * 	- type (see above), variable name, size/possible values.
45
 * 	  OR make type '' for an empty string for a horizontal rule.
46
 *  - SET preinput - to put some HTML prior to the input box.
47
 *  - SET postinput - to put some HTML following the input box.
48
 *  - SET invalid - to mark the data as invalid.
49
 *  - PLUS you can override label and help parameters by forcing their keys in the array, for example:
50
 *  	array('text', 'invalidlabel', 3, 'label' => 'Actual Label')
51
 *
52
 * Simple Machines Forum (SMF)
53
 *
54
 * @package SMF
55
 * @author Simple Machines http://www.simplemachines.org
56
 * @copyright 2017 Simple Machines and individual contributors
57
 * @license http://www.simplemachines.org/about/smf/license.php BSD
58
 *
59
 * @version 2.1 Beta 3
60
 */
61
62
if (!defined('SMF'))
63
	die('No direct access...');
64
65
/**
66
 * This is the main dispatcher. Sets up all the available sub-actions, all the tabs and selects
67
 * the appropriate one based on the sub-action.
68
 *
69
 * Requires the admin_forum permission.
70
 * Redirects to the appropriate function based on the sub-action.
71
 *
72
 * @uses edit_settings adminIndex.
73
 */
74
function ModifySettings()
75
{
76
	global $context, $txt, $boarddir;
77
78
	// This is just to keep the database password more secure.
79
	isAllowedTo('admin_forum');
80
81
	// Load up all the tabs...
82
	$context[$context['admin_menu_name']]['tab_data'] = array(
83
		'title' => $txt['admin_server_settings'],
84
		'help' => 'serversettings',
85
		'description' => $txt['admin_basic_settings'],
86
	);
87
88
	checkSession('request');
89
90
	// The settings are in here, I swear!
91
	loadLanguage('ManageSettings');
92
93
	$context['page_title'] = $txt['admin_server_settings'];
94
	$context['sub_template'] = 'show_settings';
95
96
	$subActions = array(
97
		'general' => 'ModifyGeneralSettings',
98
		'database' => 'ModifyDatabaseSettings',
99
		'cookie' => 'ModifyCookieSettings',
100
		'security' => 'ModifyGeneralSecuritySettings',
101
		'cache' => 'ModifyCacheSettings',
102
		'loads' => 'ModifyLoadBalancingSettings',
103
		'phpinfo' => 'ShowPHPinfoSettings',
104
	);
105
106
	// By default we're editing the core settings
107
	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'general';
108
	$context['sub_action'] = $_REQUEST['sa'];
109
110
	// Warn the user if there's any relevant information regarding Settings.php.
111
	$settings_not_writable = !is_writable($boarddir . '/Settings.php');
112
	$settings_backup_fail = !@is_writable($boarddir . '/Settings_bak.php') || !@copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
113
114 View Code Duplication
	if ($settings_not_writable)
115
		$context['settings_message'] = '<div class="centertext"><strong>' . $txt['settings_not_writable'] . '</strong></div><br>';
116
	elseif ($settings_backup_fail)
117
		$context['settings_message'] = '<div class="centertext"><strong>' . $txt['admin_backup_fail'] . '</strong></div><br>';
118
119
	$context['settings_not_writable'] = $settings_not_writable;
120
121
	call_integration_hook('integrate_server_settings', array(&$subActions));
122
123
	// Call the right function for this sub-action.
124
	call_helper($subActions[$_REQUEST['sa']]);
125
}
126
127
/**
128
 * General forum settings - forum name, maintenance mode, etc.
129
 * Practically, this shows an interface for the settings in Settings.php to be changed.
130
 *
131
 * - Requires the admin_forum permission.
132
 * - Uses the edit_settings administration area.
133
 * - Contains the actual array of settings to show from Settings.php.
134
 * - Accessed from ?action=admin;area=serversettings;sa=general.
135
 *
136
 * @param bool $return_config Whether to return the $config_vars array (for pagination purposes)
137
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
138
 */
139
function ModifyGeneralSettings($return_config = false)
140
{
141
	global $scripturl, $context, $txt;
142
143
	/* If you're writing a mod, it's a bad idea to add things here....
144
	For each option:
145
		variable name, description, type (constant), size/possible values, helptext, optional 'min' (minimum value for float/int, defaults to 0), optional 'max' (maximum value for float/int), optional 'step' (amount to increment/decrement value for float/int)
146
	OR	an empty string for a horizontal rule.
147
	OR	a string for a titled section. */
148
	$config_vars = array(
149
		array('mbname', $txt['admin_title'], 'file', 'text', 30),
150
		'',
151
		array('maintenance', $txt['admin_maintain'], 'file', 'check'),
152
		array('mtitle', $txt['maintenance_subject'], 'file', 'text', 36),
153
		array('mmessage', $txt['maintenance_message'], 'file', 'text', 36),
154
		'',
155
		array('webmaster_email', $txt['admin_webmaster_email'], 'file', 'text', 30),
156
		'',
157
		array('enableCompressedOutput', $txt['enableCompressedOutput'], 'db', 'check', null, 'enableCompressedOutput'),
158
		array('disableTemplateEval', $txt['disableTemplateEval'], 'db', 'check', null, 'disableTemplateEval'),
159
		array('disableHostnameLookup', $txt['disableHostnameLookup'], 'db', 'check', null, 'disableHostnameLookup'),
160
		'',
161
		array('force_ssl', $txt['force_ssl'], 'db', 'select', array($txt['force_ssl_off'], $txt['force_ssl_auth'], $txt['force_ssl_complete']), 'force_ssl'),
162
		array('image_proxy_enabled', $txt['image_proxy_enabled'], 'file', 'check', null, 'image_proxy_enabled'),
163
		array('image_proxy_secret', $txt['image_proxy_secret'], 'file', 'text', 30, 'image_proxy_secret'),
164
		array('image_proxy_maxsize', $txt['image_proxy_maxsize'], 'file', 'int', null, 'image_proxy_maxsize'),
165
		'',
166
		array('enable_sm_stats', $txt['sm_state_setting'], 'db', 'check', null, 'enable_sm_stats'),
167
	);
168
169
	call_integration_hook('integrate_general_settings', array(&$config_vars));
170
171
	if ($return_config)
172
		return $config_vars;
173
174
	// Setup the template stuff.
175
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=general;save';
176
	$context['settings_title'] = $txt['general_settings'];
177
178
	// Saving settings?
179
	if (isset($_REQUEST['save']))
180
	{
181
		call_integration_hook('integrate_save_general_settings');
182
183
		// Are we saving the stat collection?
184
		if (!empty($_POST['enable_sm_stats']) && empty($modSettings['sm_stats_key']))
0 ignored issues
show
Bug introduced by
The variable $modSettings seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
185
			registerSMStats();
186
187
		saveSettings($config_vars);
188
		$_SESSION['adm-save'] = true;
189
		redirectexit('action=admin;area=serversettings;sa=general;' . $context['session_var'] . '=' . $context['session_id']);
190
	}
191
192
	// Fill the config array.
193
	prepareServerSettingsContext($config_vars);
194
195
	// Some javascript for SSL
196
	addInlineJavaScript('
197
$(function()
198
{
199
	$("#force_ssl").change(function()
200
	{
201
		var mode = $(this).val() == 2 ? false : true;
202
		$("#image_proxy_enabled").prop("disabled", mode);
203
		$("#image_proxy_secret").prop("disabled", mode);
204
		$("#image_proxy_maxsize").prop("disabled", mode);
205
	}).change();
206
});');
207
}
208
209
/**
210
 * Basic database and paths settings - database name, host, etc.
211
 *
212
 * - It shows an interface for the settings in Settings.php to be changed.
213
 * - It contains the actual array of settings to show from Settings.php.
214
 * - Requires the admin_forum permission.
215
 * - Uses the edit_settings administration area.
216
 * - Accessed from ?action=admin;area=serversettings;sa=database.
217
 *
218
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
219
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
220
 */
221
function ModifyDatabaseSettings($return_config = false)
222
{
223
	global $scripturl, $context, $txt;
224
225
	/* If you're writing a mod, it's a bad idea to add things here....
226
		For each option:
227
		variable name, description, type (constant), size/possible values, helptext, optional 'min' (minimum value for float/int, defaults to 0), optional 'max' (maximum value for float/int), optional 'step' (amount to increment/decrement value for float/int)
228
		OR an empty string for a horizontal rule.
229
		OR a string for a titled section. */
230
	$config_vars = array(
231
		array('db_persist', $txt['db_persist'], 'file', 'check', null, 'db_persist'),
232
		array('db_error_send', $txt['db_error_send'], 'file', 'check'),
233
		array('ssi_db_user', $txt['ssi_db_user'], 'file', 'text', null, 'ssi_db_user'),
234
		array('ssi_db_passwd', $txt['ssi_db_passwd'], 'file', 'password'),
235
		'',
236
		array('autoFixDatabase', $txt['autoFixDatabase'], 'db', 'check', false, 'autoFixDatabase')
237
	);
238
239
	call_integration_hook('integrate_database_settings', array(&$config_vars));
240
241
	if ($return_config)
242
		return $config_vars;
243
244
	// Setup the template stuff.
245
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=database;save';
246
	$context['settings_title'] = $txt['database_settings'];
247
	$context['save_disabled'] = $context['settings_not_writable'];
248
249
	// Saving settings?
250
	if (isset($_REQUEST['save']))
251
	{
252
		call_integration_hook('integrate_save_database_settings');
253
254
		saveSettings($config_vars);
255
		$_SESSION['adm-save'] = true;
256
		redirectexit('action=admin;area=serversettings;sa=database;' . $context['session_var'] . '=' . $context['session_id']);
257
	}
258
259
	// Fill the config array.
260
	prepareServerSettingsContext($config_vars);
261
}
262
263
/**
264
 * This function handles cookies settings modifications.
265
 *
266
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
267
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
268
 */
269
function ModifyCookieSettings($return_config = false)
270
{
271
	global $context, $scripturl, $txt, $sourcedir, $modSettings, $cookiename, $user_settings, $boardurl, $smcFunc;
272
273
	// Define the variables we want to edit.
274
	$config_vars = array(
275
		// Cookies...
276
		array('cookiename', $txt['cookie_name'], 'file', 'text', 20),
277
		array('cookieTime', $txt['cookieTime'], 'db', 'int', 'postinput' => $txt['minutes']),
278
		array('localCookies', $txt['localCookies'], 'db', 'check', false, 'localCookies'),
279
		array('globalCookies', $txt['globalCookies'], 'db', 'check', false, 'globalCookies'),
280
		array('globalCookiesDomain', $txt['globalCookiesDomain'], 'db', 'text', false, 'globalCookiesDomain'),
281
		array('secureCookies', $txt['secureCookies'], 'db', 'check', false, 'secureCookies', 'disabled' => !isset($_SERVER['HTTPS']) || !(strtolower($_SERVER['HTTPS']) == 'on' || strtolower($_SERVER['HTTPS']) == '1')),
282
		array('httponlyCookies', $txt['httponlyCookies'], 'db', 'check', false, 'httponlyCookies'),
283
		'',
284
		// Sessions
285
		array('databaseSession_enable', $txt['databaseSession_enable'], 'db', 'check', false, 'databaseSession_enable'),
286
		array('databaseSession_loose', $txt['databaseSession_loose'], 'db', 'check', false, 'databaseSession_loose'),
287
		array('databaseSession_lifetime', $txt['databaseSession_lifetime'], 'db', 'int', false, 'databaseSession_lifetime', 'postinput' => $txt['seconds']),
288
		'',
289
		// 2FA
290
		array('tfa_mode', $txt['tfa_mode'], 'db', 'select', array(
291
			0 => $txt['tfa_mode_disabled'],
292
			1 => $txt['tfa_mode_enabled'],
293
		) + (empty($user_settings['tfa_secret']) ? array() : array(
294
			2 => $txt['tfa_mode_forced'],
295
		)) + (empty($user_settings['tfa_secret']) ? array() : array(
296
			3 => $txt['tfa_mode_forcedall'],
297
		)), 'subtext' => $txt['tfa_mode_subtext'] . (empty($user_settings['tfa_secret']) ? '<br /><strong>' . $txt['tfa_mode_forced_help'] . '</strong>' : ''), 'tfa_mode'),
298
	);
299
300
	addInlineJavaScript('
301
	function hideGlobalCookies()
302
	{
303
		var usingLocal = $("#localCookies").prop("checked");
304
		$("#setting_globalCookies").closest("dt").toggle(!usingLocal);
305
		$("#globalCookies").closest("dd").toggle(!usingLocal);
306
307
		var usingGlobal = !usingLocal && $("#globalCookies").prop("checked");
308
		$("#setting_globalCookiesDomain").closest("dt").toggle(usingGlobal);
309
		$("#globalCookiesDomain").closest("dd").toggle(usingGlobal);
310
	};
311
	hideGlobalCookies();
312
313
	$("#localCookies, #globalCookies").click(function() {
314
		hideGlobalCookies();
315
	});', true);
316
317
	if (empty($user_settings['tfa_secret']))
318
		addInlineJavaScript('');
319
320
	call_integration_hook('integrate_cookie_settings', array(&$config_vars));
321
322
	if ($return_config)
323
		return $config_vars;
324
325
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=cookie;save';
326
	$context['settings_title'] = $txt['cookies_sessions_settings'];
327
328
	// Saving settings?
329
	if (isset($_REQUEST['save']))
330
	{
331
		call_integration_hook('integrate_save_cookie_settings');
332
333
		// Local and global do not play nicely together.
334
		if (!empty($_POST['localCookies']) && empty($_POST['globalCookies']))
335
			unset ($_POST['globalCookies']);
336
337
		if (!empty($_POST['globalCookiesDomain']) && strpos($boardurl, $_POST['globalCookiesDomain']) === false)
338
			fatal_lang_error('invalid_cookie_domain', false);
339
340
		saveSettings($config_vars);
341
342
		// If the cookie name was changed, reset the cookie.
343
		if ($cookiename != $_POST['cookiename'])
344
		{
345
			$original_session_id = $context['session_id'];
346
			include_once($sourcedir . '/Subs-Auth.php');
347
348
			// Remove the old cookie.
349
			setLoginCookie(-3600, 0);
350
351
			// Set the new one.
352
			$cookiename = $_POST['cookiename'];
353
			setLoginCookie(60 * $modSettings['cookieTime'], $user_settings['id_member'], hash_salt($user_settings['passwd'], $user_settings['password_salt']));
354
355
			redirectexit('action=admin;area=serversettings;sa=cookie;' . $context['session_var'] . '=' . $original_session_id, $context['server']['needs_login_fix']);
356
		}
357
358
		//If we disabled 2FA, reset all members and membergroups settings.
359
		if (isset($_POST['tfa_mode']) && empty($_POST['tfa_mode']))
360
		{
361
			$smcFunc['db_query']('', '
362
				UPDATE {db_prefix}membergroups
363
				SET tfa_required = {int:zero}',
364
				array(
365
					'zero' => 0,
366
				)
367
			);
368
			$smcFunc['db_query']('', '
369
				UPDATE {db_prefix}members
370
				SET tfa_secret = {string:empty}, tfa_backup = {string:empty}',
371
				array(
372
					'empty' => '',
373
				)
374
			);
375
		}
376
377
		$_SESSION['adm-save'] = true;
378
		redirectexit('action=admin;area=serversettings;sa=cookie;' . $context['session_var'] . '=' . $context['session_id']);
379
	}
380
381
	// Fill the config array.
382
	prepareServerSettingsContext($config_vars);
383
}
384
385
/**
386
 * Settings really associated with general security aspects.
387
 *
388
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
389
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
390
 */
391
function ModifyGeneralSecuritySettings($return_config = false)
392
{
393
	global $txt, $scripturl, $context;
394
395
	$config_vars = array(
396
			array('int', 'failed_login_threshold'),
397
			array('int', 'loginHistoryDays', 'subtext' => $txt['zero_to_disable']),
398
		'',
399
			array('check', 'securityDisable'),
400
			array('check', 'securityDisable_moderate'),
401
		'',
402
			// Reactive on email, and approve on delete
403
			array('check', 'send_validation_onChange'),
404
			array('check', 'approveAccountDeletion'),
405
		'',
406
			// Password strength.
407
			array('select', 'password_strength', array($txt['setting_password_strength_low'], $txt['setting_password_strength_medium'], $txt['setting_password_strength_high'])),
408
			array('check', 'enable_password_conversion'),
409
		'',
410
			// Reporting of personal messages?
411
			array('check', 'enableReportPM'),
412
		'',
413
			array('select', 'frame_security', array('SAMEORIGIN' => $txt['setting_frame_security_SAMEORIGIN'], 'DENY' => $txt['setting_frame_security_DENY'], 'DISABLE' => $txt['setting_frame_security_DISABLE'])),
414
		'',
415
			array('select', 'proxy_ip_header', array('disabled' => $txt['setting_proxy_ip_header_disabled'], 'autodetect' => $txt['setting_proxy_ip_header_autodetect'], 'HTTP_X_FORWARDED_FOR' => 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP' => 'HTTP_CLIENT_IP', 'HTTP_X_REAL_IP' => 'HTTP_X_REAL_IP', 'CF-Connecting-IP' => 'CF-Connecting-IP')),
416
			array('text', 'proxy_ip_servers'),
417
	);
418
419
	call_integration_hook('integrate_general_security_settings', array(&$config_vars));
420
421
	if ($return_config)
422
		return $config_vars;
423
424
	// Saving?
425 View Code Duplication
	if (isset($_GET['save']))
426
	{
427
		saveDBSettings($config_vars);
428
		$_SESSION['adm-save'] = true;
429
430
		call_integration_hook('integrate_save_general_security_settings');
431
432
		writeLog();
433
		redirectexit('action=admin;area=serversettings;sa=security;' . $context['session_var'] . '=' . $context['session_id']);
434
	}
435
436
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;save;sa=security';
437
	$context['settings_title'] = $txt['security_settings'];
438
439
	prepareDBSettingContext($config_vars);
440
}
441
442
/**
443
 * Simply modifying cache functions
444
 *
445
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
446
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
447
 */
448
function ModifyCacheSettings($return_config = false)
449
{
450
	global $context, $scripturl, $txt, $cacheAPI;
451
452
	// Detect all available optimizers
453
	$detected = loadCacheAPIs();
454
455
	// set our values to show what, if anything, we found
456
	if (empty($detected))
457
	{
458
		$txt['cache_settings_message'] = $txt['detected_no_caching'];
459
		$cache_level = array($txt['cache_off']);
460
		$detected['none'] = $txt['cache_off'];
461
	}
462
	else
463
	{
464
		$txt['cache_settings_message'] = sprintf($txt['detected_accelerators'], implode(', ', $detected));
465
		$cache_level = array($txt['cache_off'], $txt['cache_level1'], $txt['cache_level2'], $txt['cache_level3']);
466
	}
467
468
	// Define the variables we want to edit.
469
	$config_vars = array(
470
		// Only a few settings, but they are important
471
		array('', $txt['cache_settings_message'], '', 'desc'),
472
		array('cache_enable', $txt['cache_enable'], 'file', 'select', $cache_level, 'cache_enable'),
473
		array('cache_accelerator', $txt['cache_accelerator'], 'file', 'select', $detected),
474
	);
475
476
	// some javascript to enable / disable certain settings if the option is not selected
477
	$context['settings_post_javascript'] = '
478
		$(document).ready(function() {
479
			$("#cache_accelerator").change();
480
		});';
481
482
	call_integration_hook('integrate_modify_cache_settings', array(&$config_vars));
483
484
	// Maybe we have some additional settings from the selected accelerator.
485
	if (!empty($detected))
486
	{
487
		foreach ($detected as $tryCache => $dummy)
488
		{
489
			$cache_class_name = $tryCache . '_cache';
490
491
			// loadCacheAPIs has already included the file, just see if we can't add the settings in.
492
			if (is_callable(array($cache_class_name, 'cacheSettings')))
493
			{
494
				$testAPI = new $cache_class_name();
495
				call_user_func_array(array($testAPI, 'cacheSettings'), array(&$config_vars));
496
			}
497
		}
498
	}
499
	if ($return_config)
500
		return $config_vars;
501
502
	// Saving again?
503 View Code Duplication
	if (isset($_GET['save']))
504
	{
505
		call_integration_hook('integrate_save_cache_settings');
506
507
		saveSettings($config_vars);
508
		$_SESSION['adm-save'] = true;
509
510
		// We need to save the $cache_enable to $modSettings as well
511
		updatesettings(array('cache_enable' => (int) $_POST['cache_enable']));
512
513
		// exit so we reload our new settings on the page
514
		redirectexit('action=admin;area=serversettings;sa=cache;' . $context['session_var'] . '=' . $context['session_id']);
515
	}
516
517
	loadLanguage('ManageMaintenance');
518
	createToken('admin-maint');
519
	$context['template_layers'][] = 'clean_cache_button';
520
521
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=cache;save';
522
	$context['settings_title'] = $txt['caching_settings'];
523
524
	// Changing cache settings won't have any effect if Settings.php is not writeable.
525
	$context['save_disabled'] = $context['settings_not_writable'];
526
527
	// Decide what message to show.
528
	if (!$context['save_disabled'])
529
		$context['settings_message'] = $txt['caching_information'];
530
531
	// Prepare the template.
532
	prepareServerSettingsContext($config_vars);
533
}
534
535
/**
536
 * Allows to edit load balancing settings.
537
 *
538
 * @param bool $return_config Whether or not to return the config_vars array
539
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
540
 */
541
function ModifyLoadBalancingSettings($return_config = false)
542
{
543
	global $txt, $scripturl, $context, $modSettings;
544
545
	// Setup a warning message, but disabled by default.
546
	$disabled = true;
547
	$context['settings_message'] = $txt['loadavg_disabled_conf'];
548
549
	if (stripos(PHP_OS, 'win') === 0)
550
	{
551
		$context['settings_message'] = $txt['loadavg_disabled_windows'];
552
		if (isset($_GET['save']))
553
			$_SESSION['adm-save'] = $txt['loadavg_disabled_windows'];
554
	}
555
	elseif (stripos(PHP_OS, 'darwin') === 0)
556
	{
557
		$context['settings_message'] = $txt['loadavg_disabled_osx'];
558
		if (isset($_GET['save']))
559
			$_SESSION['adm-save'] = $txt['loadavg_disabled_osx'];
560
	}
561
	else
562
	{
563
		$modSettings['load_average'] = @file_get_contents('/proc/loadavg');
564
		if (!empty($modSettings['load_average']) && preg_match('~^([^ ]+?) ([^ ]+?) ([^ ]+)~', $modSettings['load_average'], $matches) !== 0)
565
			$modSettings['load_average'] = (float) $matches[1];
566 View Code Duplication
		elseif (($modSettings['load_average'] = @`uptime`) !== null && preg_match('~load averages?: (\d+\.\d+), (\d+\.\d+), (\d+\.\d+)~i', $modSettings['load_average'], $matches) !== 0)
567
			$modSettings['load_average'] = (float) $matches[1];
568
		else
569
			unset($modSettings['load_average']);
570
571
		if (!empty($modSettings['load_average']) || $modSettings['load_average'] === 0.0)
572
		{
573
			$context['settings_message'] = sprintf($txt['loadavg_warning'], $modSettings['load_average']);
574
			$disabled = false;
575
		}
576
	}
577
578
	// Start with a simple checkbox.
579
	$config_vars = array(
580
		array('check', 'loadavg_enable', 'disabled' => $disabled),
581
	);
582
583
	// Set the default values for each option.
584
	$default_values = array(
585
		'loadavg_auto_opt' => 1.0,
586
		'loadavg_search' => 2.5,
587
		'loadavg_allunread' => 2.0,
588
		'loadavg_unreadreplies' => 3.5,
589
		'loadavg_show_posts' => 2.0,
590
		'loadavg_userstats' => 10.0,
591
		'loadavg_bbc' => 30.0,
592
		'loadavg_forum' => 40.0,
593
	);
594
595
	// Loop through the settings.
596
	foreach ($default_values as $name => $value)
597
	{
598
		// Use the default value if the setting isn't set yet.
599
		$value = !isset($modSettings[$name]) ? $value : $modSettings[$name];
600
		$config_vars[] = array('float', $name, 'value' => $value, 'disabled' => $disabled);
601
	}
602
603
	call_integration_hook('integrate_loadavg_settings', array(&$config_vars));
604
605
	if ($return_config)
606
		return $config_vars;
607
608
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=loads;save';
609
	$context['settings_title'] = $txt['load_balancing_settings'];
610
611
	// Saving?
612
	if (isset($_GET['save']))
613
	{
614
		// Stupidity is not allowed.
615
		foreach ($_POST as $key => $value)
616
		{
617
			if (strpos($key, 'loadavg') === 0 || $key === 'loadavg_enable' || !in_array($key, array_keys($default_values)))
618
				continue;
619
			else
620
				$_POST[$key] = (float) $value;
621
622
			if ($key == 'loadavg_auto_opt' && $value <= 1)
623
				$_POST['loadavg_auto_opt'] = 1.0;
624
			elseif ($key == 'loadavg_forum' && $value < 10)
625
				$_POST['loadavg_forum'] = 10.0;
626
			elseif ($value < 2)
627
				$_POST[$key] = 2.0;
628
		}
629
630
		call_integration_hook('integrate_save_loadavg_settings');
631
632
		saveDBSettings($config_vars);
633
		if (!isset($_SESSION['adm-save']))
634
			$_SESSION['adm-save'] = true;
635
		redirectexit('action=admin;area=serversettings;sa=loads;' . $context['session_var'] . '=' . $context['session_id']);
636
	}
637
638
	prepareDBSettingContext($config_vars);
639
}
640
641
/**
642
 * Helper function, it sets up the context for the manage server settings.
643
 * - The basic usage of the six numbered key fields are
644
 * - array (0 ,1, 2, 3, 4, 5
645
 *		0 variable name - the name of the saved variable
646
 *		1 label - the text to show on the settings page
647
 *		2 saveto - file or db, where to save the variable name - value pair
648
 *		3 type - type of data to save, int, float, text, check
649
 *		4 size - false or field size
650
 *		5 help - '' or helptxt variable name
651
 *	)
652
 *
653
 * the following named keys are also permitted
654
 * 'disabled' => A string of code that will determine whether or not the setting should be disabled
655
 * 'postinput' => Text to display after the input field
656
 * 'preinput' => Text to display before the input field
657
 * 'subtext' => Additional descriptive text to display under the field's label
658
 * 'min' => minimum allowed value (for int/float). Defaults to 0 if not set.
659
 * 'max' => maximum allowed value (for int/float)
660
 * 'step' => how much to increment/decrement the value by (only for int/float - mostly used for float values).
661
 *
662
 * @param array $config_vars An array of configuration variables
663
 */
664
function prepareServerSettingsContext(&$config_vars)
665
{
666
	global $context, $modSettings, $smcFunc;
667
668 View Code Duplication
	if (isset($_SESSION['adm-save']))
669
	{
670
		if ($_SESSION['adm-save'] === true)
671
			$context['saved_successful'] = true;
672
		else
673
			$context['saved_failed'] = $_SESSION['adm-save'];
674
675
		unset($_SESSION['adm-save']);
676
	}
677
678
	$context['config_vars'] = array();
679
	foreach ($config_vars as $identifier => $config_var)
680
	{
681
		if (!is_array($config_var) || !isset($config_var[1]))
682
			$context['config_vars'][] = $config_var;
683
		else
684
		{
685
			$varname = $config_var[0];
686
			global $$varname;
687
688
			// Set the subtext in case it's part of the label.
689
			// @todo Temporary. Preventing divs inside label tags.
690
			$divPos = strpos($config_var[1], '<div');
691
			$subtext = '';
692
			if ($divPos !== false)
693
			{
694
				$subtext = preg_replace('~</?div[^>]*>~', '', substr($config_var[1], $divPos));
695
				$config_var[1] = substr($config_var[1], 0, $divPos);
696
			}
697
698
			$context['config_vars'][$config_var[0]] = array(
699
				'label' => $config_var[1],
700
				'help' => isset($config_var[5]) ? $config_var[5] : '',
701
				'type' => $config_var[3],
702
				'size' => empty($config_var[4]) ? 0 : $config_var[4],
703
				'data' => isset($config_var[4]) && is_array($config_var[4]) && $config_var[3] != 'select' ? $config_var[4] : array(),
704
				'name' => $config_var[0],
705
				'value' => $config_var[2] == 'file' ? $smcFunc['htmlspecialchars']($$varname) : (isset($modSettings[$config_var[0]]) ? $smcFunc['htmlspecialchars']($modSettings[$config_var[0]]) : (in_array($config_var[3], array('int', 'float')) ? 0 : '')),
706
				'disabled' => !empty($context['settings_not_writable']) || !empty($config_var['disabled']),
707
				'invalid' => false,
708
				'subtext' => !empty($config_var['subtext']) ? $config_var['subtext'] : $subtext,
709
				'javascript' => '',
710
				'preinput' => !empty($config_var['preinput']) ? $config_var['preinput'] : '',
711
				'postinput' => !empty($config_var['postinput']) ? $config_var['postinput'] : '',
712
			);
713
714
			// Handle min/max/step if necessary
715 View Code Duplication
			if ($config_var[3] == 'int' || $config_var[3] == 'float')
716
			{
717
				// Default to a min of 0 if one isn't set
718
				if (isset($config_var['min']))
719
					$context['config_vars'][$config_var[0]]['min'] = $config_var['min'];
720
				else
721
					$context['config_vars'][$config_var[0]]['min'] = 0;
722
723
				if (isset($config_var['max']))
724
					$context['config_vars'][$config_var[0]]['max'] = $config_var['max'];
725
726
				if (isset($config_var['step']))
727
					$context['config_vars'][$config_var[0]]['step'] = $config_var['step'];
728
			}
729
730
			// If this is a select box handle any data.
731
			if (!empty($config_var[4]) && is_array($config_var[4]))
732
			{
733
				// If it's associative
734
				$config_values = array_values($config_var[4]);
735 View Code Duplication
				if (isset($config_values[0]) && is_array($config_values[0]))
736
					$context['config_vars'][$config_var[0]]['data'] = $config_var[4];
737
				else
738
				{
739
					foreach ($config_var[4] as $key => $item)
740
						$context['config_vars'][$config_var[0]]['data'][] = array($key, $item);
741
				}
742
			}
743
		}
744
	}
745
746
	// Two tokens because saving these settings requires both saveSettings and saveDBSettings
747
	createToken('admin-ssc');
748
	createToken('admin-dbsc');
749
}
750
751
/**
752
 * Helper function, it sets up the context for database settings.
753
 * @todo see rev. 10406 from 2.1-requests
754
 *
755
 * @param array $config_vars An array of configuration variables
756
 */
757
function prepareDBSettingContext(&$config_vars)
758
{
759
	global $txt, $helptxt, $context, $modSettings, $sourcedir, $smcFunc;
760
761
	loadLanguage('Help');
762
763 View Code Duplication
	if (isset($_SESSION['adm-save']))
764
	{
765
		if ($_SESSION['adm-save'] === true)
766
			$context['saved_successful'] = true;
767
		else
768
			$context['saved_failed'] = $_SESSION['adm-save'];
769
770
		unset($_SESSION['adm-save']);
771
	}
772
773
	$context['config_vars'] = array();
774
	$inlinePermissions = array();
775
	$bbcChoice = array();
776
	$board_list = false;
777
	foreach ($config_vars as $config_var)
778
	{
779
		// HR?
780
		if (!is_array($config_var))
781
			$context['config_vars'][] = $config_var;
782
		else
783
		{
784
			// If it has no name it doesn't have any purpose!
785
			if (empty($config_var[1]))
786
				continue;
787
788
			// Special case for inline permissions
789
			if ($config_var[0] == 'permissions' && allowedTo('manage_permissions'))
790
				$inlinePermissions[] = $config_var[1];
791
			elseif ($config_var[0] == 'permissions')
792
				continue;
793
794
			if ($config_var[0] == 'boards')
795
				$board_list = true;
796
797
			// Are we showing the BBC selection box?
798
			if ($config_var[0] == 'bbc')
799
				$bbcChoice[] = $config_var[1];
800
801
			// We need to do some parsing of the value before we pass it in.
802
			if (isset($modSettings[$config_var[1]]))
803
			{
804
				switch ($config_var[0])
805
				{
806
					case 'select':
807
						$value = $modSettings[$config_var[1]];
808
						break;
809
					case 'json':
810
						$value = $smcFunc['htmlspecialchars'](json_encode($modSettings[$config_var[1]]));
811
						break;
812
					case 'boards':
813
						$value = explode(',', $modSettings[$config_var[1]]);
814
						break;
815
					default:
816
						$value = $smcFunc['htmlspecialchars']($modSettings[$config_var[1]]);
817
				}
818
			}
819
			else
820
			{
821
				// Darn, it's empty. What type is expected?
822
				switch ($config_var[0])
823
				{
824
					case 'int':
825
					case 'float':
826
						$value = 0;
827
						break;
828
					case 'select':
829
						$value = !empty($config_var['multiple']) ? json_encode(array()) : '';
830
						break;
831
					case 'boards':
832
						$value = array();
833
						break;
834
					default:
835
						$value = '';
836
				}
837
			}
838
839
			$context['config_vars'][$config_var[1]] = array(
840
				'label' => isset($config_var['text_label']) ? $config_var['text_label'] : (isset($txt[$config_var[1]]) ? $txt[$config_var[1]] : (isset($config_var[3]) && !is_array($config_var[3]) ? $config_var[3] : '')),
841
				'help' => isset($helptxt[$config_var[1]]) ? $config_var[1] : '',
842
				'type' => $config_var[0],
843
				'size' => !empty($config_var['size']) ? $config_var['size'] : (!empty($config_var[2]) && !is_array($config_var[2]) ? $config_var[2] : (in_array($config_var[0], array('int', 'float')) ? 6 : 0)),
844
				'data' => array(),
845
				'name' => $config_var[1],
846
				'value' => $value,
847
				'disabled' => false,
848
				'invalid' => !empty($config_var['invalid']),
849
				'javascript' => '',
850
				'var_message' => !empty($config_var['message']) && isset($txt[$config_var['message']]) ? $txt[$config_var['message']] : '',
851
				'preinput' => isset($config_var['preinput']) ? $config_var['preinput'] : '',
852
				'postinput' => isset($config_var['postinput']) ? $config_var['postinput'] : '',
853
			);
854
855
			// Handle min/max/step if necessary
856 View Code Duplication
			if ($config_var[0] == 'int' || $config_var[0] == 'float')
857
			{
858
				// Default to a min of 0 if one isn't set
859
				if (isset($config_var['min']))
860
					$context['config_vars'][$config_var[1]]['min'] = $config_var['min'];
861
				else
862
					$context['config_vars'][$config_var[1]]['min'] = 0;
863
864
				if (isset($config_var['max']))
865
					$context['config_vars'][$config_var[1]]['max'] = $config_var['max'];
866
867
				if (isset($config_var['step']))
868
					$context['config_vars'][$config_var[1]]['step'] = $config_var['step'];
869
			}
870
871
			// If this is a select box handle any data.
872
			if (!empty($config_var[2]) && is_array($config_var[2]))
873
			{
874
				// If we allow multiple selections, we need to adjust a few things.
875
				if ($config_var[0] == 'select' && !empty($config_var['multiple']))
876
				{
877
					$context['config_vars'][$config_var[1]]['name'] .= '[]';
878
					$context['config_vars'][$config_var[1]]['value'] = !empty($context['config_vars'][$config_var[1]]['value']) ? smf_json_decode($context['config_vars'][$config_var[1]]['value'], true) : array();
879
				}
880
881
				// If it's associative
882 View Code Duplication
				if (isset($config_var[2][0]) && is_array($config_var[2][0]))
883
					$context['config_vars'][$config_var[1]]['data'] = $config_var[2];
884
				else
885
				{
886
					foreach ($config_var[2] as $key => $item)
887
						$context['config_vars'][$config_var[1]]['data'][] = array($key, $item);
888
				}
889
			}
890
891
			// Finally allow overrides - and some final cleanups.
892
			foreach ($config_var as $k => $v)
893
			{
894
				if (!is_numeric($k))
895
				{
896
					if (substr($k, 0, 2) == 'on')
897
						$context['config_vars'][$config_var[1]]['javascript'] .= ' ' . $k . '="' . $v . '"';
898
					else
899
						$context['config_vars'][$config_var[1]][$k] = $v;
900
				}
901
902
				// See if there are any other labels that might fit?
903
				if (isset($txt['setting_' . $config_var[1]]))
904
					$context['config_vars'][$config_var[1]]['label'] = $txt['setting_' . $config_var[1]];
905
				elseif (isset($txt['groups_' . $config_var[1]]))
906
					$context['config_vars'][$config_var[1]]['label'] = $txt['groups_' . $config_var[1]];
907
			}
908
909
			// Set the subtext in case it's part of the label.
910
			// @todo Temporary. Preventing divs inside label tags.
911
			$divPos = strpos($context['config_vars'][$config_var[1]]['label'], '<div');
912
			if ($divPos !== false)
913
			{
914
				$context['config_vars'][$config_var[1]]['subtext'] = preg_replace('~</?div[^>]*>~', '', substr($context['config_vars'][$config_var[1]]['label'], $divPos));
915
				$context['config_vars'][$config_var[1]]['label'] = substr($context['config_vars'][$config_var[1]]['label'], 0, $divPos);
916
			}
917
		}
918
	}
919
920
	// If we have inline permissions we need to prep them.
921
	if (!empty($inlinePermissions) && allowedTo('manage_permissions'))
922
	{
923
		require_once($sourcedir . '/ManagePermissions.php');
924
		init_inline_permissions($inlinePermissions, isset($context['permissions_excluded']) ? $context['permissions_excluded'] : array());
925
	}
926
927
	if ($board_list)
928
	{
929
		require_once($sourcedir . '/Subs-MessageIndex.php');
930
		$context['board_list'] = getBoardList();
931
	}
932
933
	// What about any BBC selection boxes?
934
	if (!empty($bbcChoice))
935
	{
936
		// What are the options, eh?
937
		$temp = parse_bbc(false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
938
		$bbcTags = array();
939
		foreach ($temp as $tag)
0 ignored issues
show
Bug introduced by
The expression $temp of type string is not traversable.
Loading history...
940
			$bbcTags[] = $tag['tag'];
941
942
		$bbcTags = array_unique($bbcTags);
943
		$totalTags = count($bbcTags);
944
945
		// The number of columns we want to show the BBC tags in.
946
		$numColumns = isset($context['num_bbc_columns']) ? $context['num_bbc_columns'] : 3;
947
948
		// Start working out the context stuff.
949
		$context['bbc_columns'] = array();
950
		$tagsPerColumn = ceil($totalTags / $numColumns);
951
952
		$col = 0; $i = 0;
953
		foreach ($bbcTags as $tag)
954
		{
955
			if ($i % $tagsPerColumn == 0 && $i != 0)
956
				$col++;
957
958
			$context['bbc_columns'][$col][] = array(
959
				'tag' => $tag,
960
				// @todo  'tag_' . ?
961
				'show_help' => isset($helptxt[$tag]),
962
			);
963
964
			$i++;
965
		}
966
967
		// Now put whatever BBC options we may have into context too!
968
		$context['bbc_sections'] = array();
969
		foreach ($bbcChoice as $bbc)
970
		{
971
			$context['bbc_sections'][$bbc] = array(
972
				'title' => isset($txt['bbc_title_' . $bbc]) ? $txt['bbc_title_' . $bbc] : $txt['bbcTagsToUse_select'],
973
				'disabled' => empty($modSettings['bbc_disabled_' . $bbc]) ? array() : $modSettings['bbc_disabled_' . $bbc],
974
				'all_selected' => empty($modSettings['bbc_disabled_' . $bbc]),
975
			);
976
		}
977
	}
978
979
	call_integration_hook('integrate_prepare_db_settings', array(&$config_vars));
980
	createToken('admin-dbsc');
981
}
982
983
/**
984
 * Helper function. Saves settings by putting them in Settings.php or saving them in the settings table.
985
 *
986
 * - Saves those settings set from ?action=admin;area=serversettings.
987
 * - Requires the admin_forum permission.
988
 * - Contains arrays of the types of data to save into Settings.php.
989
 *
990
 * @param $config_vars An array of configuration variables
991
 */
992
function saveSettings(&$config_vars)
993
{
994
	global $sourcedir, $context;
995
996
	validateToken('admin-ssc');
997
998
	// Fix the darn stupid cookiename! (more may not be allowed, but these for sure!)
999
	if (isset($_POST['cookiename']))
1000
		$_POST['cookiename'] = preg_replace('~[,;\s\.$]+~' . ($context['utf8'] ? 'u' : ''), '', $_POST['cookiename']);
1001
1002
	// Fix the forum's URL if necessary.
1003
	if (isset($_POST['boardurl']))
1004
	{
1005 View Code Duplication
		if (substr($_POST['boardurl'], -10) == '/index.php')
1006
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
1007
		elseif (substr($_POST['boardurl'], -1) == '/')
1008
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
1009 View Code Duplication
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
1010
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
1011
	}
1012
1013
	// Any passwords?
1014
	$config_passwords = array(
1015
		'db_passwd',
1016
		'ssi_db_passwd',
1017
	);
1018
1019
	// All the strings to write.
1020
	$config_strs = array(
1021
		'mtitle', 'mmessage',
1022
		'language', 'mbname', 'boardurl',
1023
		'cookiename',
1024
		'webmaster_email',
1025
		'db_name', 'db_user', 'db_server', 'db_prefix', 'ssi_db_user',
1026
		'boarddir', 'sourcedir',
1027
		'cachedir', 'cachedir_sqlite', 'cache_accelerator', 'cache_memcached',
1028
		'image_proxy_secret',
1029
	);
1030
1031
	// All the numeric variables.
1032
	$config_ints = array(
1033
		'cache_enable',
1034
		'image_proxy_maxsize',
1035
	);
1036
1037
	// All the checkboxes
1038
	$config_bools = array('db_persist', 'db_error_send', 'maintenance', 'image_proxy_enabled');
1039
1040
	// Now sort everything into a big array, and figure out arrays and etc.
1041
	$new_settings = array();
1042
	// Figure out which config vars we're saving here...
1043
	foreach ($config_vars as $var)
1044
	{
1045
		if (!is_array($var) || $var[2] != 'file' || (!in_array($var[0], $config_bools) && !isset($_POST[$var[0]])))
1046
			continue;
1047
1048
		$config_var = $var[0];
1049
1050
		if (in_array($config_var, $config_passwords))
1051
		{
1052
			if (isset($_POST[$config_var][1]) && $_POST[$config_var][0] == $_POST[$config_var][1])
1053
				$new_settings[$config_var] = '\'' . addcslashes($_POST[$config_var][0], '\'\\') . '\'';
1054
		}
1055
		elseif (in_array($config_var, $config_strs))
1056
		{
1057
			$new_settings[$config_var] = '\'' . addcslashes($_POST[$config_var], '\'\\') . '\'';
1058
		}
1059
		elseif (in_array($config_var, $config_ints))
1060
		{
1061
			$new_settings[$config_var] = (int) $_POST[$config_var];
1062
1063
			// If no min is specified, assume 0. This is done to avoid having to specify 'min => 0' for all settings where 0 is the min...
1064
			$min = isset($var['min']) ? $var['min'] : 0;
1065
			$new_settings[$config_var] = max($min, $new_settings[$config_var]);
1066
1067
			// Is there a max value for this as well?
1068
			if (isset($var['max']))
1069
				$new_settings[$config_var] = min($var['max'], $new_settings[$config_var]);
1070
		}
1071
		elseif (in_array($config_var, $config_bools))
1072
		{
1073
			if (!empty($_POST[$config_var]))
1074
				$new_settings[$config_var] = '1';
1075
			else
1076
				$new_settings[$config_var] = '0';
1077
		}
1078
		else
1079
		{
1080
			// This shouldn't happen, but it might...
1081
			fatal_error('Unknown config_var \'' . $config_var . '\'');
1082
		}
1083
	}
1084
1085
	// Save the relevant settings in the Settings.php file.
1086
	require_once($sourcedir . '/Subs-Admin.php');
1087
	updateSettingsFile($new_settings);
1088
1089
	// Now loop through the remaining (database-based) settings.
1090
	$new_settings = array();
1091
	foreach ($config_vars as $config_var)
1092
	{
1093
		// We just saved the file-based settings, so skip their definitions.
1094
		if (!is_array($config_var) || $config_var[2] == 'file')
1095
			continue;
1096
1097
		$new_setting = array($config_var[3], $config_var[0]);
1098
1099
		// Select options need carried over, too.
1100
		if (isset($config_var[4]))
1101
			$new_setting[] = $config_var[4];
1102
1103
		// Include min and max if necessary
1104
		if (isset($config_var['min']))
1105
			$new_setting['min'] = $config_var['min'];
1106
1107
		if (isset($config_var['max']))
1108
			$new_setting['max'] = $config_var['max'];
1109
1110
		// Rewrite the definition a bit.
1111
		$new_settings[] = $new_setting;
1112
	}
1113
1114
	// Save the new database-based settings, if any.
1115
	if (!empty($new_settings))
1116
		saveDBSettings($new_settings);
1117
}
1118
1119
/**
1120
 * Helper function for saving database settings.
1121
 * @todo see rev. 10406 from 2.1-requests
1122
 *
1123
 * @param array $config_vars An array of configuration variables
1124
 */
1125
function saveDBSettings(&$config_vars)
1126
{
1127
	global $sourcedir, $smcFunc;
1128
	static $board_list = null;
1129
1130
	validateToken('admin-dbsc');
1131
1132
	$inlinePermissions = array();
1133
	foreach ($config_vars as $var)
1134
	{
1135
		if (!isset($var[1]) || (!isset($_POST[$var[1]]) && $var[0] != 'check' && $var[0] != 'permissions' && $var[0] != 'boards' && ($var[0] != 'bbc' || !isset($_POST[$var[1] . '_enabledTags']))))
1136
			continue;
1137
1138
		// Checkboxes!
1139
		elseif ($var[0] == 'check')
1140
			$setArray[$var[1]] = !empty($_POST[$var[1]]) ? '1' : '0';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$setArray was never initialized. Although not strictly required by PHP, it is generally a good practice to add $setArray = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1141
		// Select boxes!
1142
		elseif ($var[0] == 'select' && in_array($_POST[$var[1]], array_keys($var[2])))
1143
			$setArray[$var[1]] = $_POST[$var[1]];
0 ignored issues
show
Bug introduced by
The variable $setArray does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1144
		elseif ($var[0] == 'select' && !empty($var['multiple']) && array_intersect($_POST[$var[1]], array_keys($var[2])) != array())
1145
		{
1146
			// For security purposes we validate this line by line.
1147
			$lOptions = array();
1148
			foreach ($_POST[$var[1]] as $invar)
1149
				if (in_array($invar, array_keys($var[2])))
1150
					$lOptions[] = $invar;
1151
1152
			$setArray[$var[1]] = json_encode($lOptions);
1153
		}
1154
		// List of boards!
1155
		elseif ($var[0] == 'boards')
1156
		{
1157
			// We just need a simple list of valid boards, nothing more.
1158
			if ($board_list === null)
1159
			{
1160
				$board_list = array();
1161
				$request = $smcFunc['db_query']('', '
1162
					SELECT id_board
1163
					FROM {db_prefix}boards');
1164
				while ($row = $smcFunc['db_fetch_row']($request))
1165
					$board_list[$row[0]] = true;
1166
1167
				$smcFunc['db_free_result']($request);
1168
			}
1169
1170
			$lOptions = array();
1171
1172
			if (!empty($_POST[$var[1]]))
1173
				foreach ($_POST[$var[1]] as $invar => $dummy)
1174
					if (isset($board_list[$invar]))
1175
						$lOptions[] = $invar;
1176
1177
			$setArray[$var[1]] = !empty($lOptions) ? implode(',', $lOptions) : '';
1178
		}
1179
		// Integers!
1180 View Code Duplication
		elseif ($var[0] == 'int')
1181
		{
1182
			$setArray[$var[1]] = (int) $_POST[$var[1]];
1183
1184
			// If no min is specified, assume 0. This is done to avoid having to specify 'min => 0' for all settings where 0 is the min...
1185
			$min = isset($var['min']) ? $var['min'] : 0;
1186
			$setArray[$var[1]] = max($min, $setArray[$var[1]]);
1187
1188
			// Do we have a max value for this as well?
1189
			if (isset($var['max']))
1190
				$setArray[$var[1]] = min($var['max'], $setArray[$var[1]]);
1191
		}
1192
		// Floating point!
1193 View Code Duplication
		elseif ($var[0] == 'float')
1194
		{
1195
			$setArray[$var[1]] = (float) $_POST[$var[1]];
1196
1197
			// If no min is specified, assume 0. This is done to avoid having to specify 'min => 0' for all settings where 0 is the min...
1198
			$min = isset($var['min']) ? $var['min'] : 0;
1199
			$setArray[$var[1]] = max($min, $setArray[$var[1]]);
1200
1201
			// Do we have a max value for this as well?
1202
			if (isset($var['max']))
1203
				$setArray[$var[1]] = min($var['max'], $setArray[$var[1]]);
1204
		}
1205
		// Text!
1206
		elseif (in_array($var[0], array('text', 'large_text', 'color', 'date', 'datetime', 'datetime-local', 'email', 'month', 'time')))
1207
			$setArray[$var[1]] = $_POST[$var[1]];
1208
		// Passwords!
1209
		elseif ($var[0] == 'password')
1210
		{
1211
			if (isset($_POST[$var[1]][1]) && $_POST[$var[1]][0] == $_POST[$var[1]][1])
1212
				$setArray[$var[1]] = $_POST[$var[1]][0];
1213
		}
1214
		// BBC.
1215
		elseif ($var[0] == 'bbc')
1216
		{
1217
1218
			$bbcTags = array();
1219
			foreach (parse_bbc(false) as $tag)
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
The expression parse_bbc(false) of type string is not traversable.
Loading history...
1220
				$bbcTags[] = $tag['tag'];
1221
1222
			if (!isset($_POST[$var[1] . '_enabledTags']))
1223
				$_POST[$var[1] . '_enabledTags'] = array();
1224
			elseif (!is_array($_POST[$var[1] . '_enabledTags']))
1225
				$_POST[$var[1] . '_enabledTags'] = array($_POST[$var[1] . '_enabledTags']);
1226
1227
			$setArray[$var[1]] = implode(',', array_diff($bbcTags, $_POST[$var[1] . '_enabledTags']));
1228
		}
1229
		// Permissions?
1230
		elseif ($var[0] == 'permissions')
1231
			$inlinePermissions[] = $var[1];
1232
	}
1233
1234
	if (!empty($setArray))
1235
		updateSettings($setArray);
1236
1237
	// If we have inline permissions we need to save them.
1238
	if (!empty($inlinePermissions) && allowedTo('manage_permissions'))
1239
	{
1240
		require_once($sourcedir . '/ManagePermissions.php');
1241
		save_inline_permissions($inlinePermissions);
1242
	}
1243
}
1244
1245
/**
1246
 * Allows us to see the servers php settings
1247
 *
1248
 * - loads the settings into an array for display in a template
1249
 * - drops cookie values just in case
1250
 */
1251
function ShowPHPinfoSettings()
1252
{
1253
	global $context, $txt;
1254
1255
	$category = $txt['phpinfo_settings'];
1256
1257
	// get the data
1258
	ob_start();
1259
	phpinfo();
1260
1261
	// We only want it for its body, pigs that we are
1262
	$info_lines = preg_replace('~^.*<body>(.*)</body>.*$~', '$1', ob_get_contents());
1263
	$info_lines = explode("\n", strip_tags($info_lines, "<tr><td><h2>"));
1264
	ob_end_clean();
1265
1266
	// remove things that could be considered sensitive
1267
	$remove = '_COOKIE|Cookie|_GET|_REQUEST|REQUEST_URI|QUERY_STRING|REQUEST_URL|HTTP_REFERER';
1268
1269
	// put all of it into an array
1270
	foreach ($info_lines as $line)
1271
	{
1272
		if (preg_match('~(' . $remove . ')~', $line))
1273
			continue;
1274
1275
		// new category?
1276
		if (strpos($line, '<h2>') !== false)
1277
			$category = preg_match('~<h2>(.*)</h2>~', $line, $title) ? $category = $title[1] : $category;
1278
1279
		// load it as setting => value or the old setting local master
1280
		if (preg_match('~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~', $line, $val))
1281
			$pinfo[$category][$val[1]] = $val[2];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$pinfo was never initialized. Although not strictly required by PHP, it is generally a good practice to add $pinfo = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1282
		elseif (preg_match('~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~', $line, $val))
1283
			$pinfo[$category][$val[1]] = array($txt['phpinfo_localsettings'] => $val[2], $txt['phpinfo_defaultsettings'] => $val[3]);
0 ignored issues
show
Bug introduced by
The variable $pinfo does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1284
	}
1285
1286
	// load it in to context and display it
1287
	$context['pinfo'] = $pinfo;
1288
	$context['page_title'] = $txt['admin_server_settings'];
1289
	$context['sub_template'] = 'php_info';
1290
	return;
1291
}
1292
1293
/**
1294
 * Get the installed Cache API implementations.
1295
 *
1296
 */
1297
function loadCacheAPIs()
1298
{
1299
	global $sourcedir, $txt;
1300
1301
	// Make sure our class is in session.
1302
	require_once($sourcedir . '/Class-CacheAPI.php');
1303
1304
	$apis = array();
1305
	if ($dh = opendir($sourcedir))
1306
	{
1307
		while (($file = readdir($dh)) !== false)
1308
		{
1309
			if (is_file($sourcedir . '/' . $file) && preg_match('~^CacheAPI-([A-Za-z\d_]+)\.php$~', $file, $matches))
1310
			{
1311
				$tryCache = strtolower($matches[1]);
1312
1313
				require_once($sourcedir . '/' . $file);
1314
				$cache_class_name = $tryCache . '_cache';
1315
				$testAPI = new $cache_class_name();
1316
1317
				// No Support?  NEXT!
1318
				if (!$testAPI->isSupported(true))
1319
					continue;
1320
1321
				$apis[$tryCache] = isset($txt[$tryCache . '_cache']) ? $txt[$tryCache . '_cache'] : $tryCache;
1322
			}
1323
		}
1324
	}
1325
	closedir($dh);
1326
1327
	return $apis;
1328
}
1329
1330
/**
1331
 * Registers the site with the Simple Machines Stat collection. This function 
1332
 * purposely does not use updateSettings.php as it will be called shortly after
1333
 * this process completes by the saveSettings() function.
1334
 *
1335
 * @see Stats.php SMStats() for more information.
1336
 * @link https://www.simplemachines.org/about/stats.php for more info.
1337
 *
1338
 */
1339
function registerSMStats()
1340
{
1341
	global $modSettings, $boardurl, $smcFunc;
1342
1343
	// Already have a key?  Can't register again.
1344
	if (!empty($modSettings['sm_stats_key']))
1345
		return true;
1346
1347
	$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
1348
	if ($fp)
1349
	{
1350
		$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
1351
		$out .= 'Host: www.simplemachines.org' . "\r\n";
1352
		$out .= 'Connection: Close' . "\r\n\r\n";
1353
		fwrite($fp, $out);
1354
1355
		$return_data = '';
1356
		while (!feof($fp))
1357
			$return_data .= fgets($fp, 128);
1358
1359
		fclose($fp);
1360
1361
		// Get the unique site ID.
1362
		preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1363
1364
		if (!empty($ID[1]))
1365
			$smcFunc['db_insert']('replace',
1366
				'{db_prefix}settings',
1367
				array('variable' => 'string', 'value' => 'string'),
1368
				array('sm_stats_key', $ID[1]),
1369
				array('variable')
1370
			);
1371
	}
1372
}
1373
1374
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...