VerificationCode()   C
last analyzed

Complexity

Conditions 17

Size

Total Lines 63
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
eloc 30
c 0
b 0
f 0
nop 0
dl 0
loc 63
rs 5.2166

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
 * This file has two main jobs, but they really are one.  It registers new
5
 * members, and it helps the administrator moderate member registrations.
6
 * Similarly, it handles account activation as well.
7
 *
8
 * Simple Machines Forum (SMF)
9
 *
10
 * @package SMF
11
 * @author Simple Machines https://www.simplemachines.org
12
 * @copyright 2022 Simple Machines and individual contributors
13
 * @license https://www.simplemachines.org/about/smf/license.php BSD
14
 *
15
 * @version 2.1.2
16
 */
17
18
if (!defined('SMF'))
19
	die('No direct access...');
20
21
/**
22
 * Begin the registration process.
23
 *
24
 * @param array $reg_errors Holds information about any errors that occurred
25
 */
26
function Register($reg_errors = array())
27
{
28
	global $txt, $boarddir, $context, $modSettings, $user_info;
29
	global $language, $scripturl, $smcFunc, $sourcedir, $cur_profile;
30
31
	// Is this an incoming AJAX check?
32
	if (isset($_GET['sa']) && $_GET['sa'] == 'usernamecheck')
33
		return RegisterCheckUsername();
34
35
	// Check if the administrator has it disabled.
36
	if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == '3')
37
		fatal_lang_error('registration_disabled', false);
38
39
	// If this user is an admin - redirect them to the admin registration page.
40
	if (allowedTo('moderate_forum') && !$user_info['is_guest'])
41
		redirectexit('action=admin;area=regcenter;sa=register');
42
	// You are not a guest, so you are a member - and members don't get to register twice!
43
	elseif (empty($user_info['is_guest']))
44
		redirectexit();
45
46
	loadLanguage('Login');
47
	loadTemplate('Register');
48
49
	// How many steps have we done so far today?
50
	$current_step = isset($_REQUEST['step']) ? (int) $_REQUEST['step'] : (!empty($modSettings['requireAgreement']) || !empty($modSettings['requirePolicyAgreement']) ? 1 : 2);
51
52
	// Do we need them to agree to the registration agreement and/or privacy policy agreement, first?
53
	$context['registration_passed_agreement'] = !empty($_SESSION['registration_agreed']);
54
	$context['show_coppa'] = !empty($modSettings['coppaAge']);
55
56
	$agree_txt_key = '';
57
	if ($current_step == 1)
58
	{
59
		if (!empty($modSettings['requireAgreement']) && !empty($modSettings['requirePolicyAgreement']))
60
			$agree_txt_key = 'agreement_policy_';
61
		elseif (!empty($modSettings['requireAgreement']))
62
			$agree_txt_key = 'agreement_';
63
		elseif (!empty($modSettings['requirePolicyAgreement']))
64
			$agree_txt_key = 'policy_';
65
	}
66
67
	// Under age restrictions?
68
	if ($context['show_coppa'])
69
	{
70
		$context['skip_coppa'] = false;
71
		$context['coppa_agree_above'] = sprintf($txt[$agree_txt_key . 'agree_coppa_above'], $modSettings['coppaAge']);
72
		$context['coppa_agree_below'] = sprintf($txt[$agree_txt_key . 'agree_coppa_below'], $modSettings['coppaAge']);
73
	}
74
	elseif ($agree_txt_key != '')
75
		$context['agree'] = $txt[$agree_txt_key . 'agree'];
76
77
	// Does this user agree to the registation agreement?
78
	if ($current_step == 1 && (isset($_POST['accept_agreement']) || isset($_POST['accept_agreement_coppa'])))
