Passed
Pull Request — release-2.1 (#7102)
by Jon
07:01
created

ModifyGeneralSettings()   C

Complexity

Conditions 12
Paths 16

Size

Total Lines 93
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 48
c 0
b 0
f 0
nc 16
nop 1
dl 0
loc 93
rs 6.9666

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 2021 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 ($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']) && strpos($boardurl, $_POST['globalCookiesDomain']) === false)
551
			fatal_lang_error('invalid_cookie_domain', false);
552
553
		saveSettings($config_vars);
554
555
		// If the cookie name or scope were changed, reset the cookie.
556
		if ($cookiename != $_POST['cookiename'] || !empty($scope_changed))
557
		{
558
			$original_session_id = $context['session_id'];
559
			include_once($sourcedir . '/Subs-Auth.php');
560
561
			// Remove the old cookie.
562
			setLoginCookie(-3600, 0);
563
564
			// Set the new one.
565
			$cookiename = !empty($_POST['cookiename']) ? $_POST['cookiename'] : $cookiename;
566
			setLoginCookie(60 * $modSettings['cookieTime'], $user_settings['id_member'], hash_salt($user_settings['passwd'], $user_settings['password_salt']));
567
568
			redirectexit('action=admin;area=serversettings;sa=cookie;' . $context['session_var'] . '=' . $original_session_id, $context['server']['needs_login_fix']);
569
		}
570
571
		//If we disabled 2FA, reset all members and membergroups settings.
572
		if (isset($_POST['tfa_mode']) && empty($_POST['tfa_mode']))
573
		{
574
			$smcFunc['db_query']('', '
575
				UPDATE {db_prefix}membergroups
576
				SET tfa_required = {int:zero}',
577
				array(
578
					'zero' => 0,
579
				)
580
			);
581
			$smcFunc['db_query']('', '
582
				UPDATE {db_prefix}members
583
				SET tfa_secret = {string:empty}, tfa_backup = {string:empty}',
584
				array(
585
					'empty' => '',
586
				)
587
			);
588
		}
589
590
		$_SESSION['adm-save'] = true;
591
		redirectexit('action=admin;area=serversettings;sa=cookie;' . $context['session_var'] . '=' . $context['session_id']);
592
	}
593
594
	// Fill the config array.
595
	prepareServerSettingsContext($config_vars);
596
}
597
598
/**
599
 * Settings really associated with general security aspects.
600
 *
601
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
602
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
603
 */
604
function ModifyGeneralSecuritySettings($return_config = false)
605
{
606
	global $txt, $scripturl, $context;
607
608
	$config_vars = array(
609
		array('int', 'failed_login_threshold'),
610
		array('int', 'loginHistoryDays', 'subtext' => $txt['zero_to_disable']),
611
		'',
612
613
		array('check', 'securityDisable'),
614
		array('check', 'securityDisable_moderate'),
615
		'',
616
617
		// Reactive on email, and approve on delete
618
		array('check', 'send_validation_onChange'),
619
		array('check', 'approveAccountDeletion'),
620
		'',
621
622
		// Password strength.
623
		array(
624
			'select',
625
			'password_strength',
626
			array(
627
				$txt['setting_password_strength_low'],
628
				$txt['setting_password_strength_medium'],
629
				$txt['setting_password_strength_high']
630
			)
631
		),
632
		array('check', 'enable_password_conversion'),
633
		'',
634
635
		// Reporting of personal messages?
636
		array('check', 'enableReportPM'),
637
		'',
638
639
		array('check', 'allow_cors'),
640
		array('check', 'allow_cors_credentials'),
641
		array('text', 'cors_domains'),
642
		array('text', 'cors_headers'),
643
		'',
644
645
		array(
646
			'select',
647
			'frame_security',
648
			array(
649
				'SAMEORIGIN' => $txt['setting_frame_security_SAMEORIGIN'],
650
				'DENY' => $txt['setting_frame_security_DENY'],
651
				'DISABLE' => $txt['setting_frame_security_DISABLE']
652
			)
653
		),
654
		'',
655
656
		array(
657
			'select',
658
			'proxy_ip_header',
659
			array(
660
				'disabled' => $txt['setting_proxy_ip_header_disabled'],
661
				'autodetect' => $txt['setting_proxy_ip_header_autodetect'],
662
				'HTTP_X_FORWARDED_FOR' => 'X-Forwarded-For',
663
				'HTTP_CLIENT_IP' => 'Client-IP',
664
				'HTTP_X_REAL_IP' => 'X-Real-IP',
665
				'HTTP_CF_CONNECTING_IP' => 'CF-Connecting-IP'
666
			)
667
		),
668
		array('text', 'proxy_ip_servers'),
669
	);
670
671
	call_integration_hook('integrate_general_security_settings', array(&$config_vars));
672
673
	if ($return_config)
674
		return $config_vars;
675
676
	// Saving?
677
	if (isset($_GET['save']))
678
	{
679
		saveDBSettings($config_vars);
680
		$_SESSION['adm-save'] = true;
681
682
		call_integration_hook('integrate_save_general_security_settings');
683
684
		writeLog();
685
		redirectexit('action=admin;area=serversettings;sa=security;' . $context['session_var'] . '=' . $context['session_id']);
686
	}
687
688
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;save;sa=security';
689
	$context['settings_title'] = $txt['security_settings'];
690
691
	prepareDBSettingContext($config_vars);
692
}
693
694
/**
695
 * Simply modifying cache functions
696
 *
697
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
698
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
699
 */
