Passed
Push — release-2.1 ( 450280...54b854 )
by Mathias
07:46 queued 12s
created

ModifyCacheSettings()   C

Complexity

Conditions 13
Paths 84

Size

Total Lines 95
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 44
c 1
b 0
f 0
nc 84
nop 1
dl 0
loc 95
rs 6.6166

How to fix   Long Method    Complexity   

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 https://www.simplemachines.org
56
 * @copyright 2022 Simple Machines and individual contributors
57
 * @license https://www.simplemachines.org/about/smf/license.php BSD
58
 *
59
 * @version 2.1 RC4
60
 */
61
62
use SMF\Cache\CacheApi;
63
use SMF\Cache\CacheApiInterface;
64
65
if (!defined('SMF'))
66
	die('No direct access...');
67
68
/**
69
 * This is the main dispatcher. Sets up all the available sub-actions, all the tabs and selects
70
 * the appropriate one based on the sub-action.
71
 *
72
 * Requires the admin_forum permission.
73
 * Redirects to the appropriate function based on the sub-action.
74
 *
75
 * Uses edit_settings adminIndex.
76
 */
77
function ModifySettings()
78
{
79
	global $context, $txt, $boarddir;
80
81
	// This is just to keep the database password more secure.
82
	isAllowedTo('admin_forum');
83
84
	// Load up all the tabs...
85
	$context[$context['admin_menu_name']]['tab_data'] = array(
86
		'title' => $txt['admin_server_settings'],
87
		'help' => 'serversettings',
88
		'description' => $txt['admin_basic_settings'],
89
	);
90
91
	checkSession('request');
92
93
	// The settings are in here, I swear!
94
	loadLanguage('ManageSettings');
95
96
	$context['page_title'] = $txt['admin_server_settings'];
97
	$context['sub_template'] = 'show_settings';
98
99
	$subActions = array(
100
		'general' => 'ModifyGeneralSettings',
101
		'database' => 'ModifyDatabaseSettings',
102
		'cookie' => 'ModifyCookieSettings',
103
		'security' => 'ModifyGeneralSecuritySettings',
104
		'cache' => 'ModifyCacheSettings',
105
		'export' => 'ModifyExportSettings',
106
		'loads' => 'ModifyLoadBalancingSettings',
107
		'phpinfo' => 'ShowPHPinfoSettings',
108
	);
109
110
	// By default we're editing the core settings
111
	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'general';
112
	$context['sub_action'] = $_REQUEST['sa'];
113
114
	// Warn the user if there's any relevant information regarding Settings.php.
115
	$settings_not_writable = !is_writable($boarddir . '/Settings.php');
116
	$settings_backup_fail = !@is_writable($boarddir . '/Settings_bak.php') || !@copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
117
118
	if ($settings_not_writable)
119
		$context['settings_message'] = array(
120
			'label' => $txt['settings_not_writable'],
121
			'tag' => 'div',
122
			'class' => 'centertext strong'
123
		);
124
	elseif ($settings_backup_fail)
125
		$context['settings_message'] = array(
126
			'label' => $txt['admin_backup_fail'],
127
			'tag' => 'div',
128
			'class' => 'centertext strong'
129
		);
130
131
	$context['settings_not_writable'] = $settings_not_writable;
132
133
	call_integration_hook('integrate_server_settings', array(&$subActions));
134
135
	// Call the right function for this sub-action.
136
	call_helper($subActions[$_REQUEST['sa']]);
137
}
138
139
/**
140
 * General forum settings - forum name, maintenance mode, etc.
141
 * Practically, this shows an interface for the settings in Settings.php to be changed.
142
 *
143
 * - Requires the admin_forum permission.
144
 * - Uses the edit_settings administration area.
145
 * - Contains the actual array of settings to show from Settings.php.
146
 * - Accessed from ?action=admin;area=serversettings;sa=general.
147
 *
148
 * @param bool $return_config Whether to return the $config_vars array (for pagination purposes)
149
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
150
 */