79
	{
80
		$context['registration_passed_agreement'] = $_SESSION['registration_agreed'] = true;
81
		$current_step = 2;
82
83
		// Skip the coppa procedure if the user says he's old enough.
84
		if ($context['show_coppa'])
85
		{
86
			$_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']);
87
88
			// Are they saying they're under age, while under age registration is disabled?
89
			if (empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
90
			{
91
				loadLanguage('Login');
92
				fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
93
			}
94
		}
95
	}
96
	// Make sure they don't squeeze through without agreeing.
97
	elseif ($current_step > 1 && (!empty($modSettings['requireAgreement']) || !empty($modSettings['requirePolicyAgreement'])) && !$context['registration_passed_agreement'])
98
		$current_step = 1;
99
100
	// Show the user the right form.
101
	$context['sub_template'] = $current_step == 1 ? 'registration_agreement' : 'registration_form';
102
	$context['page_title'] = $current_step == 1 ? $txt['registration_agreement'] : $txt['registration_form'];
103
104
	// Kinda need this.
105
	if ($context['sub_template'] == 'registration_form')
106
		loadJavaScriptFile('register.js', array('defer' => false, 'minimize' => true), 'smf_register');
107
108
	// Add the register chain to the link tree.
109
	$context['linktree'][] = array(
110
		'url' => $scripturl . '?action=signup',
111
		'name' => $txt['register'],
112
	);
113
114
	// Prepare the time gate! Do it like so, in case later steps want to reset the limit for any reason, but make sure the time is the current one.
115
	if (!isset($_SESSION['register']))
116
		$_SESSION['register'] = array(
117
			'timenow' => time(),
118
			'limit' => 10, // minimum number of seconds required on this page for registration
119
		);
120
	else
121
		$_SESSION['register']['timenow'] = time();
122
123
	// If you have to agree to the agreement, it needs to be fetched from the file.
124
	if (!empty($modSettings['requireAgreement']))
125
	{
126
		// Have we got a localized one?
127
		if (file_exists($boarddir . '/agreement.' . $user_info['language'] . '.txt'))
128
			$context['agreement'] = parse_bbc(file_get_contents($boarddir . '/agreement.' . $user_info['language'] . '.txt'), true, 'agreement_' . $user_info['language']);
129
		elseif (file_exists($boarddir . '/agreement.txt'))
130
			$context['agreement'] = parse_bbc(file_get_contents($boarddir . '/agreement.txt'), true, 'agreement');
131
		else
132
			$context['agreement'] = '';
133
134
		// Nothing to show, lets disable registration and inform the admin of this error
135
		if (empty($context['agreement']))
136
		{
137
			// No file found or a blank file, log the error so the admin knows there is a problem!
138
			log_error($txt['registration_agreement_missing'], 'critical');
139
			fatal_lang_error('registration_disabled', false);
140
		}
141
	}
142
143
	require_once($sourcedir . '/Subs-Notify.php');
144
	$prefs = getNotifyPrefs(0, 'announcements');
145
	$context['notify_announcements'] = !empty($prefs[0]['announcements']);
146
147
	if (!empty($modSettings['userLanguage']))
148
	{
149
		$selectedLanguage = empty($_SESSION['language']) ? $language : $_SESSION['language'];
150
151
		// Do we have any languages?
152
		if (empty($context['languages']))
153
			getLanguages();
154
155
		// Try to find our selected language.
156
		foreach ($context['languages'] as $key => $lang)
157
		{
158
			$context['languages'][$key]['name'] = strtr($lang['name'], array('-utf8' => ''));
159
160
			// Found it!
161
			if ($selectedLanguage == $lang['filename'])
162
				$context['languages'][$key]['selected'] = true;
163
		}
164
	}
165
166
	// If you have to agree to the privacy policy, it needs to be loaded from the database.
167
	if (!empty($modSettings['requirePolicyAgreement']))
168
	{
169
		// Have we got a localized one?
170
		if (!empty($modSettings['policy_' . $user_info['language']]))
171
			$context['privacy_policy'] = parse_bbc($modSettings['policy_' . $user_info['language']]);
172
		elseif (!empty($modSettings['policy_' . $language]))
173
			$context['privacy_policy'] = parse_bbc($modSettings['policy_' . $language]);
174
		else
175
		{
176
			// None was found; log the error so the admin knows there is a problem!
177
			log_error($txt['registration_policy_missing'], 'critical');
178
			fatal_lang_error('registration_disabled', false);
179
		}
180
	}
181
182
	// Any custom fields we want filled in?
183
	require_once($sourcedir . '/Profile.php');
184
	loadCustomFields(0, 'register');
185
186
	// Or any standard ones?
187
	if (!empty($modSettings['registration_fields']))
188
	{
189
		require_once($sourcedir . '/Profile-Modify.php');
190
191
		// Setup some important context.
192
		loadLanguage('Profile');
193
		loadTemplate('Profile');
194
195
		$context['user']['is_owner'] = true;
196
197
		// Here, and here only, emulate the permissions the user would have to do this.
198
		$user_info['permissions'] = array_merge($user_info['permissions'], array('profile_account_own', 'profile_extra_own', 'profile_other_own', 'profile_password_own', 'profile_website_own', 'profile_blurb'));
199
		$reg_fields = explode(',', $modSettings['registration_fields']);
200
201
		// Website is a little different
202
		if (in_array('website', $reg_fields))
203
		{
204
			unset($reg_fields['website']);
205
			if (isset($_POST['website_title']))
206
				$cur_profile['website_title'] = $smcFunc['htmlspecialchars']($_POST['website_title']);
207
			if (isset($_POST['website_url']))
208
				$cur_profile['website_url'] = $smcFunc['htmlspecialchars']($_POST['website_url']);
209
		}
210
211
		// We might have had some submissions on this front - go check.
212
		foreach ($reg_fields as $field)
213
			if (isset($_POST[$field]))
214
				$cur_profile[$field] = $smcFunc['htmlspecialchars']($_POST[$field]);
215
216
		// Load all the fields in question.
217
		setupProfileContext($reg_fields);
218
	}
219
220
	// Generate a visual verification code to make sure the user is no bot.
221
	if (!empty($modSettings['reg_verification']))
222
	{
223
		require_once($sourcedir . '/Subs-Editor.php');
224
		$verificationOptions = array(
225
			'id' => 'register',
226
		);
227
		$context['visual_verification'] = create_control_verification($verificationOptions);
228
		$context['visual_verification_id'] = $verificationOptions['id'];
229
	}
230
	// Otherwise we have nothing to show.
231
	else
232
		$context['visual_verification'] = false;
233
234
	$context += array(
235
		'username' => isset($_POST['user']) ? $smcFunc['htmlspecialchars']($_POST['user']) : '',
236
		'email' => isset($_POST['email']) ? $smcFunc['htmlspecialchars']($_POST['email']) : '',
237
		'notify_announcements' => !empty($_POST['notify_announcements']) ? 1 : 0,
238
	);
239
240
	// Were there any errors?
241
	$context['registration_errors'] = array();
242
	if (!empty($reg_errors))
243
		$context['registration_errors'] = $reg_errors;
244
245
	createToken('register');
246
}
247
248
/**
249
 * Actually register the member.
250
 */