700
function ModifyCacheSettings($return_config = false)
701
{
702
	global $context, $scripturl, $txt;
703
704
	// Detect all available optimizers
705
	$detectedCacheApis = loadCacheAPIs();
706
	$apis_names = array();
707
708
	/* @var CacheApiInterface $cache_api */
709
	foreach ($detectedCacheApis as $class_name => $cache_api)
710
	{
711
		$class_name_txt_key = strtolower($cache_api->getImplementationClassKeyName());
712
713
		$apis_names[$class_name] = isset($txt[$class_name_txt_key . '_cache']) ?
714
			$txt[$class_name_txt_key . '_cache'] : $class_name;
715
	}
716
717
	// set our values to show what, if anything, we found
718
	if (empty($detectedCacheApis))
719
	{
720
		$txt['cache_settings_message'] = '<strong class="alert">' . $txt['detected_no_caching'] . '</strong>';
721
		$cache_level = array($txt['cache_off']);
722
		$apis_names['none'] = $txt['cache_off'];
723
	}
724
725
	else
726
	{
727
		$txt['cache_settings_message'] = '<strong class="success">' .
728
			sprintf($txt['detected_accelerators'], implode(', ', $apis_names)) . '</strong>';
729
730
		$cache_level = array($txt['cache_off'], $txt['cache_level1'], $txt['cache_level2'], $txt['cache_level3']);
731
	}
732
733
	// Define the variables we want to edit.
734
	$config_vars = array(
735
		// Only a few settings, but they are important
736
		array('', $txt['cache_settings_message'], '', 'desc'),
737
		array('cache_enable', $txt['cache_enable'], 'file', 'select', $cache_level, 'cache_enable'),
738
		array('cache_accelerator', $txt['cache_accelerator'], 'file', 'select', $apis_names),
739
	);
740
741
	// some javascript to enable / disable certain settings if the option is not selected
742
	$context['settings_post_javascript'] = '
743
		$(document).ready(function() {
744
			$("#cache_accelerator").change();
745
		});';
746
747
	call_integration_hook('integrate_modify_cache_settings', array(&$config_vars));
748
749
	// Maybe we have some additional settings from the selected accelerator.
750
	if (!empty($detectedCacheApis))
751
		/* @var CacheApiInterface $cache_api */
752
		foreach ($detectedCacheApis as $class_name_txt_key => $cache_api)
753
			if (is_callable(array($cache_api, 'cacheSettings')))
754
				$cache_api->cacheSettings($config_vars);
755
756
	if ($return_config)
757
		return $config_vars;
758
759
	// Saving again?
760
	if (isset($_GET['save']))
761
	{
762
		call_integration_hook('integrate_save_cache_settings');
763
764
		saveSettings($config_vars);
765
		$_SESSION['adm-save'] = true;
766
767
		// We need to save the $cache_enable to $modSettings as well
768
		updatesettings(array('cache_enable' => (int) $_POST['cache_enable']));
769
770
		// exit so we reload our new settings on the page
771
		redirectexit('action=admin;area=serversettings;sa=cache;' . $context['session_var'] . '=' . $context['session_id']);
772
	}
773
774
	loadLanguage('ManageMaintenance');
775
	createToken('admin-maint');
776
	$context['template_layers'][] = 'clean_cache_button';
777
778
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=cache;save';
779
	$context['settings_title'] = $txt['caching_settings'];
780
781
	// Changing cache settings won't have any effect if Settings.php is not writable.
782
	$context['save_disabled'] = $context['settings_not_writable'];
783
784
	// Decide what message to show.
785
	if (!$context['save_disabled'])
786
		$context['settings_message'] = $txt['caching_information'];
787
788
	// Prepare the template.
789
	prepareServerSettingsContext($config_vars);
790
}
791
792
/**
793
 * Controls settings for data export functionality
794
 *
795
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
796
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
797
 */
798
function ModifyExportSettings($return_config = false)
799
{
800
	global $context, $scripturl, $txt, $modSettings, $boarddir, $sourcedir;
801
802
	// Fill in a default value for this if it is missing.
803
	if (empty($modSettings['export_dir']))
804
		$modSettings['export_dir'] = $boarddir . DIRECTORY_SEPARATOR . 'exports';
805
806
	/*
807
		Some paranoid hosts worry that the disk space functions pose a security
808
		risk. Usually these hosts just disable the functions and move on, which
809
		is fine. A rare few, however, are not only paranoid, but also think it'd
810
		be a "clever" security move to overload the disk space functions with
811
		custom code that intentionally delivers false information, which is
812
		idiotic and evil. At any rate, if the functions are unavailable or if
813
		they report obviously insane values, it's not possible to track disk
814
		usage correctly.
815
	 */
816
	$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);
817
818
	$context['settings_message'] = $txt['export_settings_description'];
819
820
	$config_vars = array(
821
		array('text', 'export_dir', 40),
822
		array('int', 'export_expiry', 'subtext' => $txt['zero_to_disable'], 'postinput' => $txt['days_word']),
823
		array('int', 'export_min_diskspace_pct', 'postinput' => '%', 'max' => 80, 'disabled' => $diskspace_disabled),
824
		array('int', 'export_rate', 'min' => 5, 'max' => 500, 'step' => 5, 'subtext' => $txt['export_rate_desc']),
825
	);
826
827
	call_integration_hook('integrate_export_settings', array(&$config_vars));
828
829
	if ($return_config)
830
		return $config_vars;
831
832
	if (isset($_REQUEST['save']))
833
	{
834
		$prev_export_dir = is_dir($modSettings['export_dir']) ? rtrim($modSettings['export_dir'], '/\\') : '';
835
836
		if (!empty($_POST['export_dir']))
837
			$_POST['export_dir'] = rtrim($_POST['export_dir'], '/\\');
838
839
		if ($diskspace_disabled)
840
			$_POST['export_min_diskspace_pct'] = 0;
841
842
		$_POST['export_rate'] = max(5, min($_POST['export_rate'], 500));
843
844
		saveDBSettings($config_vars);
845
846
		// Create the new directory, but revert to the previous one if anything goes wrong.
847
		require_once($sourcedir . '/Profile-Export.php');
848
		create_export_dir($prev_export_dir);
849
850
		// Ensure we don't lose track of any existing export files.
851
		if (!empty($prev_export_dir) && $prev_export_dir != $modSettings['export_dir'])
852
		{
853
			$export_files = glob($prev_export_dir . DIRECTORY_SEPARATOR . '*');
854
855
			foreach ($export_files as $export_file)
856
			{
857
				if (!in_array(basename($export_file), array('index.php', '.htaccess')))
858
				{
859
					rename($export_file, $modSettings['export_dir'] . DIRECTORY_SEPARATOR . basename($export_file));
860
				}
861
			}
862
		}
863
864
		call_integration_hook('integrate_save_export_settings');
865
866
		$_SESSION['adm-save'] = true;
867
		redirectexit('action=admin;area=serversettings;sa=export;' . $context['session_var'] . '=' . $context['session_id']);
868
	}