151
function ModifyGeneralSettings($return_config = false)
152
{
153
	global $scripturl, $context, $txt, $modSettings, $boardurl, $sourcedir, $smcFunc;
154
155
	// If no cert, force_ssl must remain 0
156
	require_once($sourcedir . '/Subs.php');
157
	if (!ssl_cert_found($boardurl) && empty($modSettings['force_ssl']))
158
		$disable_force_ssl = true;
159
	else
160
		$disable_force_ssl = false;
161
162
	/* If you're writing a mod, it's a bad idea to add things here....
163
	For each option:
164
		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)
165
	OR	an empty string for a horizontal rule.
166
	OR	a string for a titled section. */
167
	$config_vars = array(
168
		array('mbname', $txt['admin_title'], 'file', 'text', 30),
169
		'',
170
		array('maintenance', $txt['admin_maintain'], 'file', 'check'),
171
		array('mtitle', $txt['maintenance_subject'], 'file', 'text', 36),
172
		array('mmessage', $txt['maintenance_message'], 'file', 'text', 36),
173
		'',
174
		array('webmaster_email', $txt['admin_webmaster_email'], 'file', 'text', 30),
175
		'',
176
		array('enableCompressedOutput', $txt['enableCompressedOutput'], 'db', 'check', null, 'enableCompressedOutput'),
177
		array('disableHostnameLookup', $txt['disableHostnameLookup'], 'db', 'check', null, 'disableHostnameLookup'),
178
		'',
179
		array('force_ssl', $txt['force_ssl'], 'db', 'select', array($txt['force_ssl_off'], $txt['force_ssl_complete']), 'force_ssl', 'disabled' => $disable_force_ssl),
180
		array('image_proxy_enabled', $txt['image_proxy_enabled'], 'file', 'check', null, 'image_proxy_enabled'),
181
		array('image_proxy_secret', $txt['image_proxy_secret'], 'file', 'text', 30, 'image_proxy_secret'),
182
		array('image_proxy_maxsize', $txt['image_proxy_maxsize'], 'file', 'int', null, 'image_proxy_maxsize'),
183
		'',
184
		array('enable_sm_stats', $txt['enable_sm_stats'], 'db', 'check', null, 'enable_sm_stats'),
185
	);
186
187
	call_integration_hook('integrate_general_settings', array(&$config_vars));
188
189
	if ($return_config)
190
		return $config_vars;
191
192
	// Setup the template stuff.
193
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=general;save';
194
	$context['settings_title'] = $txt['general_settings'];
195
196
	// Saving settings?
197
	if (isset($_REQUEST['save']))
198
	{
199
		call_integration_hook('integrate_save_general_settings');
200
201
		foreach ($config_vars as $config_var)
202
		{
203
			if (is_array($config_var) && isset($config_var[3]) && $config_var[3] == 'text' && !empty($_POST[$config_var[0]]))
204
				$_POST[$config_var[0]] = $smcFunc['normalize']($_POST[$config_var[0]]);
205
		}
206
207
		// Are we saving the stat collection?
208
		if (!empty($_POST['enable_sm_stats']) && empty($modSettings['sm_stats_key']))
209
		{
210
			$registerSMStats = registerSMStats();
211
212
			// Failed to register, disable it again.
213
			if (empty($registerSMStats))
214
				$_POST['enable_sm_stats'] = 0;
215
		}
216
217
		// Ensure all URLs are aligned with the new force_ssl setting
218
		// Treat unset like 0
219
		if (isset($_POST['force_ssl']))
220
			AlignURLsWithSSLSetting($_POST['force_ssl']);
221
		else
222
			AlignURLsWithSSLSetting(0);
223
224
		saveSettings($config_vars);
225
		$_SESSION['adm-save'] = true;
226
		redirectexit('action=admin;area=serversettings;sa=general;' . $context['session_var'] . '=' . $context['session_id']);
227
	}
228
229
	// Fill the config array.
230
	prepareServerSettingsContext($config_vars);
231
232
	// Some javascript for SSL
233
	addInlineJavaScript('
234
$(function()
235
{
236
	$("#force_ssl").change(function()
237
	{
238
		var mode = $(this).val() == 1 ? false : true;
239
		$("#image_proxy_enabled").prop("disabled", mode);
240
		$("#image_proxy_secret").prop("disabled", mode);
241
		$("#image_proxy_maxsize").prop("disabled", mode);
242
	}).change();
243
});', true);
244
}
245
246
/**
247
 * Align URLs with SSL Setting.
248
 *
249
 * If force_ssl has changed, ensure all URLs are aligned with the new setting.
250
 * This includes:
251
 *     - $boardurl
252
 *     - $modSettings['smileys_url']
253
 *     - $modSettings['avatar_url']
254
 *     - $modSettings['custom_avatar_url'] - if found
255
 *     - theme_url - all entries in the themes table
256
 *     - images_url - all entries in the themes table
257
 *
258
 * This function will NOT overwrite URLs that are not subfolders of $boardurl.
259
 * The admin must have pointed those somewhere else on purpose, so they must be updated manually.
260
 *
261
 * A word of caution: You can't trust the http/https scheme reflected for these URLs in $globals
262
 * (e.g., $boardurl) or in $modSettings.  This is because SMF may change them in memory to comply
263
 * with the force_ssl setting - a soft redirect may be in effect...  Thus, conditional updates
264
 * to these values do not work.  You gotta just brute force overwrite them based on force_ssl.
265
 *
266
 * @param int $new_force_ssl is the current force_ssl setting.
267
 * @return void Returns nothing, just does its job
268
 */
269
function AlignURLsWithSSLSetting($new_force_ssl = 0)
270
{
271
	global $boardurl, $modSettings, $sourcedir, $smcFunc;
272
	require_once($sourcedir . '/Subs-Admin.php');
273
274
	// Check $boardurl
275
	if (!empty($new_force_ssl))
276
		$newval = strtr($boardurl, array('http://' => 'https://'));
277
	else
278
		$newval = strtr($boardurl, array('https://' => 'http://'));
279
	updateSettingsFile(array('boardurl' => $newval));
280
281
	$new_settings = array();
282
283
	// Check $smileys_url, but only if it points to a subfolder of $boardurl
284
	if (BoardurlMatch($modSettings['smileys_url']))
285
	{
286
		if (!empty($new_force_ssl))
287
			$newval = strtr($modSettings['smileys_url'], array('http://' => 'https://'));
288
		else
289
			$newval = strtr($modSettings['smileys_url'], array('https://' => 'http://'));
290
		$new_settings['smileys_url'] = $newval;
291
	}
292
293
	// Check $avatar_url, but only if it points to a subfolder of $boardurl
294
	if (BoardurlMatch($modSettings['avatar_url']))
295
	{
296
		if (!empty($new_force_ssl))
297
			$newval = strtr($modSettings['avatar_url'], array('http://' => 'https://'));
298
		else
299
			$newval = strtr($modSettings['avatar_url'], array('https://' => 'http://'));
300
		$new_settings['avatar_url'] = $newval;
301
	}
302
303
	// Check $custom_avatar_url, but only if it points to a subfolder of $boardurl
304
	// This one had been optional in the past, make sure it is set first
305
	if (isset($modSettings['custom_avatar_url']) && BoardurlMatch($modSettings['custom_avatar_url']))
306
	{
307
		if (!empty($new_force_ssl))
308
			$newval = strtr($modSettings['custom_avatar_url'], array('http://' => 'https://'));
309
		else
310
			$newval = strtr($modSettings['custom_avatar_url'], array('https://' => 'http://'));
311
		$new_settings['custom_avatar_url'] = $newval;
312
	}
313
314
	// Save updates to the settings table
315
	if (!empty($new_settings))
316
		updateSettings($new_settings, true);
317
318
	// Now we move onto the themes.
319
	// First, get a list of theme URLs...
320
	$request = $smcFunc['db_query']('', '
321
		SELECT id_theme, variable, value
322
		FROM {db_prefix}themes
323
		WHERE variable in ({string:themeurl}, {string:imagesurl})
324
			AND id_member = {int:zero}',
325
		array(
326
			'themeurl' => 'theme_url',
327
			'imagesurl' => 'images_url',
328
			'zero' => 0,
329
		)
330
	);
331
332
	while ($row = $smcFunc['db_fetch_assoc']($request))
333
	{
334
		// First check to see if it points to a subfolder of $boardurl
335
		if (BoardurlMatch($row['value']))
336
		{
337
			if (!empty($new_force_ssl))
338
				$newval = strtr($row['value'], array('http://' => 'https://'));
339
			else
340
				$newval = strtr($row['value'], array('https://' => 'http://'));
341
342
			$smcFunc['db_query']('', '
343
				UPDATE {db_prefix}themes
344
				SET value = {string:theme_val}
345
				WHERE variable = {string:theme_var}
346
					AND id_theme = {string:theme_id}
347
					AND id_member = {int:zero}',
348
				array(
349
					'theme_val' => $newval,
350
					'theme_var' => $row['variable'],
351
					'theme_id' => $row['id_theme'],
352
					'zero' => 0,
353
				)
354
			);
355
		}
356
	}
357
	$smcFunc['db_free_result']($request);
358
}
359
360
/**
361
 * $boardurl Match.
362
 *
363
 * Helper function to see if the url being checked is based off of $boardurl.
364
 * If not, it was overridden by the admin to some other value on purpose, and should not
365
 * be stepped on by SMF when aligning URLs with the force_ssl setting.
366
 * The site admin must change URLs that are not aligned with $boardurl manually.
367
 *
368
 * @param string $url is the url to check.
369
 * @return bool Returns true if the url is based off of $boardurl (without the scheme), false if not
370
 */
371
function BoardurlMatch($url = '')
372
{
373
	global $boardurl;
374
375
	// Strip the schemes
376
	$urlpath = strtr($url, array('http://' => '', 'https://' => ''));
377
	$boardurlpath = strtr($boardurl, array('http://' => '', 'https://' => ''));
378
379
	// If leftmost portion of path matches boardurl, return true
380
	$result = strpos($urlpath, $boardurlpath);
381
	if ($result === false || $result != 0)
382
		return false;
383
	else
384
		return true;
385
}
386
387
/**
388
 * Basic database and paths settings - database name, host, etc.
389
 *
390
 * - It shows an interface for the settings in Settings.php to be changed.
391
 * - It contains the actual array of settings to show from Settings.php.
392
 * - Requires the admin_forum permission.
393
 * - Uses the edit_settings administration area.
394
 * - Accessed from ?action=admin;area=serversettings;sa=database.
395
 *
396
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
397
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
398
 */
399
function ModifyDatabaseSettings($return_config = false)
400
{
401
	global $scripturl, $context, $txt, $smcFunc;
402
	db_extend('extra');
403
404
	/* If you're writing a mod, it's a bad idea to add things here....
405
		For each option:
406
		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)
407
		OR an empty string for a horizontal rule.
408
		OR a string for a titled section. */
409
	$config_vars = array(
410
		array('db_persist', $txt['db_persist'], 'file', 'check', null, 'db_persist'),
411
		array('db_error_send', $txt['db_error_send'], 'file', 'check'),
412
		array('ssi_db_user', $txt['ssi_db_user'], 'file', 'text', null, 'ssi_db_user'),
413
		array('ssi_db_passwd', $txt['ssi_db_passwd'], 'file', 'password'),
414
		'',
415
		array('autoFixDatabase', $txt['autoFixDatabase'], 'db', 'check', false, 'autoFixDatabase')
416
	);
417
418
	// Add PG Stuff
419
	if ($smcFunc['db_title'] === POSTGRE_TITLE)
420
	{
421
		$request = $smcFunc['db_query']('', 'SELECT cfgname FROM pg_ts_config', array());
422
		$fts_language = array();
423
424
		while ($row = $smcFunc['db_fetch_assoc']($request))
425
			$fts_language[$row['cfgname']] = $row['cfgname'];
426
427
		$config_vars = array_merge($config_vars, array(
428
				'',
429
				array('search_language', $txt['search_language'], 'db', 'select', $fts_language, 'pgFulltextSearch')
430
			)
431
		);
432
	}
433
434
	call_integration_hook('integrate_database_settings', array(&$config_vars));
435
436
	if ($return_config)
437
		return $config_vars;
438
439
	// Setup the template stuff.
440
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=database;save';
441
	$context['settings_title'] = $txt['database_settings'];
442
	$context['save_disabled'] = $context['settings_not_writable'];
443
444
	if (!$smcFunc['db_allow_persistent']())
445
		addInlineJavaScript('
446
			$(function()
447
			{
448
				$("#db_persist").prop("disabled", true);
449
			});', true);
450
451
	// Saving settings?
452
	if (isset($_REQUEST['save']))
453
	{
454
		call_integration_hook('integrate_save_database_settings');
455
456
		saveSettings($config_vars);
457
		$_SESSION['adm-save'] = true;
458
		redirectexit('action=admin;area=serversettings;sa=database;' . $context['session_var'] . '=' . $context['session_id']);
459
	}
460
461
	// Fill the config array.
462
	prepareServerSettingsContext($config_vars);
463
}
464
465
/**
466
 * This function handles cookies settings modifications.
467
 *
468
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
469
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
470
 */
471
function ModifyCookieSettings($return_config = false)
472
{
473
	global $context, $scripturl, $txt, $sourcedir, $modSettings, $cookiename, $user_settings, $boardurl, $smcFunc;
474
475
	// Define the variables we want to edit.
476
	$config_vars = array(
477
		// Cookies...
478
		array('cookiename', $txt['cookie_name'], 'file', 'text', 20),
479
		array('cookieTime', $txt['cookieTime'], 'db', 'select', array(
480
			3153600 => $txt['always_logged_in'],
481
			60 => $txt['one_hour'],
482
			1440 => $txt['one_day'],
483
			10080 => $txt['one_week'],
484
			43200 => $txt['one_month'],
485
		)),
486
		array('localCookies', $txt['localCookies'], 'db', 'check', false, 'localCookies'),
487
		array('globalCookies', $txt['globalCookies'], 'db', 'check', false, 'globalCookies'),
488
		array('globalCookiesDomain', $txt['globalCookiesDomain'], 'db', 'text', false, 'globalCookiesDomain'),
489
		array('secureCookies', $txt['secureCookies'], 'db', 'check', false, 'secureCookies', 'disabled' => !httpsOn()),
490
		array('httponlyCookies', $txt['httponlyCookies'], 'db', 'check', false, 'httponlyCookies'),
491
		'',
492
		// Sessions
493
		array('databaseSession_enable', $txt['databaseSession_enable'], 'db', 'check', false, 'databaseSession_enable'),
494
		array('databaseSession_loose', $txt['databaseSession_loose'], 'db', 'check', false, 'databaseSession_loose'),
495
		array('databaseSession_lifetime', $txt['databaseSession_lifetime'], 'db', 'int', false, 'databaseSession_lifetime', 'postinput' => $txt['seconds']),
496
		'',
497
		// 2FA
498
		array('tfa_mode', $txt['tfa_mode'], 'db', 'select', array(
499
			0 => $txt['tfa_mode_disabled'],
500
			1 => $txt['tfa_mode_enabled'],
501
		) + (empty($user_settings['tfa_secret']) ? array() : array(
502
			2 => $txt['tfa_mode_forced'],
503
		)) + (empty($user_settings['tfa_secret']) ? array() : array(
504
			3 => $txt['tfa_mode_forcedall'],
505
		)), 'subtext' => $txt['tfa_mode_subtext'] . (empty($user_settings['tfa_secret']) ? '<br><strong>' . $txt['tfa_mode_forced_help'] . '</strong>' : ''), 'tfa_mode'),
506
	);
507
508
	addInlineJavaScript('
509
	function hideGlobalCookies()
510
	{
511
		var usingLocal = $("#localCookies").prop("checked");
512
		$("#setting_globalCookies").closest("dt").toggle(!usingLocal);
513
		$("#globalCookies").closest("dd").toggle(!usingLocal);
514
515
		var usingGlobal = !usingLocal && $("#globalCookies").prop("checked");
516
		$("#setting_globalCookiesDomain").closest("dt").toggle(usingGlobal);
517
		$("#globalCookiesDomain").closest("dd").toggle(usingGlobal);
518
	};
519
	hideGlobalCookies();
520
521
	$("#localCookies, #globalCookies").click(function() {
522
		hideGlobalCookies();
523
	});', true);
524
525
	if (empty($user_settings['tfa_secret']))
526
		addInlineJavaScript('');
527
528
	call_integration_hook('integrate_cookie_settings', array(&$config_vars));
529
530
	if ($return_config)
531
		return $config_vars;
532
533
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=cookie;save';
534
	$context['settings_title'] = $txt['cookies_sessions_settings'];
535
536
	// Saving settings?
537
	if (isset($_REQUEST['save']))
538
	{
539
		call_integration_hook('integrate_save_cookie_settings');
540
541
		$_POST['cookiename'] = $smcFunc['normalize']($_POST['cookiename']);
542
543
		// Local and global do not play nicely together.
544
		if (!empty($_POST['localCookies']) && empty($_POST['globalCookies']))
545
			unset ($_POST['globalCookies']);
546
547
		if (empty($modSettings['localCookies']) != empty($_POST['localCookies']) || empty($modSettings['globalCookies']) != empty($_POST['globalCookies']))
548
			$scope_changed = true;
549
550
		if (!empty($_POST['globalCookiesDomain']))
551
		{
552
			$_POST['globalCookiesDomain'] = parse_iri(normalize_iri((strpos($_POST['globalCookiesDomain'], '//') === false ? 'http://' : '') . ltrim($_POST['globalCookiesDomain'], '.')), PHP_URL_HOST);
553
554
			if (!preg_match('/(?:^|\.)' . preg_quote($_POST['globalCookiesDomain'], '/') . '$/u', parse_iri($boardurl, PHP_URL_HOST)))
555
				fatal_lang_error('invalid_cookie_domain', false);
556
		}
557
558
		saveSettings($config_vars);
559
560
		// If the cookie name or scope were changed, reset the cookie.
561
		if ($cookiename != $_POST['cookiename'] || !empty($scope_changed))
562
		{
563
			$original_session_id = $context['session_id'];
564
			include_once($sourcedir . '/Subs-Auth.php');
565
566
			// Remove the old cookie.
567
			setLoginCookie(-3600, 0);
568
569
			// Set the new one.
570
			$cookiename = !empty($_POST['cookiename']) ? $_POST['cookiename'] : $cookiename;
571
			setLoginCookie(60 * $modSettings['cookieTime'], $user_settings['id_member'], hash_salt($user_settings['passwd'], $user_settings['password_salt']));
572
573
			redirectexit('action=admin;area=serversettings;sa=cookie;' . $context['session_var'] . '=' . $original_session_id, $context['server']['needs_login_fix']);
574
		}
575
576
		//If we disabled 2FA, reset all members and membergroups settings.
577
		if (isset($_POST['tfa_mode']) && empty($_POST['tfa_mode']))
578
		{
579
			$smcFunc['db_query']('', '
580
				UPDATE {db_prefix}membergroups
581
				SET tfa_required = {int:zero}',
582
				array(
583
					'zero' => 0,
584
				)
585
			);
586
			$smcFunc['db_query']('', '
587
				UPDATE {db_prefix}members
588
				SET tfa_secret = {string:empty}, tfa_backup = {string:empty}',
589
				array(
590
					'empty' => '',
591
				)
592
			);
593
		}
594
595
		$_SESSION['adm-save'] = true;
596
		redirectexit('action=admin;area=serversettings;sa=cookie;' . $context['session_var'] . '=' . $context['session_id']);
597
	}
598
599
	// Fill the config array.
600
	prepareServerSettingsContext($config_vars);
601
}
602
603
/**
604
 * Settings really associated with general security aspects.
605
 *
606
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
607
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
608
 */
609
function ModifyGeneralSecuritySettings($return_config = false)
610
{
611
	global $txt, $scripturl, $context;
612
613
	$config_vars = array(
614
		array('int', 'failed_login_threshold'),
615
		array('int', 'loginHistoryDays', 'subtext' => $txt['zero_to_disable']),
616
		'',
617
618
		array('check', 'securityDisable'),
619
		array('check', 'securityDisable_moderate'),
620
		'',
621
622
		// Reactive on email, and approve on delete
623
		array('check', 'send_validation_onChange'),
624
		array('check', 'approveAccountDeletion'),
625
		'',
626
627
		// Password strength.
628
		array(
629
			'select',
630
			'password_strength',
631
			array(
632
				$txt['setting_password_strength_low'],
633
				$txt['setting_password_strength_medium'],
634
				$txt['setting_password_strength_high']
635
			)
636
		),
637
		array('check', 'enable_password_conversion'),
638
		'',
639
640
		// Reporting of personal messages?
641
		array('check', 'enableReportPM'),
642
		'',
643
644
		array('check', 'allow_cors'),
645
		array('check', 'allow_cors_credentials'),
646
		array('text', 'cors_domains'),
647
		array('text', 'cors_headers'),
648
		'',
649
650
		array(
651
			'select',
652
			'frame_security',
653
			array(
654
				'SAMEORIGIN' => $txt['setting_frame_security_SAMEORIGIN'],
655
				'DENY' => $txt['setting_frame_security_DENY'],
656
				'DISABLE' => $txt['setting_frame_security_DISABLE']
657
			)
658
		),
659
		'',
660
661
		array(
662
			'select',
663
			'proxy_ip_header',
664
			array(
665
				'disabled' => $txt['setting_proxy_ip_header_disabled'],
666
				'autodetect' => $txt['setting_proxy_ip_header_autodetect'],
667
				'HTTP_X_FORWARDED_FOR' => 'X-Forwarded-For',
668
				'HTTP_CLIENT_IP' => 'Client-IP',
669
				'HTTP_X_REAL_IP' => 'X-Real-IP',
670
				'HTTP_CF_CONNECTING_IP' => 'CF-Connecting-IP'
671
			)
672
		),
673
		array('text', 'proxy_ip_servers'),
674
	);
675
676
	call_integration_hook('integrate_general_security_settings', array(&$config_vars));
677
678
	if ($return_config)
679
		return $config_vars;
680
681
	// Saving?
682
	if (isset($_GET['save']))
683
	{
684
		if (!empty($_POST['cors_domains']))
685
		{
686
			$cors_domains = explode(',', $_POST['cors_domains']);
687
688
			foreach ($cors_domains as &$cors_domain)
689
			{
690
				if (strpos($cors_domain, '//') === false)
691
					$cors_domain = '//' . $cors_domain;
692
693
				$temp = parse_iri(normalize_iri($cors_domain));
694
695
				if (strpos($temp['host'], '*') !== false)
696
					$temp['host'] = substr($temp['host'], strrpos($temp['host'], '*'));
697
698
				$cors_domain = (!empty($temp['scheme']) ? $temp['scheme'] . '://' : '') . $temp['host'] . (!empty($temp['port']) ? ':' . $temp['port'] : '');
699
			}
700
701
			$_POST['cors_domains'] = implode(',', $cors_domains);
702
		}
703
704
		saveDBSettings($config_vars);
705
		$_SESSION['adm-save'] = true;
706
707
		call_integration_hook('integrate_save_general_security_settings');
708
709
		writeLog();
710
		redirectexit('action=admin;area=serversettings;sa=security;' . $context['session_var'] . '=' . $context['session_id']);
711
	}
712
713
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;save;sa=security';
714
	$context['settings_title'] = $txt['security_settings'];
715
716
	prepareDBSettingContext($config_vars);
717
}
718
719
/**
720
 * Simply modifying cache functions
721
 *
722
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
723
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
724
 */
725
function ModifyCacheSettings($return_config = false)
726
{
727
	global $context, $scripturl, $txt, $cacheAPI, $cache_enable;
728
729
	// Detect all available optimizers
730
	$detectedCacheApis = loadCacheAPIs();
731
	$apis_names = array();
732
733
	/* @var CacheApiInterface $cache_api */
734
	foreach ($detectedCacheApis as $class_name => $cache_api)
735
	{
736
		$class_name_txt_key = strtolower($cache_api->getImplementationClassKeyName());
737
738
		$apis_names[$class_name] = isset($txt[$class_name_txt_key . '_cache']) ?
739
			$txt[$class_name_txt_key . '_cache'] : $class_name;
740
	}
741
742
	// set our values to show what, if anything, we found
743
	if (empty($detectedCacheApis))
744
	{
745
		$txt['cache_settings_message'] = '<strong class="alert">' . $txt['detected_no_caching'] . '</strong>';
746
		$cache_level = array($txt['cache_off']);
747
		$apis_names['none'] = $txt['cache_off'];
748
	}
749
750
	else
751
	{
752
		$txt['cache_settings_message'] = '<strong class="success">' .
753
			sprintf($txt['detected_accelerators'], implode(', ', $apis_names)) . '</strong>';
754
755
		$cache_level = array($txt['cache_off'], $txt['cache_level1'], $txt['cache_level2'], $txt['cache_level3']);
756
	}
757
758
	// Define the variables we want to edit.
759
	$config_vars = array(
760
		// Only a few settings, but they are important
761
		array('', $txt['cache_settings_message'], '', 'desc'),
762
		array('cache_enable', $txt['cache_enable'], 'file', 'select', $cache_level, 'cache_enable'),
763
		array('cache_accelerator', $txt['cache_accelerator'], 'file', 'select', $apis_names),
764
	);
765
766
	// some javascript to enable / disable certain settings if the option is not selected
767
	$context['settings_post_javascript'] = '
768
		$(document).ready(function() {
769
			$("#cache_accelerator").change();
770
		});';
771
772
	call_integration_hook('integrate_modify_cache_settings', array(&$config_vars));
773
774
	// Maybe we have some additional settings from the selected accelerator.
775
	if (!empty($detectedCacheApis))
776
		/* @var CacheApiInterface $cache_api */
777
		foreach ($detectedCacheApis as $class_name_txt_key => $cache_api)
778
			if (is_callable(array($cache_api, 'cacheSettings')))
779
				$cache_api->cacheSettings($config_vars);
780
781
	if ($return_config)
782
		return $config_vars;
783
784
	// Saving again?
785
	if (isset($_GET['save']))
786
	{
787
		call_integration_hook('integrate_save_cache_settings');
788
789
		if (is_callable(array($cacheAPI, 'cleanCache')) && ((int) $_POST['cache_enable'] < $cache_enable || $_POST['cache_accelerator'] != $cache_accelerator))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $cache_accelerator seems to be never defined.
Loading history...
790
		{
791
			$cacheAPI->cleanCache();
792
		}
793
794
		saveSettings($config_vars);
795
		$_SESSION['adm-save'] = true;
796
797
		// We need to save the $cache_enable to $modSettings as well
798
		updatesettings(array('cache_enable' => (int) $_POST['cache_enable']));
799
800
		// exit so we reload our new settings on the page
801
		redirectexit('action=admin;area=serversettings;sa=cache;' . $context['session_var'] . '=' . $context['session_id']);
802
	}
803
804
	loadLanguage('ManageMaintenance');
805
	createToken('admin-maint');
806
	$context['template_layers'][] = 'clean_cache_button';
807
808
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=cache;save';
809
	$context['settings_title'] = $txt['caching_settings'];
810
811
	// Changing cache settings won't have any effect if Settings.php is not writable.
812
	$context['save_disabled'] = $context['settings_not_writable'];
813
814
	// Decide what message to show.
815
	if (!$context['save_disabled'])
816
		$context['settings_message'] = $txt['caching_information'];
817
818
	// Prepare the template.
819
	prepareServerSettingsContext($config_vars);
820
}
821
822
/**
823
 * Controls settings for data export functionality
824
 *
825
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
826
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
827
 */
828
function ModifyExportSettings($return_config = false)
829
{
830
	global $context, $scripturl, $txt, $modSettings, $boarddir, $sourcedir;
831
832
	// Fill in a default value for this if it is missing.
833
	if (empty($modSettings['export_dir']))
834
		$modSettings['export_dir'] = $boarddir . DIRECTORY_SEPARATOR . 'exports';
835
836
	/*
837
		Some paranoid hosts worry that the disk space functions pose a security
838
		risk. Usually these hosts just disable the functions and move on, which
839
		is fine. A rare few, however, are not only paranoid, but also think it'd
840
		be a "clever" security move to overload the disk space functions with
841
		custom code that intentionally delivers false information, which is
842
		idiotic and evil. At any rate, if the functions are unavailable or if
843
		they report obviously insane values, it's not possible to track disk
844
		usage correctly.
845
	 */
846
	$diskspace_disabled = (!function_exists('disk_free_space') || !function_exists('disk_total_space') || intval(@disk_total_space(file_exists($modSettings['export_dir']) ? $modSettings['export_dir'] : $boarddir)) < 1440);
847
848
	$context['settings_message'] = $txt['export_settings_description'];
849
850
	$config_vars = array(
851
		array('text', 'export_dir', 40),
852
		array('int', 'export_expiry', 'subtext' => $txt['zero_to_disable'], 'postinput' => $txt['days_word']),
853
		array('int', 'export_min_diskspace_pct', 'postinput' => '%', 'max' => 80, 'disabled' => $diskspace_disabled),
854
		array('int', 'export_rate', 'min' => 5, 'max' => 500, 'step' => 5, 'subtext' => $txt['export_rate_desc']),
855
	);
856
857
	call_integration_hook('integrate_export_settings', array(&$config_vars));
858
859
	if ($return_config)
860
		return $config_vars;
861
862
	if (isset($_REQUEST['save']))
863
	{
864
		$prev_export_dir = is_dir($modSettings['export_dir']) ? rtrim($modSettings['export_dir'], '/\\') : '';
865
866
		if (!empty($_POST['export_dir']))
867
			$_POST['export_dir'] = rtrim($_POST['export_dir'], '/\\');
868
869
		if ($diskspace_disabled)
870
			$_POST['export_min_diskspace_pct'] = 0;
871
872
		$_POST['export_rate'] = max(5, min($_POST['export_rate'], 500));
873
874
		saveDBSettings($config_vars);
875
876
		// Create the new directory, but revert to the previous one if anything goes wrong.
877
		require_once($sourcedir . '/Profile-Export.php');
878
		create_export_dir($prev_export_dir);
879
880
		// Ensure we don't lose track of any existing export files.
881
		if (!empty($prev_export_dir) && $prev_export_dir != $modSettings['export_dir'])
882
		{
883
			$export_files = glob($prev_export_dir . DIRECTORY_SEPARATOR . '*');
884
885
			foreach ($export_files as $export_file)
886
			{
887
				if (!in_array(basename($export_file), array('index.php', '.htaccess')))
888
				{
889
					rename($export_file, $modSettings['export_dir'] . DIRECTORY_SEPARATOR . basename($export_file));
890
				}
891
			}
892
		}
893
894
		call_integration_hook('integrate_save_export_settings');
895
896
		$_SESSION['adm-save'] = true;
897
		redirectexit('action=admin;area=serversettings;sa=export;' . $context['session_var'] . '=' . $context['session_id']);
898
	}
899
900
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=export;save';
901
	$context['settings_title'] = $txt['export_settings'];
902
903
	prepareDBSettingContext($config_vars);
904
}
905
906
/**
907
 * Allows to edit load balancing settings.
908
 *
909
 * @param bool $return_config Whether or not to return the config_vars array
910
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
911
 */
912
function ModifyLoadBalancingSettings($return_config = false)
913
{
914
	global $txt, $scripturl, $context, $modSettings;
915
916
	// Setup a warning message, but disabled by default.
917
	$disabled = true;
918
	$context['settings_message'] = array('label' => $txt['loadavg_disabled_conf'], 'class' => 'error');
919
920
	if (DIRECTORY_SEPARATOR === '\\')
921
	{
922
		$context['settings_message']['label'] = $txt['loadavg_disabled_windows'];
923
		if (isset($_GET['save']))
924
			$_SESSION['adm-save'] = $context['settings_message']['label'];
925
	}
926
	elseif (stripos(PHP_OS, 'darwin') === 0)
927
	{
928
		$context['settings_message']['label'] = $txt['loadavg_disabled_osx'];
929
		if (isset($_GET['save']))
930
			$_SESSION['adm-save'] = $context['settings_message']['label'];
931
	}
932
	else
933
	{
934
		$modSettings['load_average'] = @file_get_contents('/proc/loadavg');
935
		if (!empty($modSettings['load_average']) && preg_match('~^([^ ]+?) ([^ ]+?) ([^ ]+)~', $modSettings['load_average'], $matches) !== 0)
936
			$modSettings['load_average'] = (float) $matches[1];
937
		elseif (($modSettings['load_average'] = @`uptime`) !== null && preg_match('~load averages?: (\d+\.\d+), (\d+\.\d+), (\d+\.\d+)~i', $modSettings['load_average'], $matches) !== 0)
938
			$modSettings['load_average'] = (float) $matches[1];
939
		else
940
			unset($modSettings['load_average']);
941
942
		if (!empty($modSettings['load_average']) || (isset($modSettings['load_average']) && $modSettings['load_average'] === 0.0))
943
		{
944
			$context['settings_message']['label'] = sprintf($txt['loadavg_warning'], $modSettings['load_average']);
945
			$disabled = false;
946
		}
947
	}
948
949
	// Start with a simple checkbox.
950
	$config_vars = array(
951
		array('check', 'loadavg_enable', 'disabled' => $disabled),
952
	);
953
954
	// Set the default values for each option.
955
	$default_values = array(
956
		'loadavg_auto_opt' => 1.0,
957
		'loadavg_search' => 2.5,
958
		'loadavg_allunread' => 2.0,
959
		'loadavg_unreadreplies' => 3.5,
960
		'loadavg_show_posts' => 2.0,
961
		'loadavg_userstats' => 10.0,
962
		'loadavg_bbc' => 30.0,
963
		'loadavg_forum' => 40.0,
964
	);
965
966
	// Loop through the settings.
967
	foreach ($default_values as $name => $value)
968
	{
969
		// Use the default value if the setting isn't set yet.
970
		$value = !isset($modSettings[$name]) ? $value : $modSettings[$name];
971
		$config_vars[] = array('float', $name, 'value' => $value, 'disabled' => $disabled);
972
	}
973
974
	call_integration_hook('integrate_loadavg_settings', array(&$config_vars));
975
976
	if ($return_config)
977
		return $config_vars;
978
979
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=loads;save';
980
	$context['settings_title'] = $txt['load_balancing_settings'];
981
982
	// Saving?
983
	if (isset($_GET['save']))
984
	{
985
		// Stupidity is not allowed.
986
		foreach ($_POST as $key => $value)
987
		{
988
			if (strpos($key, 'loadavg') === 0 || $key === 'loadavg_enable' || !in_array($key, array_keys($default_values)))
989
				continue;
990
			else
991
				$_POST[$key] = (float) $value;
992
993
			if ($key == 'loadavg_auto_opt' && $value <= 1)
994
				$_POST['loadavg_auto_opt'] = 1.0;
995
			elseif ($key == 'loadavg_forum' && $value < 10)
996
				$_POST['loadavg_forum'] = 10.0;
997
			elseif ($value < 2)
998
				$_POST[$key] = 2.0;
999
		}
1000
1001
		call_integration_hook('integrate_save_loadavg_settings');
1002
1003
		saveDBSettings($config_vars);
1004
		if (!isset($_SESSION['adm-save']))
1005
			$_SESSION['adm-save'] = true;
1006
		redirectexit('action=admin;area=serversettings;sa=loads;' . $context['session_var'] . '=' . $context['session_id']);
1007
	}
1008
1009
	prepareDBSettingContext($config_vars);
1010
}
1011
1012
/**
1013
 * Helper function, it sets up the context for the manage server settings.
1014
 * - The basic usage of the six numbered key fields are
1015
 * - array (0 ,1, 2, 3, 4, 5
1016
 *		0 variable name - the name of the saved variable
1017
 *		1 label - the text to show on the settings page
1018
 *		2 saveto - file or db, where to save the variable name - value pair
1019
 *		3 type - type of data to save, int, float, text, check
1020
 *		4 size - false or field size
1021
 *		5 help - '' or helptxt variable name
1022
 *	)
1023
 *
1024
 * the following named keys are also permitted
1025
 * 'disabled' => A string of code that will determine whether or not the setting should be disabled
1026
 * 'postinput' => Text to display after the input field
1027
 * 'preinput' => Text to display before the input field
1028
 * 'subtext' => Additional descriptive text to display under the field's label
1029
 * 'min' => minimum allowed value (for int/float). Defaults to 0 if not set.
1030
 * 'max' => maximum allowed value (for int/float)
1031
 * 'step' => how much to increment/decrement the value by (only for int/float - mostly used for float values).
1032
 *
1033
 * @param array $config_vars An array of configuration variables
1034
 */
1035
function prepareServerSettingsContext(&$config_vars)
1036
{
1037
	global $context, $modSettings, $smcFunc;
1038
1039
	if (isset($_SESSION['adm-save']))
1040
	{
1041
		if ($_SESSION['adm-save'] === true)
1042
			$context['saved_successful'] = true;
1043
		else
1044
			$context['saved_failed'] = $_SESSION['adm-save'];
1045
1046
		unset($_SESSION['adm-save']);
1047
	}
1048
1049
	$context['config_vars'] = array();
1050
	foreach ($config_vars as $identifier => $config_var)
1051
	{
1052
		if (!is_array($config_var) || !isset($config_var[1]))
1053
			$context['config_vars'][] = $config_var;
1054
		else
1055
		{
1056
			$varname = $config_var[0];
1057
			global $$varname;
1058
1059
			// Set the subtext in case it's part of the label.
1060
			// @todo Temporary. Preventing divs inside label tags.
1061
			$divPos = strpos($config_var[1], '<div');
1062
			$subtext = '';
1063
			if ($divPos !== false)
1064
			{
1065
				$subtext = preg_replace('~</?div[^>]*>~', '', substr($config_var[1], $divPos));
1066
				$config_var[1] = substr($config_var[1], 0, $divPos);
1067
			}
1068
1069
			$context['config_vars'][$config_var[0]] = array(
1070
				'label' => $config_var[1],
1071
				'help' => isset($config_var[5]) ? $config_var[5] : '',
1072
				'type' => $config_var[3],
1073
				'size' => !empty($config_var[4]) && !is_array($config_var[4]) ? $config_var[4] : 0,
1074
				'data' => isset($config_var[4]) && is_array($config_var[4]) && $config_var[3] != 'select' ? $config_var[4] : array(),
1075
				'name' => $config_var[0],
1076
				'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 : '')),
1077
				'disabled' => !empty($context['settings_not_writable']) || !empty($config_var['disabled']),
1078
				'invalid' => false,
1079
				'subtext' => !empty($config_var['subtext']) ? $config_var['subtext'] : $subtext,
1080
				'javascript' => '',
1081
				'preinput' => !empty($config_var['preinput']) ? $config_var['preinput'] : '',
1082
				'postinput' => !empty($config_var['postinput']) ? $config_var['postinput'] : '',
1083
			);
1084
1085
			// Handle min/max/step if necessary
1086
			if ($config_var[3] == 'int' || $config_var[3] == 'float')
1087
			{
1088
				// Default to a min of 0 if one isn't set
1089
				if (isset($config_var['min']))
1090
					$context['config_vars'][$config_var[0]]['min'] = $config_var['min'];
1091
				else
1092
					$context['config_vars'][$config_var[0]]['min'] = 0;
1093
1094
				if (isset($config_var['max']))
1095
					$context['config_vars'][$config_var[0]]['max'] = $config_var['max'];
1096
1097
				if (isset($config_var['step']))
1098
					$context['config_vars'][$config_var[0]]['step'] = $config_var['step'];
1099
			}
1100
1101
			// If this is a select box handle any data.
1102
			if (!empty($config_var[4]) && is_array($config_var[4]))
1103
			{
1104
				// If it's associative
1105
				$config_values = array_values($config_var[4]);
1106
				if (isset($config_values[0]) && is_array($config_values[0]))
1107
					$context['config_vars'][$config_var[0]]['data'] = $config_var[4];
1108
				else
1109
				{
1110
					foreach ($config_var[4] as $key => $item)
1111
						$context['config_vars'][$config_var[0]]['data'][] = array($key, $item);
1112
				}
1113
			}
1114
		}
1115
	}
1116
1117
	// Two tokens because saving these settings requires both saveSettings and saveDBSettings
1118
	createToken('admin-ssc');
1119
	createToken('admin-dbsc');
1120
}
1121
1122
/**
1123
 * Helper function, it sets up the context for database settings.
1124
 *
1125
 * @todo see rev. 10406 from 2.1-requests
1126
 *
1127
 * @param array $config_vars An array of configuration variables
1128
 */
1129
function prepareDBSettingContext(&$config_vars)
1130
{
1131
	global $txt, $helptxt, $context, $modSettings, $sourcedir, $smcFunc;
1132
1133
	loadLanguage('Help');
1134
1135
	if (isset($_SESSION['adm-save']))
1136
	{
1137
		if ($_SESSION['adm-save'] === true)
1138
			$context['saved_successful'] = true;
1139
		else
1140
			$context['saved_failed'] = $_SESSION['adm-save'];
1141
1142
		unset($_SESSION['adm-save']);
1143
	}
1144
1145
	$context['config_vars'] = array();
1146
	$inlinePermissions = array();
1147
	$bbcChoice = array();
1148
	$board_list = false;
1149
	foreach ($config_vars as $config_var)
1150
	{
1151
		// HR?
1152
		if (!is_array($config_var))
1153
			$context['config_vars'][] = $config_var;
1154
		else
1155
		{
1156
			// If it has no name it doesn't have any purpose!
1157
			if (empty($config_var[1]))
1158
				continue;
1159
1160
			// Special case for inline permissions
1161
			if ($config_var[0] == 'permissions' && allowedTo('manage_permissions'))
1162
				$inlinePermissions[] = $config_var[1];
1163
1164
			elseif ($config_var[0] == 'permissions')
1165
				continue;
1166
1167
			if ($config_var[0] == 'boards')
1168
				$board_list = true;
1169
1170
			// Are we showing the BBC selection box?
1171
			if ($config_var[0] == 'bbc')
1172
				$bbcChoice[] = $config_var[1];
1173
1174
			// We need to do some parsing of the value before we pass it in.
1175
			if (isset($modSettings[$config_var[1]]))
1176
			{
1177
				switch ($config_var[0])
1178
				{
1179
					case 'select':
1180
						$value = $modSettings[$config_var[1]];
1181
						break;
1182
					case 'json':
1183
						$value = $smcFunc['htmlspecialchars']($smcFunc['json_encode']($modSettings[$config_var[1]]));
1184
						break;
1185
					case 'boards':
1186
						$value = explode(',', $modSettings[$config_var[1]]);
1187
						break;
1188
					default:
1189
						$value = $smcFunc['htmlspecialchars']($modSettings[$config_var[1]]);
1190
				}
1191
			}
1192
			else
1193
			{
1194
				// Darn, it's empty. What type is expected?
1195
				switch ($config_var[0])
1196
				{
1197
					case 'int':
1198
					case 'float':
1199
						$value = 0;
1200
						break;
1201
					case 'select':
1202
						$value = !empty($config_var['multiple']) ? $smcFunc['json_encode'](array()) : '';
1203
						break;
1204
					case 'boards':
1205
						$value = array();
1206
						break;
1207
					default:
1208
						$value = '';
1209
				}
1210
			}
1211
1212
			$context['config_vars'][$config_var[1]] = array(
1213
				'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] : '')),
1214
				'help' => isset($helptxt[$config_var[1]]) ? $config_var[1] : '',
1215
				'type' => $config_var[0],
1216
				'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)),
1217
				'data' => array(),
1218
				'name' => $config_var[1],
1219
				'value' => $value,
1220
				'disabled' => false,
1221
				'invalid' => !empty($config_var['invalid']),
1222
				'javascript' => '',
1223
				'var_message' => !empty($config_var['message']) && isset($txt[$config_var['message']]) ? $txt[$config_var['message']] : '',
1224
				'preinput' => isset($config_var['preinput']) ? $config_var['preinput'] : '',
1225
				'postinput' => isset($config_var['postinput']) ? $config_var['postinput'] : '',
1226
			);
1227
1228
			// Handle min/max/step if necessary
1229
			if ($config_var[0] == 'int' || $config_var[0] == 'float')
1230
			{
1231
				// Default to a min of 0 if one isn't set
1232
				if (isset($config_var['min']))
1233
					$context['config_vars'][$config_var[1]]['min'] = $config_var['min'];
1234
1235
				else
1236
					$context['config_vars'][$config_var[1]]['min'] = 0;
1237
1238
				if (isset($config_var['max']))
1239
					$context['config_vars'][$config_var[1]]['max'] = $config_var['max'];
1240
1241
				if (isset($config_var['step']))
1242
					$context['config_vars'][$config_var[1]]['step'] = $config_var['step'];
1243
			}
1244
1245
			// If this is a select box handle any data.
1246
			if (!empty($config_var[2]) && is_array($config_var[2]))
1247
			{
1248
				// If we allow multiple selections, we need to adjust a few things.
1249
				if ($config_var[0] == 'select' && !empty($config_var['multiple']))
1250
				{
1251
					$context['config_vars'][$config_var[1]]['name'] .= '[]';
1252
					$context['config_vars'][$config_var[1]]['value'] = !empty($context['config_vars'][$config_var[1]]['value']) ? $smcFunc['json_decode']($context['config_vars'][$config_var[1]]['value'], true) : array();
1253
				}
1254
1255
				// If it's associative
1256
				if (isset($config_var[2][0]) && is_array($config_var[2][0]))
1257
					$context['config_vars'][$config_var[1]]['data'] = $config_var[2];
1258
1259
				else
1260
				{
1261
					foreach ($config_var[2] as $key => $item)
1262
						$context['config_vars'][$config_var[1]]['data'][] = array($key, $item);
1263
				}
1264
				if (empty($config_var['size']) && !empty($config_var['multiple']))
1265
					$context['config_vars'][$config_var[1]]['size'] = max(4, count($config_var[2]));
1266
			}
1267
1268
			// Finally allow overrides - and some final cleanups.
1269
			foreach ($config_var as $k => $v)
1270
			{
1271
				if (!is_numeric($k))
1272
				{
1273
					if (substr($k, 0, 2) == 'on')
1274
						$context['config_vars'][$config_var[1]]['javascript'] .= ' ' . $k . '="' . $v . '"';
1275
					else
1276
						$context['config_vars'][$config_var[1]][$k] = $v;
1277
				}
1278
1279
				// See if there are any other labels that might fit?
1280
				if (isset($txt['setting_' . $config_var[1]]))
1281
					$context['config_vars'][$config_var[1]]['label'] = $txt['setting_' . $config_var[1]];
1282
1283
				elseif (isset($txt['groups_' . $config_var[1]]))
1284
					$context['config_vars'][$config_var[1]]['label'] = $txt['groups_' . $config_var[1]];
1285
			}
1286
1287
			// Set the subtext in case it's part of the label.
1288
			// @todo Temporary. Preventing divs inside label tags.
1289
			$divPos = strpos($context['config_vars'][$config_var[1]]['label'], '<div');
1290
			if ($divPos !== false)
1291
			{
1292
				$context['config_vars'][$config_var[1]]['subtext'] = preg_replace('~</?div[^>]*>~', '', substr($context['config_vars'][$config_var[1]]['label'], $divPos));
1293
				$context['config_vars'][$config_var[1]]['label'] = substr($context['config_vars'][$config_var[1]]['label'], 0, $divPos);
1294
			}
1295
		}
1296
	}
1297
1298
	// If we have inline permissions we need to prep them.
1299
	if (!empty($inlinePermissions) && allowedTo('manage_permissions'))
1300
	{
1301
		require_once($sourcedir . '/ManagePermissions.php');
1302
		init_inline_permissions($inlinePermissions);
1303
	}
1304
1305
	if ($board_list)
1306
	{
1307
		require_once($sourcedir . '/Subs-MessageIndex.php');
1308
		$context['board_list'] = getBoardList();
1309
	}
1310
1311
	// What about any BBC selection boxes?
1312
	if (!empty($bbcChoice))
1313
	{
1314
		// What are the options, eh?
1315
		$temp = parse_bbc(false);
1316
		$bbcTags = array();
1317
		foreach ($temp as $tag)
0 ignored issues
show
Bug introduced by
The expression $temp of type string is not traversable.
Loading history...
1318
			if (!isset($tag['require_parents']))
1319
				$bbcTags[] = $tag['tag'];
1320
1321
		$bbcTags = array_unique($bbcTags);
1322
1323
		// The number of columns we want to show the BBC tags in.
1324
		$numColumns = isset($context['num_bbc_columns']) ? $context['num_bbc_columns'] : 3;
1325
1326
		// Now put whatever BBC options we may have into context too!
1327
		$context['bbc_sections'] = array();
1328
		foreach ($bbcChoice as $bbcSection)
1329
		{
1330
			$context['bbc_sections'][$bbcSection] = array(
1331
				'title' => isset($txt['bbc_title_' . $bbcSection]) ? $txt['bbc_title_' . $bbcSection] : $txt['enabled_bbc_select'],
1332
				'disabled' => empty($modSettings['bbc_disabled_' . $bbcSection]) ? array() : $modSettings['bbc_disabled_' . $bbcSection],
1333
				'all_selected' => empty($modSettings['bbc_disabled_' . $bbcSection]),
1334
				'columns' => array(),
1335
			);
1336
1337
			if ($bbcSection == 'legacyBBC')
1338
				$sectionTags = array_intersect($context['legacy_bbc'], $bbcTags);
1339
			else
1340
				$sectionTags = array_diff($bbcTags, $context['legacy_bbc']);
1341
1342
			$totalTags = count($sectionTags);
1343
			$tagsPerColumn = ceil($totalTags / $numColumns);
1344
1345
			$col = 0;
1346
			$i = 0;
1347
			foreach ($sectionTags as $tag)
1348
			{
1349
				if ($i % $tagsPerColumn == 0 && $i != 0)
1350
					$col++;
1351
1352
				$context['bbc_sections'][$bbcSection]['columns'][$col][] = array(
1353
					'tag' => $tag,
1354
					'show_help' => isset($helptxt['tag_' . $tag]),
1355
				);
1356
1357
				$i++;
1358
			}
1359
		}
1360
	}
1361
1362
	call_integration_hook('integrate_prepare_db_settings', array(&$config_vars));
1363
	createToken('admin-dbsc');
1364
}
1365
1366
/**
1367
 * Helper function. Saves settings by putting them in Settings.php or saving them in the settings table.
1368
 *
1369
 * - Saves those settings set from ?action=admin;area=serversettings.
1370
 * - Requires the admin_forum permission.
1371
 * - Contains arrays of the types of data to save into Settings.php.
1372
 *
1373
 * @param array $config_vars An array of configuration variables
1374
 */
1375
function saveSettings(&$config_vars)
1376
{
1377
	global $sourcedir, $context;
1378
1379
	validateToken('admin-ssc');
1380
1381
	// Fix the darn stupid cookiename! (more may not be allowed, but these for sure!)
1382
	if (isset($_POST['cookiename']))
1383
		$_POST['cookiename'] = preg_replace('~[,;\s\.$]+~' . ($context['utf8'] ? 'u' : ''), '', $_POST['cookiename']);
1384
1385
	// Fix the forum's URL if necessary.
1386
	if (isset($_POST['boardurl']))
1387
	{
1388
		if (substr($_POST['boardurl'], -10) == '/index.php')
1389
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
1390
		elseif (substr($_POST['boardurl'], -1) == '/')
1391
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
1392
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
1393
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
1394
1395
		$_POST['boardurl'] = normalize_iri($_POST['boardurl']);
1396
	}
1397
1398
	// Any passwords?
1399
	$config_passwords = array(
1400
		'db_passwd',
1401
		'ssi_db_passwd',
1402
	);
1403
1404
	// All the strings to write.
1405
	$config_strs = array(
1406
		'mtitle', 'mmessage',
1407
		'language', 'mbname', 'boardurl',
1408
		'cookiename',
1409
		'webmaster_email',
1410
		'db_name', 'db_user', 'db_server', 'db_prefix', 'ssi_db_user',
1411
		'boarddir', 'sourcedir',
1412
		'cachedir', 'cachedir_sqlite', 'cache_accelerator', 'cache_memcached',
1413
		'image_proxy_secret',
1414
	);
1415
1416
	// All the numeric variables.
1417
	$config_ints = array(
1418
		'db_port',
1419
		'cache_enable',
1420
		'image_proxy_maxsize',
1421
	);
1422
1423
	// All the checkboxes
1424
	$config_bools = array('db_persist', 'db_error_send', 'maintenance', 'image_proxy_enabled');
1425
1426
	// Now sort everything into a big array, and figure out arrays and etc.
1427
	$new_settings = array();
1428
	// Figure out which config vars we're saving here...
1429
	foreach ($config_vars as $var)
1430
	{
1431
		if (!is_array($var) || $var[2] != 'file' || (!in_array($var[0], $config_bools) && !isset($_POST[$var[0]])))
1432
			continue;
1433
1434
		$config_var = $var[0];
1435
1436
		if (in_array($config_var, $config_passwords))
1437
		{
1438
			if (isset($_POST[$config_var][1]) && $_POST[$config_var][0] == $_POST[$config_var][1])
1439
				$new_settings[$config_var] = $_POST[$config_var][0];
1440
		}
1441
		elseif (in_array($config_var, $config_strs))
1442
		{
1443
			$new_settings[$config_var] = $_POST[$config_var];
1444
		}
1445
		elseif (in_array($config_var, $config_ints))
1446
		{
1447
			$new_settings[$config_var] = (int) $_POST[$config_var];
1448
1449
			// 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...
1450
			$min = isset($var['min']) ? $var['min'] : 0;
1451
			$new_settings[$config_var] = max($min, $new_settings[$config_var]);
1452
1453
			// Is there a max value for this as well?
1454
			if (isset($var['max']))
1455
				$new_settings[$config_var] = min($var['max'], $new_settings[$config_var]);
1456
		}
1457
		elseif (in_array($config_var, $config_bools))
1458
		{
1459
			if (!empty($_POST[$config_var]))
1460
				$new_settings[$config_var] = 1;
1461
			else
1462
				$new_settings[$config_var] = 0;
1463
		}
1464
		else
1465
		{
1466
			// This shouldn't happen, but it might...
1467
			fatal_error('Unknown config_var \'' . $config_var . '\'');
1468
		}
1469
	}
1470
1471
	// Save the relevant settings in the Settings.php file.
1472
	require_once($sourcedir . '/Subs-Admin.php');
1473
	updateSettingsFile($new_settings);
1474
1475
	// Now loop through the remaining (database-based) settings.
1476
	$new_settings = array();
1477
	foreach ($config_vars as $config_var)
1478
	{
1479
		// We just saved the file-based settings, so skip their definitions.
1480
		if (!is_array($config_var) || $config_var[2] == 'file')
1481
			continue;
1482
1483
		$new_setting = array($config_var[3], $config_var[0]);
1484
1485
		// Select options need carried over, too.
1486
		if (isset($config_var[4]))
1487
			$new_setting[] = $config_var[4];
1488
1489
		// Include min and max if necessary
1490
		if (isset($config_var['min']))
1491
			$new_setting['min'] = $config_var['min'];
1492
1493
		if (isset($config_var['max']))
1494
			$new_setting['max'] = $config_var['max'];
1495
1496
		// Rewrite the definition a bit.
1497
		$new_settings[] = $new_setting;
1498
	}
1499
1500
	// Save the new database-based settings, if any.
1501
	if (!empty($new_settings))
1502
		saveDBSettings($new_settings);
1503
}
1504
1505
/**
1506
 * Helper function for saving database settings.
1507
 *
1508
 * @todo see rev. 10406 from 2.1-requests
1509
 *
1510
 * @param array $config_vars An array of configuration variables
1511
 */
1512
function saveDBSettings(&$config_vars)
1513
{
1514
	global $sourcedir, $smcFunc;
1515
	static $board_list = null;
1516
1517
	validateToken('admin-dbsc');
1518
1519
	$inlinePermissions = array();
1520
	foreach ($config_vars as $var)
1521
	{
1522
		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']))))
1523
			continue;
1524
1525
		// Checkboxes!
1526
		elseif ($var[0] == 'check')
1527
			$setArray[$var[1]] = !empty($_POST[$var[1]]) ? '1' : '0';
1528
		// Select boxes!
1529
		elseif ($var[0] == 'select' && in_array($_POST[$var[1]], array_keys($var[2])))
1530
			$setArray[$var[1]] = $_POST[$var[1]];
1531
		elseif ($var[0] == 'select' && !empty($var['multiple']) && array_intersect($_POST[$var[1]], array_keys($var[2])) != array())
1532
		{
1533
			// For security purposes we validate this line by line.
1534
			$lOptions = array();
1535
			foreach ($_POST[$var[1]] as $invar)
1536
				if (in_array($invar, array_keys($var[2])))
1537
					$lOptions[] = $invar;
1538
1539
			$setArray[$var[1]] = $smcFunc['json_encode']($lOptions);
1540
		}
1541
		// List of boards!
1542
		elseif ($var[0] == 'boards')
1543
		{
1544
			// We just need a simple list of valid boards, nothing more.
1545
			if ($board_list === null)
1546
			{
1547
				$board_list = array();
1548
				$request = $smcFunc['db_query']('', '
1549
					SELECT id_board
1550
					FROM {db_prefix}boards');
1551
1552
				while ($row = $smcFunc['db_fetch_row']($request))
1553
					$board_list[$row[0]] = true;
1554
1555
				$smcFunc['db_free_result']($request);
1556
			}
1557
1558
			$lOptions = array();
1559
1560
			if (!empty($_POST[$var[1]]))
1561
				foreach ($_POST[$var[1]] as $invar => $dummy)
1562
					if (isset($board_list[$invar]))
1563
						$lOptions[] = $invar;
1564
1565
			$setArray[$var[1]] = !empty($lOptions) ? implode(',', $lOptions) : '';
1566
		}
1567
		// Integers!
1568
		elseif ($var[0] == 'int')
1569
		{
1570
			$setArray[$var[1]] = (int) $_POST[$var[1]];
1571
1572
			// 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...
1573
			$min = isset($var['min']) ? $var['min'] : 0;
1574
			$setArray[$var[1]] = max($min, $setArray[$var[1]]);
1575
1576
			// Do we have a max value for this as well?
1577
			if (isset($var['max']))
1578
				$setArray[$var[1]] = min($var['max'], $setArray[$var[1]]);
1579
		}
1580
		// Floating point!
1581
		elseif ($var[0] == 'float')
1582
		{
1583
			$setArray[$var[1]] = (float) $_POST[$var[1]];
1584
1585
			// 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...
1586
			$min = isset($var['min']) ? $var['min'] : 0;
1587
			$setArray[$var[1]] = max($min, $setArray[$var[1]]);
1588
1589
			// Do we have a max value for this as well?
1590
			if (isset($var['max']))
1591
				$setArray[$var[1]] = min($var['max'], $setArray[$var[1]]);
1592
		}
1593
		// Text!
1594
		elseif (in_array($var[0], array('text', 'large_text', 'color', 'date', 'datetime', 'datetime-local', 'email', 'month', 'time')))
1595
			$setArray[$var[1]] = $_POST[$var[1]];
1596
		// Passwords!
1597
		elseif ($var[0] == 'password')
1598
		{
1599
			if (isset($_POST[$var[1]][1]) && $_POST[$var[1]][0] == $_POST[$var[1]][1])
1600
				$setArray[$var[1]] = $_POST[$var[1]][0];
1601
		}
1602
		// BBC.
1603
		elseif ($var[0] == 'bbc')
1604
		{
1605
			$bbcTags = array();
1606
			foreach (parse_bbc(false) as $tag)
0 ignored issues
show
Bug introduced by
The expression parse_bbc(false) of type string is not traversable.
Loading history...
1607
				$bbcTags[] = $tag['tag'];
1608
1609
			if (!isset($_POST[$var[1] . '_enabledTags']))
1610
				$_POST[$var[1] . '_enabledTags'] = array();
1611
			elseif (!is_array($_POST[$var[1] . '_enabledTags']))
1612
				$_POST[$var[1] . '_enabledTags'] = array($_POST[$var[1] . '_enabledTags']);
1613
1614
			$setArray[$var[1]] = implode(',', array_diff($bbcTags, $_POST[$var[1] . '_enabledTags']));
1615
		}
1616
		// Permissions?
1617
		elseif ($var[0] == 'permissions')
1618
			$inlinePermissions[] = $var[1];
1619
	}
1620
1621
	if (!empty($setArray))
1622
		updateSettings($setArray);
1623
1624
	// If we have inline permissions we need to save them.
1625
	if (!empty($inlinePermissions) && allowedTo('manage_permissions'))
1626
	{
1627
		require_once($sourcedir . '/ManagePermissions.php');
1628
		save_inline_permissions($inlinePermissions);
1629
	}
1630
}
1631
1632
/**
1633
 * Allows us to see the servers php settings
1634
 *
1635
 * - loads the settings into an array for display in a template
1636
 * - drops cookie values just in case
1637
 */
1638
function ShowPHPinfoSettings()
1639
{
1640
	global $context, $txt;
1641
1642
	$category = $txt['phpinfo_settings'];
1643
1644
	// get the data
1645
	ob_start();
1646
	phpinfo();
1647
1648
	// We only want it for its body, pigs that we are
1649
	$info_lines = preg_replace('~^.*<body>(.*)</body>.*$~', '$1', ob_get_contents());
1650
	$info_lines = explode("\n", strip_tags($info_lines, "<tr><td><h2>"));
1651
	ob_end_clean();
1652
1653
	// remove things that could be considered sensitive
1654
	$remove = '_COOKIE|Cookie|_GET|_REQUEST|REQUEST_URI|QUERY_STRING|REQUEST_URL|HTTP_REFERER';
1655
1656
	// put all of it into an array
1657
	foreach ($info_lines as $line)
1658
	{
1659
		if (preg_match('~(' . $remove . ')~', $line))
1660
			continue;
1661
1662
		// new category?
1663
		if (strpos($line, '<h2>') !== false)
1664
			$category = preg_match('~<h2>(.*)</h2>~', $line, $title) ? $category = $title[1] : $category;
0 ignored issues
show
Unused Code introduced by
The assignment to $category is dead and can be removed.
Loading history...
1665
1666
		// load it as setting => value or the old setting local master
1667
		if (preg_match('~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~', $line, $val))
1668
			$pinfo[$category][$val[1]] = $val[2];
1669
		elseif (preg_match('~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~', $line, $val))
1670
			$pinfo[$category][$val[1]] = array($txt['phpinfo_localsettings'] => $val[2], $txt['phpinfo_defaultsettings'] => $val[3]);
1671
	}
1672
1673
	// load it in to context and display it
1674
	$context['pinfo'] = $pinfo;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pinfo does not seem to be defined for all execution paths leading up to this point.
Loading history...
1675
	$context['page_title'] = $txt['admin_server_settings'];
1676
	$context['sub_template'] = 'php_info';
1677
	return;
1678
}
1679
1680
/**
1681
 * Get the installed Cache API implementations.
1682
 *
1683
 */
1684
function loadCacheAPIs()
1685
{
1686
	global $sourcedir;
1687
1688
	$cacheAPIdir = $sourcedir . '/Cache';
1689
1690
	$loadedApis = array();
1691
	$apis_dir = $cacheAPIdir .'/'. CacheApi::APIS_FOLDER;
1692
1693
	$api_classes = new GlobIterator($apis_dir . '/*.php', FilesystemIterator::NEW_CURRENT_AND_KEY);
1694
1695
	foreach ($api_classes as $file_path => $file_info)
1696
	{
1697
		require_once($apis_dir . '/' . $file_path);
1698
1699
		$class_name = $file_info->getBasename('.php');
1700
		$fully_qualified_class_name = CacheApi::APIS_NAMESPACE . $class_name;
1701
1702
		/* @var CacheApiInterface $cache_api */
1703
		$cache_api = new $fully_qualified_class_name();
1704
1705
		// Deal with it!
1706
		if (!($cache_api instanceof CacheApiInterface) || !($cache_api instanceof CacheApi))
1707
			continue;
1708
1709
		// No Support?  NEXT!
1710
		if (!$cache_api->isSupported(true))
1711
			continue;
1712
1713
		$loadedApis[$class_name] = $cache_api;
1714
	}
1715
1716
	call_integration_hook('integrate_load_cache_apis', array(&$loadedApis));
1717
1718
	return $loadedApis;
1719
}
1720
1721
/**
1722
 * Registers the site with the Simple Machines Stat collection. This function
1723
 * purposely does not use updateSettings.php as it will be called shortly after
1724
 * this process completes by the saveSettings() function.
1725
 *
1726
 * @see SMStats() for more information.
1727
 * @link https://www.simplemachines.org/about/stats.php for more info.
1728
 *
1729
 */
1730
function registerSMStats()
1731
{
1732
	global $modSettings, $boardurl, $smcFunc;
1733
1734
	// Already have a key?  Can't register again.
1735
	if (!empty($modSettings['sm_stats_key']))
1736
		return true;
1737
1738
	$fp = @fsockopen('www.simplemachines.org', 443, $errno, $errstr);
1739
	if (!$fp)
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
1740
		$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
1741
	if ($fp)
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
1742
	{
1743
		$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
1744
		$out .= 'Host: www.simplemachines.org' . "\r\n";
1745
		$out .= 'Connection: Close' . "\r\n\r\n";
1746
		fwrite($fp, $out);
1747
1748
		$return_data = '';
1749
		while (!feof($fp))
1750
			$return_data .= fgets($fp, 128);
1751
1752
		fclose($fp);
1753
1754
		// Get the unique site ID.
1755
		preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1756
1757
		if (!empty($ID[1]))
1758
		{
1759
			$smcFunc['db_insert']('replace',
1760
				'{db_prefix}settings',
1761
				array('variable' => 'string', 'value' => 'string'),
1762
				array('sm_stats_key', $ID[1]),
1763
				array('variable')
1764
			);
1765
			return true;
1766
		}
1767
	}
1768
1769
	return false;
1770
}
1771
1772
?>