251
function Register2()
252
{
253
	global $txt, $modSettings, $context, $sourcedir;
254
	global $smcFunc, $maintenance;
255
256
	checkSession();
257
	validateToken('register');
258
259
	// Check to ensure we're forcing SSL for authentication
260
	if (!empty($modSettings['force_ssl']) && empty($maintenance) && !httpsOn())
261
		fatal_lang_error('register_ssl_required');
262
263
	// Start collecting together any errors.
264
	$reg_errors = array();
265
266
	// You can't register if it's disabled.
267
	if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3)
268
		fatal_lang_error('registration_disabled', false);
269
270
	// Well, if you don't agree, you can't register.
271
	if ((!empty($modSettings['requireAgreement']) || !empty($modSettings['requirePolicyAgreement'])) && empty($_SESSION['registration_agreed']))
272
		redirectexit();
273
274
	// Make sure they came from *somewhere*, have a session.
275
	if (!isset($_SESSION['old_url']))
276
		redirectexit('action=signup');
277
278
	// If we require neither an agreement nor a privacy policy, we need a extra check for coppa.
279
	if (empty($modSettings['requireAgreement']) && empty($modSettings['requirePolicyAgreement']) && !empty($modSettings['coppaAge']))
280
		$_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']);
281
282
	// Are they under age, and under age users are banned?
283
	if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
284
	{
285
		loadLanguage('Errors');
286
		fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
287
	}
288
289
	// Check the time gate for miscreants. First make sure they came from somewhere that actually set it up.
290
	if (empty($_SESSION['register']['timenow']) || empty($_SESSION['register']['limit']))
291
		redirectexit('action=signup');
292
	// Failing that, check the time on it.
293
	if (time() - $_SESSION['register']['timenow'] < $_SESSION['register']['limit'])
294
	{
295
		loadLanguage('Errors');
296
		$reg_errors[] = $txt['error_too_quickly'];
297
	}
298
299
	// Check whether the visual verification code was entered correctly.
300
	if (!empty($modSettings['reg_verification']))
301
	{
302
		require_once($sourcedir . '/Subs-Editor.php');
303
		$verificationOptions = array(
304
			'id' => 'register',
305
		);
306
		$context['visual_verification'] = create_control_verification($verificationOptions, true);
307
308
		if (is_array($context['visual_verification']))
309
		{
310
			loadLanguage('Errors');
311
			foreach ($context['visual_verification'] as $error)
312
				$reg_errors[] = $txt['error_' . $error];
313
		}
314
	}
315
316
	array_walk_recursive(
317
		$_POST,
318
		function (&$value, $key) use ($context, $smcFunc)
0 ignored issues
show
Unused Code introduced by
The import $context is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
319
		{
320
			// Normalize Unicode characters. (Does nothing if not in UTF-8 mode.)
321
			$value = $smcFunc['normalize']($value);
322
323
			// Replace any kind of space or illegal character with a normal space, and then trim.
324
			$value = $smcFunc['htmltrim'](normalize_spaces(sanitize_chars($value, 1, ' '), true, true, array('no_breaks' => true, 'replace_tabs' => true, 'collapse_hspace' => true)));
325
		}
326
	);
327
328
	// Collect all extra registration fields someone might have filled in.
329
	$possible_strings = array(
330
		'birthdate',
331
		'timezone',
332
		'buddy_list',
333
		'pm_ignore_list',
334
		'smiley_set',
335
		'personal_text', 'avatar',
336
		'lngfile',
337
		'secret_question', 'secret_answer',
338
	);
339
	$possible_ints = array(
340
		'id_theme',
341
	);
342
	$possible_floats = array(
343
		'time_offset',
344
	);