869
870
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=export;save';
871
	$context['settings_title'] = $txt['export_settings'];
872
873
	prepareDBSettingContext($config_vars);
874
}
875
876
/**
877
 * Allows to edit load balancing settings.
878
 *
879
 * @param bool $return_config Whether or not to return the config_vars array
880
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
881
 */
882
function ModifyLoadBalancingSettings($return_config = false)
883
{
884
	global $txt, $scripturl, $context, $modSettings;
885
886
	// Setup a warning message, but disabled by default.
887
	$disabled = true;
888
	$context['settings_message'] = array('label' => $txt['loadavg_disabled_conf'], 'class' => 'error');
889
890
	if (DIRECTORY_SEPARATOR === '\\')
891
	{
892
		$context['settings_message']['label'] = $txt['loadavg_disabled_windows'];
893
		if (isset($_GET['save']))
894
			$_SESSION['adm-save'] = $context['settings_message']['label'];
895
	}
896
	elseif (stripos(PHP_OS, 'darwin') === 0)
897
	{
898
		$context['settings_message']['label'] = $txt['loadavg_disabled_osx'];
899
		if (isset($_GET['save']))
900
			$_SESSION['adm-save'] = $context['settings_message']['label'];
901
	}
902
	else
903
	{
904
		$modSettings['load_average'] = @file_get_contents('/proc/loadavg');
905
		if (!empty($modSettings['load_average']) && preg_match('~^([^ ]+?) ([^ ]+?) ([^ ]+)~', $modSettings['load_average'], $matches) !== 0)
906
			$modSettings['load_average'] = (float) $matches[1];
907
		elseif (($modSettings['load_average'] = @`uptime`) !== null && preg_match('~load averages?: (\d+\.\d+), (\d+\.\d+), (\d+\.\d+)~i', $modSettings['load_average'], $matches) !== 0)
908
			$modSettings['load_average'] = (float) $matches[1];
909
		else
910
			unset($modSettings['load_average']);
911
912
		if (!empty($modSettings['load_average']) || (isset($modSettings['load_average']) && $modSettings['load_average'] === 0.0))
913
		{
914
			$context['settings_message']['label'] = sprintf($txt['loadavg_warning'], $modSettings['load_average']);
915
			$disabled = false;
916
		}
917
	}
918
919
	// Start with a simple checkbox.
920
	$config_vars = array(
921
		array('check', 'loadavg_enable', 'disabled' => $disabled),
922
	);
923
924
	// Set the default values for each option.
925
	$default_values = array(
926
		'loadavg_auto_opt' => 1.0,
927
		'loadavg_search' => 2.5,
928
		'loadavg_allunread' => 2.0,
929
		'loadavg_unreadreplies' => 3.5,
930
		'loadavg_show_posts' => 2.0,
931
		'loadavg_userstats' => 10.0,
932
		'loadavg_bbc' => 30.0,
933
		'loadavg_forum' => 40.0,
934
	);
935
936
	// Loop through the settings.
937
	foreach ($default_values as $name => $value)
938
	{
939
		// Use the default value if the setting isn't set yet.
940
		$value = !isset($modSettings[$name]) ? $value : $modSettings[$name];
941
		$config_vars[] = array('float', $name, 'value' => $value, 'disabled' => $disabled);
942
	}
943
944
	call_integration_hook('integrate_loadavg_settings', array(&$config_vars));
945
946
	if ($return_config)
947
		return $config_vars;
948
949
	$context['post_url'] = $scripturl . '?action=admin;area=serversettings;sa=loads;save';
950
	$context['settings_title'] = $txt['load_balancing_settings'];
951
952
	// Saving?
953
	if (isset($_GET['save']))
954
	{
955
		// Stupidity is not allowed.
956
		foreach ($_POST as $key => $value)
957
		{
958
			if (strpos($key, 'loadavg') === 0 || $key === 'loadavg_enable' || !in_array($key, array_keys($default_values)))
959
				continue;
960
			else
961
				$_POST[$key] = (float) $value;
962
963
			if ($key == 'loadavg_auto_opt' && $value <= 1)
964
				$_POST['loadavg_auto_opt'] = 1.0;
965
			elseif ($key == 'loadavg_forum' && $value < 10)
966
				$_POST['loadavg_forum'] = 10.0;
967
			elseif ($value < 2)
968
				$_POST[$key] = 2.0;
969
		}
970
971
		call_integration_hook('integrate_save_loadavg_settings');
972
973
		saveDBSettings($config_vars);
974
		if (!isset($_SESSION['adm-save']))
975
			$_SESSION['adm-save'] = true;
976
		redirectexit('action=admin;area=serversettings;sa=loads;' . $context['session_var'] . '=' . $context['session_id']);
977
	}
978
979
	prepareDBSettingContext($config_vars);
980
}
981
982
/**
983
 * Helper function, it sets up the context for the manage server settings.
984
 * - The basic usage of the six numbered key fields are
985
 * - array (0 ,1, 2, 3, 4, 5
986
 *		0 variable name - the name of the saved variable
987
 *		1 label - the text to show on the settings page
988
 *		2 saveto - file or db, where to save the variable name - value pair
989
 *		3 type - type of data to save, int, float, text, check
990
 *		4 size - false or field size
991
 *		5 help - '' or helptxt variable name
992
 *	)
993
 *
994
 * the following named keys are also permitted
995
 * 'disabled' => A string of code that will determine whether or not the setting should be disabled
996
 * 'postinput' => Text to display after the input field
997
 * 'preinput' => Text to display before the input field
998
 * 'subtext' => Additional descriptive text to display under the field's label
999
 * 'min' => minimum allowed value (for int/float). Defaults to 0 if not set.
1000
 * 'max' => maximum allowed value (for int/float)
1001
 * 'step' => how much to increment/decrement the value by (only for int/float - mostly used for float values).
1002
 *
1003
 * @param array $config_vars An array of configuration variables
1004
 */
1005
function prepareServerSettingsContext(&$config_vars)
1006
{
1007
	global $context, $modSettings, $smcFunc;
1008
1009
	if (isset($_SESSION['adm-save']))
1010
	{
1011
		if ($_SESSION['adm-save'] === true)
1012
			$context['saved_successful'] = true;
1013
		else
1014
			$context['saved_failed'] = $_SESSION['adm-save'];
1015
1016
		unset($_SESSION['adm-save']);
1017
	}
1018
1019
	$context['config_vars'] = array();
1020
	foreach ($config_vars as $identifier => $config_var)
1021
	{
1022
		if (!is_array($config_var) || !isset($config_var[1]))
1023
			$context['config_vars'][] = $config_var;
1024
		else
1025
		{
1026
			$varname = $config_var[0];
1027
			global $$varname;
1028
1029
			// Set the subtext in case it's part of the label.
1030
			// @todo Temporary. Preventing divs inside label tags.
1031
			$divPos = strpos($config_var[1], '<div');
1032
			$subtext = '';
1033
			if ($divPos !== false)
1034
			{
1035
				$subtext = preg_replace('~</?div[^>]*>~', '', substr($config_var[1], $divPos));
1036
				$config_var[1] = substr($config_var[1], 0, $divPos);
1037
			}
1038
1039
			$context['config_vars'][$config_var[0]] = array(
1040
				'label' => $config_var[1],
1041
				'help' => isset($config_var[5]) ? $config_var[5] : '',
1042
				'type' => $config_var[3],
1043
				'size' => !empty($config_var[4]) && !is_array($config_var[4]) ? $config_var[4] : 0,
1044
				'data' => isset($config_var[4]) && is_array($config_var[4]) && $config_var[3] != 'select' ? $config_var[4] : array(),
1045
				'name' => $config_var[0],
1046
				'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 : '')),
1047
				'disabled' => !empty($context['settings_not_writable']) || !empty($config_var['disabled']),
1048
				'invalid' => false,
1049
				'subtext' => !empty($config_var['subtext']) ? $config_var['subtext'] : $subtext,
1050
				'javascript' => '',
1051
				'preinput' => !empty($config_var['preinput']) ? $config_var['preinput'] : '',
1052
				'postinput' => !empty($config_var['postinput']) ? $config_var['postinput'] : '',
1053
			);
1054
1055
			// Handle min/max/step if necessary
1056
			if ($config_var[3] == 'int' || $config_var[3] == 'float')
1057
			{
1058
				// Default to a min of 0 if one isn't set
1059
				if (isset($config_var['min']))
1060
					$context['config_vars'][$config_var[0]]['min'] = $config_var['min'];
1061
				else
1062
					$context['config_vars'][$config_var[0]]['min'] = 0;
1063
1064
				if (isset($config_var['max']))
1065
					$context['config_vars'][$config_var[0]]['max'] = $config_var['max'];
1066
1067
				if (isset($config_var['step']))
1068
					$context['config_vars'][$config_var[0]]['step'] = $config_var['step'];
1069
			}
1070
1071
			// If this is a select box handle any data.
1072
			if (!empty($config_var[4]) && is_array($config_var[4]))
1073
			{
1074
				// If it's associative
1075
				$config_values = array_values($config_var[4]);
1076
				if (isset($config_values[0]) && is_array($config_values[0]))
1077
					$context['config_vars'][$config_var[0]]['data'] = $config_var[4];
1078
				else
1079
				{
1080
					foreach ($config_var[4] as $key => $item)
1081
						$context['config_vars'][$config_var[0]]['data'][] = array($key, $item);
1082
				}
1083
			}
1084
		}
1085
	}
1086
1087
	// Two tokens because saving these settings requires both saveSettings and saveDBSettings
1088
	createToken('admin-ssc');
1089
	createToken('admin-dbsc');
1090
}
1091
1092
/**
1093
 * Helper function, it sets up the context for database settings.
1094
 *
1095
 * @todo see rev. 10406 from 2.1-requests
1096
 *
1097
 * @param array $config_vars An array of configuration variables
1098
 */