345
	$possible_bools = array(
346
		'show_online',
347
	);
348
349
	// We may want to add certain things to these if selected in the admin panel.
350
	if (!empty($modSettings['registration_fields']))
351
	{
352
		$reg_fields = explode(',', $modSettings['registration_fields']);
353
354
		// Website is a little different
355
		if (in_array('website', $reg_fields))
356
		{
357
			$possible_strings = array_merge(array('website_url', 'website_title'), $possible_strings);
358
359
			// Make sure their website URL is squeaky clean
360
			if (isset($_POST['website_url']))
361
				$_POST['website_url'] = (string) validate_iri(normalize_iri($_POST['website_url']));
362
		}
363
	}
364
365
	if (isset($_POST['secret_answer']) && $_POST['secret_answer'] != '')
366
		$_POST['secret_answer'] = md5($_POST['secret_answer']);
367
368
	// Needed for isReservedName() and registerMember().
369
	require_once($sourcedir . '/Subs-Members.php');
370
371
	// Maybe you want set the displayed name during registration
372
	if (isset($_POST['real_name']))
373
	{
374
		// Are you already allowed to edit the displayed name?
375
		if (allowedTo('profile_displayed_name') || allowedTo('moderate_forum'))
376
			$canEditDisplayName = true;
377
378
		// If you are a guest, will you be allowed to once you register?
379
		else
380
		{
381
			$request = $smcFunc['db_query']('', '
382
				SELECT add_deny
383
				FROM {db_prefix}permissions
384
				WHERE id_group = {int:id_group} AND permission = {string:permission}',
385
				array(
386
					'id_group' => 0,
387
					'permission' => 'profile_displayed_name_own',
388
				)
389
			);
390
			list($canEditDisplayName) = $smcFunc['db_fetch_row']($request);
391
			$smcFunc['db_free_result']($request);
392
		}
393
394
		// Only set it if you can and if we are sure it is good
395
		if ($canEditDisplayName && $smcFunc['htmltrim']($_POST['real_name']) != '' && !isReservedName($_POST['real_name']) && $smcFunc['strlen']($_POST['real_name']) < 60)
396
			$possible_strings[] = 'real_name';
397
	}
398
399
	// Handle a string as a birthdate...
400
	if (isset($_POST['birthdate']) && $_POST['birthdate'] != '')
401
		$_POST['birthdate'] = smf_strftime('%Y-%m-%d', strtotime($_POST['birthdate']));
402
	// Or birthdate parts...
403
	elseif (!empty($_POST['bday1']) && !empty($_POST['bday2']))
404
		$_POST['birthdate'] = sprintf('%04d-%02d-%02d', empty($_POST['bday3']) ? 0 : (int) $_POST['bday3'], (int) $_POST['bday1'], (int) $_POST['bday2']);
405
406
	// Validate the passed language file.
407
	if (isset($_POST['lngfile']) && !empty($modSettings['userLanguage']))
408
	{
409
		// Do we have any languages?
410
		if (empty($context['languages']))
411
			getLanguages();
412
413
		// Did we find it?
414
		if (isset($context['languages'][$_POST['lngfile']]))
415
			$_SESSION['language'] = $_POST['lngfile'];
416
		else
417
			unset($_POST['lngfile']);
418
	}
419
	else
420
		unset($_POST['lngfile']);
421
422
	// Set the options needed for registration.
423
	$regOptions = array(
424
		'interface' => 'guest',
425
		'username' => !empty($_POST['user']) ? $_POST['user'] : '',
426
		'email' => !empty($_POST['email']) ? $_POST['email'] : '',
427
		'password' => !empty($_POST['passwrd1']) ? $_POST['passwrd1'] : '',
428
		'password_check' => !empty($_POST['passwrd2']) ? $_POST['passwrd2'] : '',
429
		'check_reserved_name' => true,
430
		'check_password_strength' => true,
431
		'check_email_ban' => true,
432
		'send_welcome_email' => !empty($modSettings['send_welcomeEmail']),
433
		'require' => !empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')),
434
		'extra_register_vars' => array(),
435
		'theme_vars' => array(),
436
	);
437
438
	// Include the additional options that might have been filled in.
439
	foreach ($possible_strings as $var)
440
		if (isset($_POST[$var]))
441
			$regOptions['extra_register_vars'][$var] = $smcFunc['htmlspecialchars']($_POST[$var], ENT_QUOTES);
442
	foreach ($possible_ints as $var)
443
		if (isset($_POST[$var]))
444
			$regOptions['extra_register_vars'][$var] = (int) $_POST[$var];
445
	foreach ($possible_floats as $var)
446
		if (isset($_POST[$var]))
447
			$regOptions['extra_register_vars'][$var] = (float) $_POST[$var];
448
	foreach ($possible_bools as $var)
449
		if (isset($_POST[$var]))
450
			$regOptions['extra_register_vars'][$var] = empty($_POST[$var]) ? 0 : 1;