1099
function prepareDBSettingContext(&$config_vars)
1100
{
1101
	global $txt, $helptxt, $context, $modSettings, $sourcedir, $smcFunc;
1102
1103
	loadLanguage('Help');
1104
1105
	if (isset($_SESSION['adm-save']))
1106
	{
1107
		if ($_SESSION['adm-save'] === true)
1108
			$context['saved_successful'] = true;
1109
		else
1110
			$context['saved_failed'] = $_SESSION['adm-save'];
1111
1112
		unset($_SESSION['adm-save']);
1113
	}
1114
1115
	$context['config_vars'] = array();
1116
	$inlinePermissions = array();
1117
	$bbcChoice = array();
1118
	$board_list = false;
1119
	foreach ($config_vars as $config_var)
1120
	{
1121
		// HR?
1122
		if (!is_array($config_var))
1123
			$context['config_vars'][] = $config_var;
1124
		else
1125
		{
1126
			// If it has no name it doesn't have any purpose!
1127
			if (empty($config_var[1]))
1128
				continue;
1129
1130
			// Special case for inline permissions
1131
			if ($config_var[0] == 'permissions' && allowedTo('manage_permissions'))
1132
				$inlinePermissions[] = $config_var[1];
1133
1134
			elseif ($config_var[0] == 'permissions')
1135
				continue;
1136
1137
			if ($config_var[0] == 'boards')
1138
				$board_list = true;
1139
1140
			// Are we showing the BBC selection box?
1141
			if ($config_var[0] == 'bbc')
1142
				$bbcChoice[] = $config_var[1];
1143
1144
			// We need to do some parsing of the value before we pass it in.
1145
			if (isset($modSettings[$config_var[1]]))
1146
			{
1147
				switch ($config_var[0])
1148
				{
1149
					case 'select':
1150
						$value = $modSettings[$config_var[1]];
1151
						break;
1152
					case 'json':
1153
						$value = $smcFunc['htmlspecialchars']($smcFunc['json_encode']($modSettings[$config_var[1]]));
1154
						break;
1155
					case 'boards':
1156
						$value = explode(',', $modSettings[$config_var[1]]);
1157
						break;
1158
					default:
1159
						$value = $smcFunc['htmlspecialchars']($modSettings[$config_var[1]]);
1160
				}
1161
			}
1162
			else
1163
			{
1164
				// Darn, it's empty. What type is expected?
1165
				switch ($config_var[0])
1166
				{
1167
					case 'int':
1168
					case 'float':
1169
						$value = 0;
1170
						break;
1171
					case 'select':
1172
						$value = !empty($config_var['multiple']) ? $smcFunc['json_encode'](array()) : '';
1173
						break;
1174
					case 'boards':
1175
						$value = array();
1176
						break;
1177
					default:
1178
						$value = '';
1179
				}
1180
			}
1181
1182
			$context['config_vars'][$config_var[1]] = array(
1183
				'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] : '')),
1184
				'help' => isset($helptxt[$config_var[1]]) ? $config_var[1] : '',
1185
				'type' => $config_var[0],
1186
				'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)),
1187
				'data' => array(),
1188
				'name' => $config_var[1],
1189
				'value' => $value,
1190
				'disabled' => false,
1191
				'invalid' => !empty($config_var['invalid']),
1192
				'javascript' => '',
1193
				'var_message' => !empty($config_var['message']) && isset($txt[$config_var['message']]) ? $txt[$config_var['message']] : '',
1194
				'preinput' => isset($config_var['preinput']) ? $config_var['preinput'] : '',
1195
				'postinput' => isset($config_var['postinput']) ? $config_var['postinput'] : '',
1196
			);
1197
1198
			// Handle min/max/step if necessary
1199
			if ($config_var[0] == 'int' || $config_var[0] == 'float')
1200
			{
1201
				// Default to a min of 0 if one isn't set
1202
				if (isset($config_var['min']))
1203
					$context['config_vars'][$config_var[1]]['min'] = $config_var['min'];
1204
1205
				else
1206
					$context['config_vars'][$config_var[1]]['min'] = 0;
1207
1208
				if (isset($config_var['max']))
1209
					$context['config_vars'][$config_var[1]]['max'] = $config_var['max'];
1210
1211
				if (isset($config_var['step']))
1212
					$context['config_vars'][$config_var[1]]['step'] = $config_var['step'];
1213
			}
1214
1215
			// If this is a select box handle any data.
1216
			if (!empty($config_var[2]) && is_array($config_var[2]))
1217
			{
1218
				// If we allow multiple selections, we need to adjust a few things.
1219
				if ($config_var[0] == 'select' && !empty($config_var['multiple']))
1220
				{
1221
					$context['config_vars'][$config_var[1]]['name'] .= '[]';
1222
					$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();
1223
				}
1224
1225
				// If it's associative
1226
				if (isset($config_var[2][0]) && is_array($config_var[2][0]))
1227
					$context['config_vars'][$config_var[1]]['data'] = $config_var[2];
1228
1229
				else
1230
				{
1231
					foreach ($config_var[2] as $key => $item)
1232
						$context['config_vars'][$config_var[1]]['data'][] = array($key, $item);
1233
				}
1234
				if (empty($config_var['size']) && !empty($config_var['multiple']))
1235
					$context['config_vars'][$config_var[1]]['size'] = max(4, count($config_var[2]));
1236
			}
1237
1238
			// Finally allow overrides - and some final cleanups.
1239
			foreach ($config_var as $k => $v)
1240
			{
1241
				if (!is_numeric($k))
1242
				{
1243
					if (substr($k, 0, 2) == 'on')
1244
						$context['config_vars'][$config_var[1]]['javascript'] .= ' ' . $k . '="' . $v . '"';
1245
					else
1246
						$context['config_vars'][$config_var[1]][$k] = $v;
1247
				}
1248
1249
				// See if there are any other labels that might fit?
1250
				if (isset($txt['setting_' . $config_var[1]]))
1251
					$context['config_vars'][$config_var[1]]['label'] = $txt['setting_' . $config_var[1]];
1252
1253
				elseif (isset($txt['groups_' . $config_var[1]]))
1254
					$context['config_vars'][$config_var[1]]['label'] = $txt['groups_' . $config_var[1]];
1255
			}
1256
1257
			// Set the subtext in case it's part of the label.
1258
			// @todo Temporary. Preventing divs inside label tags.
1259
			$divPos = strpos($context['config_vars'][$config_var[1]]['label'], '<div');
1260
			if ($divPos !== false)
1261
			{
1262
				$context['config_vars'][$config_var[1]]['subtext'] = preg_replace('~</?div[^>]*>~', '', substr($context['config_vars'][$config_var[1]]['label'], $divPos));
1263
				$context['config_vars'][$config_var[1]]['label'] = substr($context['config_vars'][$config_var[1]]['label'], 0, $divPos);
1264
			}
1265
		}
1266
	}
1267
1268
	// If we have inline permissions we need to prep them.
1269
	if (!empty($inlinePermissions) && allowedTo('manage_permissions'))
1270
	{
1271
		require_once($sourcedir . '/ManagePermissions.php');
1272
		init_inline_permissions($inlinePermissions);
1273
	}
1274
1275
	if ($board_list)
1276
	{
1277
		require_once($sourcedir . '/Subs-MessageIndex.php');
1278
		$context['board_list'] = getBoardList();
1279
	}
1280
1281
	// What about any BBC selection boxes?
1282
	if (!empty($bbcChoice))
1283
	{
1284
		// What are the options, eh?
1285
		$temp = parse_bbc(false);
1286
		$bbcTags = array();
1287
		foreach ($temp as $tag)
0 ignored issues
show
Bug introduced by
The expression $temp of type string is not traversable.
Loading history...
1288
			if (!isset($tag['require_parents']))
1289
				$bbcTags[] = $tag['tag'];
1290
1291
		$bbcTags = array_unique($bbcTags);
1292
1293
		// The number of columns we want to show the BBC tags in.
1294
		$numColumns = isset($context['num_bbc_columns']) ? $context['num_bbc_columns'] : 3;
1295
1296
		// Now put whatever BBC options we may have into context too!
1297
		$context['bbc_sections'] = array();
1298
		foreach ($bbcChoice as $bbcSection)
1299
		{
1300
			$context['bbc_sections'][$bbcSection] = array(
1301
				'title' => isset($txt['bbc_title_' . $bbcSection]) ? $txt['bbc_title_' . $bbcSection] : $txt['enabled_bbc_select'],
1302
				'disabled' => empty($modSettings['bbc_disabled_' . $bbcSection]) ? array() : $modSettings['bbc_disabled_' . $bbcSection],
1303
				'all_selected' => empty($modSettings['bbc_disabled_' . $bbcSection]),
1304
				'columns' => array(),
1305
			);
1306
1307
			if ($bbcSection == 'legacyBBC')
1308
				$sectionTags = array_intersect($context['legacy_bbc'], $bbcTags);
1309
			else
1310
				$sectionTags = array_diff($bbcTags, $context['legacy_bbc']);
1311
1312
			$totalTags = count($sectionTags);
1313
			$tagsPerColumn = ceil($totalTags / $numColumns);
1314
1315
			$col = 0;
1316
			$i = 0;
1317
			foreach ($sectionTags as $tag)
1318
			{
1319
				if ($i % $tagsPerColumn == 0 && $i != 0)
1320
					$col++;
1321
1322
				$context['bbc_sections'][$bbcSection]['columns'][$col][] = array(
1323
					'tag' => $tag,
1324
					// @todo  'tag_' . ?
1325
					'show_help' => isset($helptxt[$tag]),
1326
				);
1327
1328
				$i++;
1329
			}
1330
		}
1331
	}
1332
1333
	call_integration_hook('integrate_prepare_db_settings', array(&$config_vars));
1334
	createToken('admin-dbsc');
1335
}
1336
1337
/**
1338
 * Helper function. Saves settings by putting them in Settings.php or saving them in the settings table.
1339
 *
1340
 * - Saves those settings set from ?action=admin;area=serversettings.
1341
 * - Requires the admin_forum permission.
1342
 * - Contains arrays of the types of data to save into Settings.php.
1343
 *
1344
 * @param array $config_vars An array of configuration variables
1345
 */
1346
function saveSettings(&$config_vars)
1347
{
1348
	global $sourcedir, $context;
1349
1350
	validateToken('admin-ssc');
1351
1352
	// Fix the darn stupid cookiename! (more may not be allowed, but these for sure!)
1353
	if (isset($_POST['cookiename']))
1354
		$_POST['cookiename'] = preg_replace('~[,;\s\.$]+~' . ($context['utf8'] ? 'u' : ''), '', $_POST['cookiename']);
1355
1356
	// Fix the forum's URL if necessary.
1357
	if (isset($_POST['boardurl']))
1358
	{
1359
		if (substr($_POST['boardurl'], -10) == '/index.php')
1360
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
1361
		elseif (substr($_POST['boardurl'], -1) == '/')
1362
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
1363
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
1364
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
1365
	}
1366
1367
	// Any passwords?
1368
	$config_passwords = array(
1369
		'db_passwd',
1370
		'ssi_db_passwd',
1371
	);
1372
1373
	// All the strings to write.
1374
	$config_strs = array(
1375
		'mtitle', 'mmessage',
1376
		'language', 'mbname', 'boardurl',
1377
		'cookiename',
1378
		'webmaster_email',
1379
		'db_name', 'db_user', 'db_server', 'db_prefix', 'ssi_db_user',
1380
		'boarddir', 'sourcedir',
1381
		'cachedir', 'cachedir_sqlite', 'cache_accelerator', 'cache_memcached',
1382
		'image_proxy_secret',
1383
	);
1384
1385
	// All the numeric variables.
1386
	$config_ints = array(
1387
		'db_port',
1388
		'cache_enable',
1389
		'image_proxy_maxsize',
1390
	);
1391
1392
	// All the checkboxes
1393
	$config_bools = array('db_persist', 'db_error_send', 'maintenance', 'image_proxy_enabled');
1394
1395
	// Now sort everything into a big array, and figure out arrays and etc.
1396
	$new_settings = array();
1397
	// Figure out which config vars we're saving here...
1398
	foreach ($config_vars as $var)
1399
	{
1400
		if (!is_array($var) || $var[2] != 'file' || (!in_array($var[0], $config_bools) && !isset($_POST[$var[0]])))
1401
			continue;
1402
1403
		$config_var = $var[0];
1404
1405
		if (in_array($config_var, $config_passwords))
1406
		{
1407
			if (isset($_POST[$config_var][1]) && $_POST[$config_var][0] == $_POST[$config_var][1])
1408
				$new_settings[$config_var] = $_POST[$config_var][0];
1409
		}
1410
		elseif (in_array($config_var, $config_strs))
1411
		{
1412
			$new_settings[$config_var] = $_POST[$config_var];
1413
		}
1414
		elseif (in_array($config_var, $config_ints))
1415
		{
1416
			$new_settings[$config_var] = (int) $_POST[$config_var];
1417
1418
			// 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...
1419
			$min = isset($var['min']) ? $var['min'] : 0;
1420
			$new_settings[$config_var] = max($min, $new_settings[$config_var]);
1421
1422
			// Is there a max value for this as well?
1423
			if (isset($var['max']))
1424
				$new_settings[$config_var] = min($var['max'], $new_settings[$config_var]);
1425
		}
1426
		elseif (in_array($config_var, $config_bools))
1427
		{
1428
			if (!empty($_POST[$config_var]))
1429
				$new_settings[$config_var] = 1;
1430
			else
1431
				$new_settings[$config_var] = 0;
1432
		}
1433
		else
1434
		{
1435
			// This shouldn't happen, but it might...
1436
			fatal_error('Unknown config_var \'' . $config_var . '\'');
1437
		}
1438
	}
1439
1440
	// Save the relevant settings in the Settings.php file.
1441
	require_once($sourcedir . '/Subs-Admin.php');
1442
	updateSettingsFile($new_settings);
1443
1444
	// Now loop through the remaining (database-based) settings.
1445
	$new_settings = array();
1446
	foreach ($config_vars as $config_var)
1447
	{
1448
		// We just saved the file-based settings, so skip their definitions.
1449
		if (!is_array($config_var) || $config_var[2] == 'file')
1450
			continue;
1451
1452
		$new_setting = array($config_var[3], $config_var[0]);
1453
1454
		// Select options need carried over, too.
1455
		if (isset($config_var[4]))
1456
			$new_setting[] = $config_var[4];
1457
1458
		// Include min and max if necessary
1459
		if (isset($config_var['min']))
1460
			$new_setting['min'] = $config_var['min'];
1461
1462
		if (isset($config_var['max']))
1463
			$new_setting['max'] = $config_var['max'];
1464
1465
		// Rewrite the definition a bit.
1466
		$new_settings[] = $new_setting;
1467
	}
1468
1469
	// Save the new database-based settings, if any.
1470
	if (!empty($new_settings))
1471
		saveDBSettings($new_settings);
1472
}
1473
1474
/**
1475
 * Helper function for saving database settings.
1476
 *
1477
 * @todo see rev. 10406 from 2.1-requests
1478
 *
1479
 * @param array $config_vars An array of configuration variables
1480
 */