451
452
	// Registration options are always default options...
453
	if (isset($_POST['default_options']))
454
		$_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
455
	$regOptions['theme_vars'] = isset($_POST['options']) && is_array($_POST['options']) ? $_POST['options'] : array();
456
457
	// Note when they accepted the agreement and privacy policy
458
	if (!empty($modSettings['requireAgreement']))
459
		$regOptions['theme_vars']['agreement_accepted'] = time();
460
	if (!empty($modSettings['requirePolicyAgreement']))
461
		$regOptions['theme_vars']['policy_accepted'] = time();
462
463
	// Make sure they are clean, dammit!
464
	$regOptions['theme_vars'] = htmlspecialchars__recursive($regOptions['theme_vars']);
465
466
	// Check whether we have fields that simply MUST be displayed?
467
	$request = $smcFunc['db_query']('', '
468
		SELECT col_name, field_name, field_type, field_length, mask, show_reg
469
		FROM {db_prefix}custom_fields
470
		WHERE active = {int:is_active}
471
		ORDER BY field_order',
472
		array(
473
			'is_active' => 1,
474
		)
475
	);
476
	$custom_field_errors = array();
477
	while ($row = $smcFunc['db_fetch_assoc']($request))
478
	{
479
		// Don't allow overriding of the theme variables.
480
		if (isset($regOptions['theme_vars'][$row['col_name']]))
481
			unset($regOptions['theme_vars'][$row['col_name']]);
482
483
		// Not actually showing it then?
484
		if (!$row['show_reg'])
485
			continue;
486
487
		// Prepare the value!
488
		$value = isset($_POST['customfield'][$row['col_name']]) ? trim($_POST['customfield'][$row['col_name']]) : '';
489
490
		// We only care for text fields as the others are valid to be empty.
491
		if (!in_array($row['field_type'], array('check', 'select', 'radio')))
492
		{
493
			// Is it too long?
494
			if ($row['field_length'] && $row['field_length'] < $smcFunc['strlen']($value))
495
				$custom_field_errors[] = array('custom_field_too_long', array($row['field_name'], $row['field_length']));
496
497
			// Any masks to apply?
498
			if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none')
499
			{
500
				if ($row['mask'] == 'email' && (!filter_var($value, FILTER_VALIDATE_EMAIL) || strlen($value) > 255))
501
					$custom_field_errors[] = array('custom_field_invalid_email', array($row['field_name']));
502
				elseif ($row['mask'] == 'number' && preg_match('~[^\d]~', $value))
503
					$custom_field_errors[] = array('custom_field_not_number', array($row['field_name']));
504
				elseif (substr($row['mask'], 0, 5) == 'regex' && trim($value) != '' && preg_match(substr($row['mask'], 5), $value) === 0)
505
					$custom_field_errors[] = array('custom_field_inproper_format', array($row['field_name']));
506
			}
507
		}
508
509
		// Is this required but not there?
510
		if (trim($value) == '' && $row['show_reg'] > 1)
511
			$custom_field_errors[] = array('custom_field_empty', array($row['field_name']));
512
	}
513
	$smcFunc['db_free_result']($request);
514
515
	// Process any errors.
516
	if (!empty($custom_field_errors))
517
	{
518
		loadLanguage('Errors');
519
		foreach ($custom_field_errors as $error)
520
			$reg_errors[] = vsprintf($txt['error_' . $error[0]], (array) $error[1]);
521
	}
522
523
	// Lets check for other errors before trying to register the member.
524
	if (!empty($reg_errors))
525
	{
526
		$_REQUEST['step'] = 2;
527
		$_SESSION['register']['limit'] = 5; // If they've filled in some details, they won't need the full 10 seconds of the limit.
528
		return Register($reg_errors);
529
	}
530
531
	$memberID = registerMember($regOptions, true);
532
533
	// What there actually an error of some kind dear boy?
534
	if (is_array($memberID))
535
	{
536
		$reg_errors = array_merge($reg_errors, $memberID);
537
		$_REQUEST['step'] = 2;
538
		return Register($reg_errors);
539
	}
540
541
	// Do our spam protection now.
542
	spamProtection('register');
543
544
	// Do they want to receive announcements?
545
	require_once($sourcedir . '/Subs-Notify.php');
546
	$prefs = getNotifyPrefs($memberID, 'announcements', true);
547
	$var = !empty($_POST['notify_announcements']);
548
	$pref = !empty($prefs[$memberID]['announcements']);
549
550
	// Don't update if the default is the same.
551
	if ($var != $pref)
552
		setNotifyPrefs($memberID, array('announcements' => (int) !empty($_POST['notify_announcements'])));
553
554
	// We'll do custom fields after as then we get to use the helper function!
555
	if (!empty($_POST['customfield']))