1481
function saveDBSettings(&$config_vars)
1482
{
1483
	global $sourcedir, $smcFunc;
1484
	static $board_list = null;
1485
1486
	validateToken('admin-dbsc');
1487
1488
	$inlinePermissions = array();
1489
	foreach ($config_vars as $var)
1490
	{
1491
		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']))))
1492
			continue;
1493
1494
		// Checkboxes!
1495
		elseif ($var[0] == 'check')
1496
			$setArray[$var[1]] = !empty($_POST[$var[1]]) ? '1' : '0';
1497
		// Select boxes!
1498
		elseif ($var[0] == 'select' && in_array($_POST[$var[1]], array_keys($var[2])))
1499
			$setArray[$var[1]] = $_POST[$var[1]];
1500
		elseif ($var[0] == 'select' && !empty($var['multiple']) && array_intersect($_POST[$var[1]], array_keys($var[2])) != array())
1501
		{
1502
			// For security purposes we validate this line by line.
1503
			$lOptions = array();
1504
			foreach ($_POST[$var[1]] as $invar)
1505
				if (in_array($invar, array_keys($var[2])))
1506
					$lOptions[] = $invar;
1507
1508
			$setArray[$var[1]] = $smcFunc['json_encode']($lOptions);
1509
		}
1510
		// List of boards!
1511
		elseif ($var[0] == 'boards')
1512
		{
1513
			// We just need a simple list of valid boards, nothing more.
1514
			if ($board_list === null)
1515
			{
1516
				$board_list = array();
1517
				$request = $smcFunc['db_query']('', '
1518
					SELECT id_board
1519
					FROM {db_prefix}boards');
1520
1521
				while ($row = $smcFunc['db_fetch_row']($request))
1522
					$board_list[$row[0]] = true;
1523
1524
				$smcFunc['db_free_result']($request);
1525
			}
1526
1527
			$lOptions = array();
1528
1529
			if (!empty($_POST[$var[1]]))
1530
				foreach ($_POST[$var[1]] as $invar => $dummy)
1531
					if (isset($board_list[$invar]))
1532
						$lOptions[] = $invar;
1533
1534
			$setArray[$var[1]] = !empty($lOptions) ? implode(',', $lOptions) : '';
1535
		}
1536
		// Integers!
1537
		elseif ($var[0] == 'int')
1538
		{
1539
			$setArray[$var[1]] = (int) $_POST[$var[1]];
1540
1541
			// 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...
1542
			$min = isset($var['min']) ? $var['min'] : 0;
1543
			$setArray[$var[1]] = max($min, $setArray[$var[1]]);
1544
1545
			// Do we have a max value for this as well?
1546
			if (isset($var['max']))
1547
				$setArray[$var[1]] = min($var['max'], $setArray[$var[1]]);
1548
		}
1549
		// Floating point!
1550
		elseif ($var[0] == 'float')
1551
		{
1552
			$setArray[$var[1]] = (float) $_POST[$var[1]];
1553
1554
			// 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...
1555
			$min = isset($var['min']) ? $var['min'] : 0;
1556
			$setArray[$var[1]] = max($min, $setArray[$var[1]]);
1557
1558
			// Do we have a max value for this as well?
1559
			if (isset($var['max']))
1560
				$setArray[$var[1]] = min($var['max'], $setArray[$var[1]]);
1561
		}
1562
		// Text!
1563
		elseif (in_array($var[0], array('text', 'large_text', 'color', 'date', 'datetime', 'datetime-local', 'email', 'month', 'time')))
1564
			$setArray[$var[1]] = $_POST[$var[1]];
1565
		// Passwords!
1566
		elseif ($var[0] == 'password')
1567
		{
1568
			if (isset($_POST[$var[1]][1]) && $_POST[$var[1]][0] == $_POST[$var[1]][1])
1569
				$setArray[$var[1]] = $_POST[$var[1]][0];
1570
		}
1571
		// BBC.
1572
		elseif ($var[0] == 'bbc')
1573
		{
1574
			$bbcTags = array();
1575
			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...
1576
				$bbcTags[] = $tag['tag'];
1577
1578
			if (!isset($_POST[$var[1] . '_enabledTags']))
1579
				$_POST[$var[1] . '_enabledTags'] = array();
1580
			elseif (!is_array($_POST[$var[1] . '_enabledTags']))
1581
				$_POST[$var[1] . '_enabledTags'] = array($_POST[$var[1] . '_enabledTags']);
1582
1583
			$setArray[$var[1]] = implode(',', array_diff($bbcTags, $_POST[$var[1] . '_enabledTags']));
1584
		}
1585
		// Permissions?
1586
		elseif ($var[0] == 'permissions')
1587
			$inlinePermissions[] = $var[1];
1588
	}
1589
1590
	if (!empty($setArray))
1591
		updateSettings($setArray);
1592
1593
	// If we have inline permissions we need to save them.
1594
	if (!empty($inlinePermissions) && allowedTo('manage_permissions'))
1595
	{
1596
		require_once($sourcedir . '/ManagePermissions.php');
1597
		save_inline_permissions($inlinePermissions);
1598
	}
1599
}
1600
1601
/**
1602
 * Allows us to see the servers php settings
1603
 *
1604
 * - loads the settings into an array for display in a template
1605
 * - drops cookie values just in case
1606
 */
1607
function ShowPHPinfoSettings()
1608
{
1609
	global $context, $txt;
1610
1611
	$category = $txt['phpinfo_settings'];
1612
1613
	// get the data
1614
	ob_start();
1615
	phpinfo();
1616
1617
	// We only want it for its body, pigs that we are
1618
	$info_lines = preg_replace('~^.*<body>(.*)</body>.*$~', '$1', ob_get_contents());
1619
	$info_lines = explode("\n", strip_tags($info_lines, "<tr><td><h2>"));
1620
	ob_end_clean();
1621
1622
	// remove things that could be considered sensitive
1623
	$remove = '_COOKIE|Cookie|_GET|_REQUEST|REQUEST_URI|QUERY_STRING|REQUEST_URL|HTTP_REFERER';
1624
1625
	// put all of it into an array
1626
	foreach ($info_lines as $line)
1627
	{
1628
		if (preg_match('~(' . $remove . ')~', $line))
1629
			continue;
1630
1631
		// new category?
1632
		if (strpos($line, '<h2>') !== false)
1633
			$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...
1634
1635
		// load it as setting => value or the old setting local master
1636
		if (preg_match('~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~', $line, $val))
1637
			$pinfo[$category][$val[1]] = $val[2];
1638
		elseif (preg_match('~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~', $line, $val))
1639
			$pinfo[$category][$val[1]] = array($txt['phpinfo_localsettings'] => $val[2], $txt['phpinfo_defaultsettings'] => $val[3]);
1640
	}
1641
1642
	// load it in to context and display it
1643
	$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...
1644
	$context['page_title'] = $txt['admin_server_settings'];
1645
	$context['sub_template'] = 'php_info';
1646
	return;
1647
}
1648
1649
/**
1650
 * Get the installed Cache API implementations.
1651
 *
1652
 */
1653
function loadCacheAPIs()
1654
{
1655
	global $sourcedir;
1656
1657
	$cacheAPIdir = $sourcedir . '/Cache';
1658
1659
	$loadedApis = array();
1660
	$apis_dir = $cacheAPIdir .'/'. CacheApi::APIS_FOLDER;
1661
1662
	$api_classes = new GlobIterator($apis_dir . '/*.php', FilesystemIterator::NEW_CURRENT_AND_KEY);
1663
1664
	foreach ($api_classes as $file_path => $file_info)
1665
	{
1666
		require_once($apis_dir . '/' . $file_path);
1667
1668
		$class_name = $file_info->getBasename('.php');
1669
		$fully_qualified_class_name = CacheApi::APIS_NAMESPACE . $class_name;
1670
1671
		/* @var CacheApiInterface $cache_api */
1672
		$cache_api = new $fully_qualified_class_name();
1673
1674
		// Deal with it!
1675
		if (!($cache_api instanceof CacheApiInterface) || !($cache_api instanceof CacheApi))
1676
			continue;
1677
1678
		// No Support?  NEXT!
1679
		if (!$cache_api->isSupported(true))
1680
			continue;
1681
1682
		$loadedApis[$class_name] = $cache_api;
1683
	}
1684
1685
	call_integration_hook('integrate_load_cache_apis', array(&$loadedApis));
1686
1687
	return $loadedApis;
1688
}
1689
1690
/**
1691
 * Registers the site with the Simple Machines Stat collection. This function
1692
 * purposely does not use updateSettings.php as it will be called shortly after
1693
 * this process completes by the saveSettings() function.
1694
 *
1695
 * @see Stats.php SMStats() for more information.
1696
 * @link https://www.simplemachines.org/about/stats.php for more info.
1697
 *
1698
 */
1699
function registerSMStats()
1700
{
1701
	global $modSettings, $boardurl, $smcFunc;
1702
1703
	// Already have a key?  Can't register again.
1704
	if (!empty($modSettings['sm_stats_key']))
1705
		return true;
1706
1707
	$fp = @fsockopen('www.simplemachines.org', 443, $errno, $errstr);
1708
	if (!$fp)
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
1709
		$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
1710
	if ($fp)
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
1711
	{
1712
		$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
1713
		$out .= 'Host: www.simplemachines.org' . "\r\n";
1714
		$out .= 'Connection: Close' . "\r\n\r\n";
1715
		fwrite($fp, $out);
1716
1717
		$return_data = '';
1718
		while (!feof($fp))
1719
			$return_data .= fgets($fp, 128);
1720
1721
		fclose($fp);
1722
1723
		// Get the unique site ID.
1724
		preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1725
1726
		if (!empty($ID[1]))
1727
		{
1728
			$smcFunc['db_insert']('replace',
1729
				'{db_prefix}settings',
1730
				array('variable' => 'string', 'value' => 'string'),
1731
				array('sm_stats_key', $ID[1]),
1732
				array('variable')
1733
			);
1734
			return true;
1735
		}
1736
	}
1737
1738
	return false;
1739
}
1740
1741
?>