556
	{
557
		require_once($sourcedir . '/Profile.php');
558
		require_once($sourcedir . '/Profile-Modify.php');
559
		makeCustomFieldChanges($memberID, 'register');
560
	}
561
562
	// If COPPA has been selected then things get complicated, setup the template.
563
	if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']))
564
		redirectexit('action=coppa;member=' . $memberID);
565
	// Basic template variable setup.
566
	elseif (!empty($modSettings['registration_method']))
567
	{
568
		loadTemplate('Register');
569
570
		$context += array(
571
			'page_title' => $txt['register'],
572
			'title' => $txt['registration_successful'],
573
			'sub_template' => 'after',
574
			'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']
575
		);
576
	}
577
	else
578
	{
579
		call_integration_hook('integrate_activate', array($regOptions['username']));
580
581
		setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash_salt($regOptions['register_vars']['passwd'], $regOptions['register_vars']['password_salt']));
582
583
		redirectexit('action=login2;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
584
	}
585
}
586
587
/**
588
 * Activate an users account.
589
 *
590
 * Checks for mail changes, resends password if needed.
591
 */
592
function Activate()
593
{
594
	global $context, $txt, $modSettings, $scripturl, $sourcedir, $smcFunc, $language, $user_info;
595
596
	// Logged in users should not bother to activate their accounts
597
	if (!empty($user_info['id']))
598
		redirectexit();
599
600
	loadLanguage('Login');
601
	loadTemplate('Login');
602
603
	if (empty($_REQUEST['u']) && empty($_POST['user']))
604
	{
605
		if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == '3')
606
			fatal_lang_error('no_access', false);
607
608
		$context['member_id'] = 0;
609
		$context['sub_template'] = 'resend';
610
		$context['page_title'] = $txt['invalid_activation_resend'];
611
		$context['can_activate'] = empty($modSettings['registration_method']) || $modSettings['registration_method'] == '1';
612
		$context['default_username'] = isset($_GET['user']) ? $_GET['user'] : '';
613
614
		return;
615
	}
616
617
	// Get the code from the database...
618
	$request = $smcFunc['db_query']('', '
619
		SELECT id_member, validation_code, member_name, real_name, email_address, is_activated, passwd, lngfile
620
		FROM {db_prefix}members' . (empty($_REQUEST['u']) ? '
621
		WHERE member_name = {string:email_address} OR email_address = {string:email_address}' : '
622
		WHERE id_member = {int:id_member}') . '
623
		LIMIT 1',
624
		array(
625
			'id_member' => isset($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0,
626
			'email_address' => isset($_POST['user']) ? $_POST['user'] : '',
627
		)
628
	);
629
630
	// Does this user exist at all?
631
	if ($smcFunc['db_num_rows']($request) == 0)
632
	{
633
		$context['sub_template'] = 'retry_activate';
634
		$context['page_title'] = $txt['invalid_userid'];
635
		$context['member_id'] = 0;
636
637
		return;
638
	}
639
640
	$row = $smcFunc['db_fetch_assoc']($request);
641
	$smcFunc['db_free_result']($request);
642
643
	// Change their email address? (they probably tried a fake one first :P.)
644
	if (!empty($_POST['new_email']) && !empty($_REQUEST['passwd']) && hash_verify_password($row['member_name'], $_REQUEST['passwd'], $row['passwd']) && ($row['is_activated'] == 0 || $row['is_activated'] == 2))
645
	{
646
		if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == 3)
647
			fatal_lang_error('no_access', false);
648
649
		if (!filter_var($_POST['new_email'], FILTER_VALIDATE_EMAIL))
650
			fatal_error(sprintf($txt['valid_email_needed'], $smcFunc['htmlspecialchars']($_POST['new_email'])), false);
651
652
		// Make sure their email isn't banned.
653
		isBannedEmail($_POST['new_email'], 'cannot_register', $txt['ban_register_prohibited']);
654
655
		// Ummm... don't even dare try to take someone else's email!!
656
		$request = $smcFunc['db_query']('', '
657
			SELECT id_member
658
			FROM {db_prefix}members
659
			WHERE email_address = {string:email_address}
660
			LIMIT 1',
661
			array(
662
				'email_address' => $_POST['new_email'],
663
			)
664
		);
665
666
		if ($smcFunc['db_num_rows']($request) != 0)
667
			fatal_lang_error('email_in_use', false, array($smcFunc['htmlspecialchars']($_POST['new_email'])));
668
		$smcFunc['db_free_result']($request);
669
670
		updateMemberData($row['id_member'], array('email_address' => $_POST['new_email']));
671
		$row['email_address'] = $_POST['new_email'];
672
673
		$email_change = true;
674
	}
675
676
	// Resend the password, but only if the account wasn't activated yet.
677
	if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'resend' && ($row['is_activated'] == 0 || $row['is_activated'] == 2) && (!isset($_REQUEST['code']) || $_REQUEST['code'] == ''))
678
	{
679
		require_once($sourcedir . '/Subs-Post.php');
680
681
		$replacements = array(
682
			'REALNAME' => $row['real_name'],
683
			'USERNAME' => $row['member_name'],
684
			'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $row['id_member'] . ';code=' . $row['validation_code'],
685
			'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $row['id_member'],
686
			'ACTIVATIONCODE' => $row['validation_code'],
687
			'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder',
688
		);
689
690
		$emaildata = loadEmailTemplate('resend_activate_message', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
691
692
		sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, 'resendact', $emaildata['is_html'], 0);
693
694
		$context['page_title'] = $txt['invalid_activation_resend'];
695
696
		// This will ensure we don't actually get an error message if it works!
697
		$context['error_title'] = $txt['invalid_activation_resend'];
698
699
		fatal_lang_error(!empty($email_change) ? 'change_email_success' : 'resend_email_success', false, array(), false);
700
	}
701
702
	// Quit if this code is not right.
703
	if (empty($_REQUEST['code']) || $row['validation_code'] != $_REQUEST['code'])
704
	{
705
		if (!empty($row['is_activated']))
706
			fatal_lang_error('already_activated', false);
707
		elseif ($row['validation_code'] == '')
708
		{
709
			loadLanguage('Profile');
710
			fatal_error(sprintf($txt['registration_not_approved'], $scripturl . '?action=activate;user=' . $row['member_name']), false);
711
		}
712
713
		$context['sub_template'] = 'retry_activate';
714
		$context['page_title'] = $txt['invalid_activation_code'];
715
		$context['member_id'] = $row['id_member'];
716
717
		return;
718
	}
719
720
	// Let the integration know that they've been activated!
721
	call_integration_hook('integrate_activate', array($row['member_name']));
722
723
	// Validation complete - update the database!
724
	updateMemberData($row['id_member'], array('is_activated' => 1, 'validation_code' => ''));
725
726
	// Also do a proper member stat re-evaluation.
727
	updateStats('member', false);
728
729
	if (!isset($_POST['new_email']))
730
	{
731
		require_once($sourcedir . '/Subs-Post.php');
732
733
		adminNotify('activation', $row['id_member'], $row['member_name']);
734
	}
735
736
	$context += array(
737
		'page_title' => $txt['registration_successful'],
738
		'sub_template' => 'login',
739
		'default_username' => $row['member_name'],
740
		'default_password' => '',
741
		'never_expire' => false,
742
		'description' => $txt['activate_success']
743
	);
744
}
745
746
/**
747
 * This function will display the contact information for the forum, as well a form to fill in.
748
 */
749
function CoppaForm()
750
{
751
	global $context, $modSettings, $txt, $smcFunc;
752
753
	loadLanguage('Login');
754
	loadTemplate('Register');
755
756
	// No User ID??
757
	if (!isset($_GET['member']))
758
		fatal_lang_error('no_access', false);
759
760
	// Get the user details...
761
	$request = $smcFunc['db_query']('', '
762
		SELECT member_name
763
		FROM {db_prefix}members
764
		WHERE id_member = {int:id_member}
765
			AND is_activated = {int:is_coppa}',
766
		array(
767
			'id_member' => (int) $_GET['member'],
768
			'is_coppa' => 5,
769
		)
770
	);
771
	if ($smcFunc['db_num_rows']($request) == 0)
772
		fatal_lang_error('no_access', false);
773
	list ($username) = $smcFunc['db_fetch_row']($request);
774
	$smcFunc['db_free_result']($request);
775
776
	if (isset($_GET['form']))
777
	{
778
		// Some simple contact stuff for the forum.
779
		$context['forum_contacts'] = (!empty($modSettings['coppaPost']) ? $modSettings['coppaPost'] . '<br><br>' : '') . (!empty($modSettings['coppaFax']) ? $modSettings['coppaFax'] . '<br>' : '');
780
		$context['forum_contacts'] = !empty($context['forum_contacts']) ? $context['forum_name_html_safe'] . '<br>' . $context['forum_contacts'] : '';
781
782
		// Showing template?
783
		if (!isset($_GET['dl']))
784
		{
785
			// Shortcut for producing underlines.
786
			$context['ul'] = '<u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</u>';
787
			$context['template_layers'] = array();
788
			$context['sub_template'] = 'coppa_form';
789
			$context['page_title'] = sprintf($txt['coppa_form_title'], $context['forum_name_html_safe']);
790
			$context['coppa_body'] = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'), array($context['ul'], $context['ul'], $username), sprintf($txt['coppa_form_body'], $context['forum_name_html_safe']));
791
		}
792
		// Downloading.
793
		else
794
		{
795
			// The data.
796
			$ul = '                ';
797
			$crlf = "\r\n";
798
			$data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . sprintf($txt['coppa_form_body'], $context['forum_name_html_safe']);
799
			$data = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br>', '<br>'), array($ul, $ul, $username, $crlf, $crlf), $data);
800
801
			// Send the headers.
802
			header('connection: close');
803
			header('content-disposition: attachment; filename="approval.txt"');
804
			header('content-type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream'));
805
			header('content-length: ' . count($data));
806
807
			echo $data;
808
			obExit(false);
809
		}
810
	}
811
	else
812
	{
813
		$context += array(
814
			'page_title' => $txt['coppa_title'],
815
			'sub_template' => 'coppa',
816
		);
817
818
		$context['coppa'] = array(
819
			'body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], sprintf($txt['coppa_after_registration'], $context['forum_name_html_safe'])),
820
			'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']),
821
			'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'],
822
			'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'],
823
			'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']),
824
			'id' => $_GET['member'],
825
		);
826
	}
827
}
828
829
/**
830
 * Show the verification code or let it be heard.
831
 */
832
function VerificationCode()
833
{
834
	global $sourcedir, $context, $scripturl;
835
836
	$verification_id = isset($_GET['vid']) ? $_GET['vid'] : '';
837
	$code = $verification_id && isset($_SESSION[$verification_id . '_vv']) ? $_SESSION[$verification_id . '_vv']['code'] : (isset($_SESSION['visual_verification_code']) ? $_SESSION['visual_verification_code'] : '');
838
839
	// Somehow no code was generated or the session was lost.
840
	if (empty($code))
841
	{
842
		header('content-type: image/gif');
843
		die("\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x21\xF9\x04\x01\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3B");
844
	}
845
846
	// Show a window that will play the verification code.
847
	elseif (isset($_REQUEST['sound']))
848
	{
849
		loadLanguage('Login');
850
		loadTemplate('Register');
851
852
		$context['verification_sound_href'] = $scripturl . '?action=verificationcode;rand=' . md5(mt_rand()) . ($verification_id ? ';vid=' . $verification_id : '') . ';format=.wav';
853
		$context['sub_template'] = 'verification_sound';
854
		$context['template_layers'] = array();
855
856
		obExit();
857
	}
858
859
	// If we have GD, try the nice code.
860
	elseif (empty($_REQUEST['format']))
861
	{
862
		require_once($sourcedir . '/Subs-Graphics.php');
863
864
		if (in_array('gd', get_loaded_extensions()) && !showCodeImage($code))
865
			send_http_status(400);
866
867
		// Otherwise just show a pre-defined letter.
868
		elseif (isset($_REQUEST['letter']))
869
		{
870
			$_REQUEST['letter'] = (int) $_REQUEST['letter'];
871
			if ($_REQUEST['letter'] > 0 && $_REQUEST['letter'] <= strlen($code) && !showLetterImage(strtolower($code[$_REQUEST['letter'] - 1])))
872
			{
873
				header('content-type: image/gif');
874
				die("\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x21\xF9\x04\x01\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3B");
875
			}
876
		}
877
		// You must be up to no good.
878
		else
879
		{
880
			header('content-type: image/gif');
881
			die("\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x21\xF9\x04\x01\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3B");
882
		}
883
	}
884
885
	elseif ($_REQUEST['format'] === '.wav')
886
	{
887
		require_once($sourcedir . '/Subs-Sound.php');
888
889
		if (!createWaveFile($code))
890
			send_http_status(400);
891
	}
892
893
	// We all die one day...
894
	die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
895
}
896
897
/**
898
 * See if a username already exists.
899
 */
900
function RegisterCheckUsername()
901
{
902
	global $sourcedir, $context;
903
904
	// This is XML!
905
	loadTemplate('Xml');
906
	$context['sub_template'] = 'check_username';
907
	$context['checked_username'] = isset($_GET['username']) ? un_htmlspecialchars($_GET['username']) : '';
908
	$context['valid_username'] = true;
909
910
	// Clean it up like mother would.
911
	$context['checked_username'] = trim(normalize_spaces(sanitize_chars($context['checked_username'], 1, ' '), true, true, array('no_breaks' => true, 'replace_tabs' => true, 'collapse_hspace' => true)));
912
913
	require_once($sourcedir . '/Subs-Auth.php');
914
	$errors = validateUsername(0, $context['checked_username'], true);
915
916
	$context['valid_username'] = empty($errors);
917
}
918
919
/**
920
 * It doesn't actually send anything, this action just shows a message for a guest.
921
 */
922
function SendActivation()
923
{
924
	global $context, $txt;
925
926
	$context['user']['is_logged'] = false;
927
	$context['user']['is_guest'] = true;
928
929
	// Send them to the done-with-registration-login screen.
930
	loadTemplate('Register');
931
932
	$context['page_title'] = $txt['profile'];
933
	$context['sub_template'] = 'after';
934
	$context['title'] = $txt['activate_changed_email_title'];
935
	$context['description'] = $txt['activate_changed_email_desc'];
936
937
	// Aaand we're gone!
938
	obExit();
939
}
940
941
?>