Issues (1061)

Sources/Register.php (1 issue)

Severity
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 2020 Simple Machines and individual contributors
13
 * @license https://www.simplemachines.org/about/smf/license.php BSD
14
 *
15
 * @version 2.1 RC2
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
	// Do we need them to agree to the registration agreement, first?
50
	$context['require_agreement'] = !empty($modSettings['requireAgreement']);
51
	$context['registration_passed_agreement'] = !empty($_SESSION['registration_agreed']);
52
	$context['show_coppa'] = !empty($modSettings['coppaAge']);
53
54
	// Under age restrictions?
55
	if ($context['show_coppa'])
56
	{
57
		$context['skip_coppa'] = false;
58
		$context['coppa_agree_above'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_above'], $modSettings['coppaAge']);
59
		$context['coppa_agree_below'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_below'], $modSettings['coppaAge']);
60
	}
61
62
	// What step are we at?
63
	$current_step = isset($_REQUEST['step']) ? (int) $_REQUEST['step'] : ($context['require_agreement'] ? 1 : 2);
64
65
	// Does this user agree to the registation agreement?
66
	if ($current_step == 1 && (isset($_POST['accept_agreement']) || isset($_POST['accept_agreement_coppa'])))
67
	{
68
		$context['registration_passed_agreement'] = $_SESSION['registration_agreed'] = true;
69
		$current_step = 2;
70
71
		// Skip the coppa procedure if the user says he's old enough.
72
		if ($context['show_coppa'])
73
		{
74
			$_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']);
75
76
			// Are they saying they're under age, while under age registration is disabled?
77
			if (empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
78
			{
79
				loadLanguage('Login');
80
				fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
81
			}
82
		}
83
	}
84
	// Make sure they don't squeeze through without agreeing.
85
	elseif ($current_step > 1 && $context['require_agreement'] && !$context['registration_passed_agreement'])
86
		$current_step = 1;
87
88
	// Show the user the right form.
89
	$context['sub_template'] = $current_step == 1 ? 'registration_agreement' : 'registration_form';
90
	$context['page_title'] = $current_step == 1 ? $txt['registration_agreement'] : $txt['registration_form'];
91
92
	// Kinda need this.
93
	if ($context['sub_template'] == 'registration_form')
94
		loadJavaScriptFile('register.js', array('defer' => false, 'minimize' => true), 'smf_register');
95
96
	// Add the register chain to the link tree.
97
	$context['linktree'][] = array(
98
		'url' => $scripturl . '?action=signup',
99
		'name' => $txt['register'],
100
	);
101
102
	// 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.
103
	if (!isset($_SESSION['register']))
104
		$_SESSION['register'] = array(
105
			'timenow' => time(),
106
			'limit' => 10, // minimum number of seconds required on this page for registration
107
		);
108
	else
109
		$_SESSION['register']['timenow'] = time();
110
111
	// If you have to agree to the agreement, it needs to be fetched from the file.
112
	if ($context['require_agreement'])
113
	{
114
		// Have we got a localized one?
115
		if (file_exists($boarddir . '/agreement.' . $user_info['language'] . '.txt'))
116
			$context['agreement'] = parse_bbc(file_get_contents($boarddir . '/agreement.' . $user_info['language'] . '.txt'), true, 'agreement_' . $user_info['language']);
117
		elseif (file_exists($boarddir . '/agreement.txt'))
118
			$context['agreement'] = parse_bbc(file_get_contents($boarddir . '/agreement.txt'), true, 'agreement');
119
		else
120
			$context['agreement'] = '';
121
122
		// Nothing to show, lets disable registration and inform the admin of this error
123
		if (empty($context['agreement']))
124
		{
125
			// No file found or a blank file, log the error so the admin knows there is a problem!
126
			log_error($txt['registration_agreement_missing'], 'critical');
127
			fatal_lang_error('registration_disabled', false);
128
		}
129
	}
130
131
	require_once($sourcedir . '/Subs-Notify.php');
132
	$prefs = getNotifyPrefs(0, 'announcements');
133
	$context['notify_announcements'] = !empty($prefs[0]['announcements']);
134
135
	if (!empty($modSettings['userLanguage']))
136
	{
137
		$selectedLanguage = empty($_SESSION['language']) ? $language : $_SESSION['language'];
138
139
		// Do we have any languages?
140
		if (empty($context['languages']))
141
			getLanguages();
142
143
		// Try to find our selected language.
144
		foreach ($context['languages'] as $key => $lang)
145
		{
146
			$context['languages'][$key]['name'] = strtr($lang['name'], array('-utf8' => ''));
147
148
			// Found it!
149
			if ($selectedLanguage == $lang['filename'])
150
				$context['languages'][$key]['selected'] = true;
151
		}
152
	}
153
154
	// Any custom fields we want filled in?
155
	require_once($sourcedir . '/Profile.php');
156
	loadCustomFields(0, 'register');
157
158
	// Or any standard ones?
159
	if (!empty($modSettings['registration_fields']))
160
	{
161
		require_once($sourcedir . '/Profile-Modify.php');
162
163
		// Setup some important context.
164
		loadLanguage('Profile');
165
		loadTemplate('Profile');
166
167
		$context['user']['is_owner'] = true;
168
169
		// Here, and here only, emulate the permissions the user would have to do this.
170
		$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'));
171
		$reg_fields = explode(',', $modSettings['registration_fields']);
172
173
		// Website is a little different
174
		if (in_array('website', $reg_fields))
175
		{
176
			unset($reg_fields['website']);
177
			if (isset($_POST['website_title']))
178
				$cur_profile['website_title'] = $smcFunc['htmlspecialchars']($_POST['website_title']);
179
			if (isset($_POST['website_url']))
180
				$cur_profile['website_url'] = $smcFunc['htmlspecialchars']($_POST['website_url']);
181
		}
182
183
		// We might have had some submissions on this front - go check.
184
		foreach ($reg_fields as $field)
185
			if (isset($_POST[$field]))
186
				$cur_profile[$field] = $smcFunc['htmlspecialchars']($_POST[$field]);
187
188
		// Load all the fields in question.
189
		setupProfileContext($reg_fields);
190
	}
191
192
	// Generate a visual verification code to make sure the user is no bot.
193
	if (!empty($modSettings['reg_verification']))
194
	{
195
		require_once($sourcedir . '/Subs-Editor.php');
196
		$verificationOptions = array(
197
			'id' => 'register',
198
		);
199
		$context['visual_verification'] = create_control_verification($verificationOptions);
200
		$context['visual_verification_id'] = $verificationOptions['id'];
201
	}
202
	// Otherwise we have nothing to show.
203
	else
204
		$context['visual_verification'] = false;
205
206
	$context += array(
207
		'username' => isset($_POST['user']) ? $smcFunc['htmlspecialchars']($_POST['user']) : '',
208
		'email' => isset($_POST['email']) ? $smcFunc['htmlspecialchars']($_POST['email']) : '',
209
		'notify_announcements' => !empty($_POST['notify_announcements']) ? 1 : 0,
210
	);
211
212
	// Were there any errors?
213
	$context['registration_errors'] = array();
214
	if (!empty($reg_errors))
215
		$context['registration_errors'] = $reg_errors;
216
217
	createToken('register');
218
}
219
220
/**
221
 * Actually register the member.
222
 */
223
function Register2()
224
{
225
	global $txt, $modSettings, $context, $sourcedir;
226
	global $smcFunc, $maintenance;
227
228
	checkSession();
229
	validateToken('register');
230
231
	// Check to ensure we're forcing SSL for authentication
232
	if (!empty($modSettings['force_ssl']) && empty($maintenance) && !httpsOn())
233
		fatal_lang_error('register_ssl_required');
234
235
	// Start collecting together any errors.
236
	$reg_errors = array();
237
238
	// You can't register if it's disabled.
239
	if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3)
240
		fatal_lang_error('registration_disabled', false);
241
242
	// Well, if you don't agree, you can't register.
243
	if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed']))
244
		redirectexit();
245
246
	// Make sure they came from *somewhere*, have a session.
247
	if (!isset($_SESSION['old_url']))
248
		redirectexit('action=signup');
249
250
	// If we don't require an agreement, we need a extra check for coppa.
251
	if (empty($modSettings['requireAgreement']) && !empty($modSettings['coppaAge']))
252
		$_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']);
253
	// Are they under age, and under age users are banned?
254
	if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
255
	{
256
		loadLanguage('Errors');
257
		fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
258
	}
259
260
	// Check the time gate for miscreants. First make sure they came from somewhere that actually set it up.
261
	if (empty($_SESSION['register']['timenow']) || empty($_SESSION['register']['limit']))
262
		redirectexit('action=signup');
263
	// Failing that, check the time on it.
264
	if (time() - $_SESSION['register']['timenow'] < $_SESSION['register']['limit'])
265
	{
266
		loadLanguage('Errors');
267
		$reg_errors[] = $txt['error_too_quickly'];
268
	}
269
270
	// Check whether the visual verification code was entered correctly.
271
	if (!empty($modSettings['reg_verification']))
272
	{
273
		require_once($sourcedir . '/Subs-Editor.php');
274
		$verificationOptions = array(
275
			'id' => 'register',
276
		);
277
		$context['visual_verification'] = create_control_verification($verificationOptions, true);
278
279
		if (is_array($context['visual_verification']))
280
		{
281
			loadLanguage('Errors');
282
			foreach ($context['visual_verification'] as $error)
283
				$reg_errors[] = $txt['error_' . $error];
284
		}
285
	}
286
287
	foreach ($_POST as $key => $value)
288
	{
289
		if (!is_array($_POST[$key]))
290
		{
291
			// For UTF-8, replace any kind of space with a normal space, and remove any kind of control character (incl. "\n" and "\r"), then trim.
292
			if ($context['utf8'])
293
				$_POST[$key] = $smcFunc['htmltrim'](preg_replace(array('~\p{Z}+~u', '~\p{C}+~u'), array(' ', ''), $_POST[$key]));
294
			// Otherwise, just remove "\n" and "\r", then trim.
295
			else
296
				$_POST[$key] = $smcFunc['htmltrim'](str_replace(array("\n", "\r"), '', $_POST[$key]));
297
		}
298
		else
299
			$_POST[$key] = htmltrim__recursive($_POST[$key]);
300
	}
301
302
	// Collect all extra registration fields someone might have filled in.
303
	$possible_strings = array(
304
		'birthdate',
305
		'timezone',
306
		'buddy_list',
307
		'pm_ignore_list',
308
		'smiley_set',
309
		'personal_text', 'avatar',
310
		'lngfile',
311
		'secret_question', 'secret_answer',
312
	);
313
	$possible_ints = array(
314
		'id_theme',
315
	);
316
	$possible_floats = array(
317
		'time_offset',
318
	);
319
	$possible_bools = array(
320
		'show_online',
321
	);
322
323
	// We may want to add certain things to these if selected in the admin panel.
324
	if (!empty($modSettings['registration_fields']))
325
	{
326
		$reg_fields = explode(',', $modSettings['registration_fields']);
327
328
		// Website is a little different
329
		if (in_array('website', $reg_fields))
330
		{
331
			$possible_strings = array_merge(array('website_url', 'website_title'), $possible_strings);
332
333
			// Make sure their website URL is squeaky clean
334
			if (isset($_POST['website_url']))
335
				$_POST['website_url'] = (string) validate_iri(sanitize_iri($_POST['website_url']));
336
		}
337
	}
338
339
	if (isset($_POST['secret_answer']) && $_POST['secret_answer'] != '')
340
		$_POST['secret_answer'] = md5($_POST['secret_answer']);
341
342
	// Needed for isReservedName() and registerMember().
343
	require_once($sourcedir . '/Subs-Members.php');
344
345
	// Maybe you want set the displayed name during registration
346
	if (isset($_POST['real_name']))
347
	{
348
		// Are you already allowed to edit the displayed name?
349
		if (allowedTo('profile_displayed_name') || allowedTo('moderate_forum'))
350
			$canEditDisplayName = true;
351
352
		// If you are a guest, will you be allowed to once you register?
353
		else
354
		{
355
			$request = $smcFunc['db_query']('', '
356
				SELECT add_deny
357
				FROM {db_prefix}permissions
358
				WHERE id_group = {int:id_group} AND permission = {string:permission}',
359
				array(
360
					'id_group' => 0,
361
					'permission' => 'profile_displayed_name_own',
362
				)
363
			);
364
			list($canEditDisplayName) = $smcFunc['db_fetch_row']($request);
365
			$smcFunc['db_free_result']($request);
366
		}
367
368
		// Only set it if you can and if we are sure it is good
369
		if ($canEditDisplayName && $smcFunc['htmltrim']($_POST['real_name']) != '' && !isReservedName($_POST['real_name']) && $smcFunc['strlen']($_POST['real_name']) < 60)
370
			$possible_strings[] = 'real_name';
371
	}
372
373
	// Handle a string as a birthdate...
374
	if (isset($_POST['birthdate']) && $_POST['birthdate'] != '')
375
		$_POST['birthdate'] = strftime('%Y-%m-%d', strtotime($_POST['birthdate']));
376
	// Or birthdate parts...
377
	elseif (!empty($_POST['bday1']) && !empty($_POST['bday2']))
378
		$_POST['birthdate'] = sprintf('%04d-%02d-%02d', empty($_POST['bday3']) ? 0 : (int) $_POST['bday3'], (int) $_POST['bday1'], (int) $_POST['bday2']);
379
380
	// Validate the passed language file.
381
	if (isset($_POST['lngfile']) && !empty($modSettings['userLanguage']))
382
	{
383
		// Do we have any languages?
384
		if (empty($context['languages']))
385
			getLanguages();
386
387
		// Did we find it?
388
		if (isset($context['languages'][$_POST['lngfile']]))
389
			$_SESSION['language'] = $_POST['lngfile'];
390
		else
391
			unset($_POST['lngfile']);
392
	}
393
	else
394
		unset($_POST['lngfile']);
395
396
	// Set the options needed for registration.
397
	$regOptions = array(
398
		'interface' => 'guest',
399
		'username' => !empty($_POST['user']) ? $_POST['user'] : '',
400
		'email' => !empty($_POST['email']) ? $_POST['email'] : '',
401
		'password' => !empty($_POST['passwrd1']) ? $_POST['passwrd1'] : '',
402
		'password_check' => !empty($_POST['passwrd2']) ? $_POST['passwrd2'] : '',
403
		'check_reserved_name' => true,
404
		'check_password_strength' => true,
405
		'check_email_ban' => true,
406
		'send_welcome_email' => !empty($modSettings['send_welcomeEmail']),
407
		'require' => !empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')),
408
		'extra_register_vars' => array(),
409
		'theme_vars' => array(),
410
		'timezone' => !empty($modSettings['default_timezone']) ? $modSettings['default_timezone'] : '',
411
	);
412
413
	// Include the additional options that might have been filled in.
414
	foreach ($possible_strings as $var)
415
		if (isset($_POST[$var]))
416
			$regOptions['extra_register_vars'][$var] = $smcFunc['htmlspecialchars']($_POST[$var], ENT_QUOTES);
417
	foreach ($possible_ints as $var)
418
		if (isset($_POST[$var]))
419
			$regOptions['extra_register_vars'][$var] = (int) $_POST[$var];
420
	foreach ($possible_floats as $var)
421
		if (isset($_POST[$var]))
422
			$regOptions['extra_register_vars'][$var] = (float) $_POST[$var];
423
	foreach ($possible_bools as $var)
424
		if (isset($_POST[$var]))
425
			$regOptions['extra_register_vars'][$var] = empty($_POST[$var]) ? 0 : 1;
426
427
	// Registration options are always default options...
428
	if (isset($_POST['default_options']))
429
		$_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
430
	$regOptions['theme_vars'] = isset($_POST['options']) && is_array($_POST['options']) ? $_POST['options'] : array();
431
432
	// Make sure they are clean, dammit!
433
	$regOptions['theme_vars'] = htmlspecialchars__recursive($regOptions['theme_vars']);
434
435
	// Check whether we have fields that simply MUST be displayed?
436
	$request = $smcFunc['db_query']('', '
437
		SELECT col_name, field_name, field_type, field_length, mask, show_reg
438
		FROM {db_prefix}custom_fields
439
		WHERE active = {int:is_active}
440
		ORDER BY field_order',
441
		array(
442
			'is_active' => 1,
443
		)
444
	);
445
	$custom_field_errors = array();
446
	while ($row = $smcFunc['db_fetch_assoc']($request))
447
	{
448
		// Don't allow overriding of the theme variables.
449
		if (isset($regOptions['theme_vars'][$row['col_name']]))
450
			unset($regOptions['theme_vars'][$row['col_name']]);
451
452
		// Not actually showing it then?
453
		if (!$row['show_reg'])
454
			continue;
455
456
		// Prepare the value!
457
		$value = isset($_POST['customfield'][$row['col_name']]) ? trim($_POST['customfield'][$row['col_name']]) : '';
458
459
		// We only care for text fields as the others are valid to be empty.
460
		if (!in_array($row['field_type'], array('check', 'select', 'radio')))
461
		{
462
			// Is it too long?
463
			if ($row['field_length'] && $row['field_length'] < $smcFunc['strlen']($value))
464
				$custom_field_errors[] = array('custom_field_too_long', array($row['field_name'], $row['field_length']));
465
466
			// Any masks to apply?
467
			if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none')
468
			{
469
				if ($row['mask'] == 'email' && (!filter_var($value, FILTER_VALIDATE_EMAIL) || strlen($value) > 255))
470
					$custom_field_errors[] = array('custom_field_invalid_email', array($row['field_name']));
471
				elseif ($row['mask'] == 'number' && preg_match('~[^\d]~', $value))
472
					$custom_field_errors[] = array('custom_field_not_number', array($row['field_name']));
473
				elseif (substr($row['mask'], 0, 5) == 'regex' && trim($value) != '' && preg_match(substr($row['mask'], 5), $value) === 0)
474
					$custom_field_errors[] = array('custom_field_inproper_format', array($row['field_name']));
475
			}
476
		}
477
478
		// Is this required but not there?
479
		if (trim($value) == '' && $row['show_reg'] > 1)
480
			$custom_field_errors[] = array('custom_field_empty', array($row['field_name']));
481
	}
482
	$smcFunc['db_free_result']($request);
483
484
	// Process any errors.
485
	if (!empty($custom_field_errors))
486
	{
487
		loadLanguage('Errors');
488
		foreach ($custom_field_errors as $error)
489
			$reg_errors[] = vsprintf($txt['error_' . $error[0]], $error[1]);
490
	}
491
492
	// Lets check for other errors before trying to register the member.
493
	if (!empty($reg_errors))
494
	{
495
		$_REQUEST['step'] = 2;
496
		$_SESSION['register']['limit'] = 5; // If they've filled in some details, they won't need the full 10 seconds of the limit.
497
		return Register($reg_errors);
498
	}
499
500
	$memberID = registerMember($regOptions, true);
501
502
	// What there actually an error of some kind dear boy?
503
	if (is_array($memberID))
504
	{
505
		$reg_errors = array_merge($reg_errors, $memberID);
506
		$_REQUEST['step'] = 2;
507
		return Register($reg_errors);
508
	}
509
510
	// Do our spam protection now.
511
	spamProtection('register');
512
513
	// Do they want to receive announcements?
514
	require_once($sourcedir . '/Subs-Notify.php');
515
	$prefs = getNotifyPrefs($memberID, 'announcements', true);
516
	$var = !empty($_POST['notify_announcements']);
517
	$pref = !empty($prefs[$memberID]['announcements']);
518
519
	// Don't update if the default is the same.
520
	if ($var != $pref)
521
		setNotifyPrefs($memberID, array('announcements' => (int) !empty($_POST['notify_announcements'])));
522
523
	// We'll do custom fields after as then we get to use the helper function!
524
	if (!empty($_POST['customfield']))
525
	{
526
		require_once($sourcedir . '/Profile.php');
527
		require_once($sourcedir . '/Profile-Modify.php');
528
		makeCustomFieldChanges($memberID, 'register');
529
	}
530
531
	// If COPPA has been selected then things get complicated, setup the template.
532
	if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']))
533
		redirectexit('action=coppa;member=' . $memberID);
534
	// Basic template variable setup.
535
	elseif (!empty($modSettings['registration_method']))
536
	{
537
		loadTemplate('Register');
538
539
		$context += array(
540
			'page_title' => $txt['register'],
541
			'title' => $txt['registration_successful'],
542
			'sub_template' => 'after',
543
			'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']
544
		);
545
	}
546
	else
547
	{
548
		call_integration_hook('integrate_activate', array($regOptions['username']));
549
550
		setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash_salt($regOptions['register_vars']['passwd'], $regOptions['register_vars']['password_salt']));
551
552
		redirectexit('action=login2;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
553
	}
554
}
555
556
/**
557
 * Activate an users account.
558
 *
559
 * Checks for mail changes, resends password if needed.
560
 */
561
function Activate()
562
{
563
	global $context, $txt, $modSettings, $scripturl, $sourcedir, $smcFunc, $language, $user_info;
564
565
	// Logged in users should not bother to activate their accounts
566
	if (!empty($user_info['id']))
567
		redirectexit();
568
569
	loadLanguage('Login');
570
	loadTemplate('Login');
571
572
	if (empty($_REQUEST['u']) && empty($_POST['user']))
573
	{
574
		if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == '3')
575
			fatal_lang_error('no_access', false);
576
577
		$context['member_id'] = 0;
578
		$context['sub_template'] = 'resend';
579
		$context['page_title'] = $txt['invalid_activation_resend'];
580
		$context['can_activate'] = empty($modSettings['registration_method']) || $modSettings['registration_method'] == '1';
581
		$context['default_username'] = isset($_GET['user']) ? $_GET['user'] : '';
582
583
		return;
584
	}
585
586
	// Get the code from the database...
587
	$request = $smcFunc['db_query']('', '
588
		SELECT id_member, validation_code, member_name, real_name, email_address, is_activated, passwd, lngfile
589
		FROM {db_prefix}members' . (empty($_REQUEST['u']) ? '
590
		WHERE member_name = {string:email_address} OR email_address = {string:email_address}' : '
591
		WHERE id_member = {int:id_member}') . '
592
		LIMIT 1',
593
		array(
594
			'id_member' => isset($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0,
595
			'email_address' => isset($_POST['user']) ? $_POST['user'] : '',
596
		)
597
	);
598
599
	// Does this user exist at all?
600
	if ($smcFunc['db_num_rows']($request) == 0)
601
	{
602
		$context['sub_template'] = 'retry_activate';
603
		$context['page_title'] = $txt['invalid_userid'];
604
		$context['member_id'] = 0;
605
606
		return;
607
	}
608
609
	$row = $smcFunc['db_fetch_assoc']($request);
610
	$smcFunc['db_free_result']($request);
611
612
	// Change their email address? (they probably tried a fake one first :P.)
613
	if (isset($_POST['new_email'], $_REQUEST['passwd']) && hash_password($row['member_name'], $_REQUEST['passwd']) == $row['passwd'] && ($row['is_activated'] == 0 || $row['is_activated'] == 2))
614
	{
615
		if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == 3)
616
			fatal_lang_error('no_access', false);
617
618
		if (!filter_var($_POST['new_email'], FILTER_VALIDATE_EMAIL))
619
			fatal_error(sprintf($txt['valid_email_needed'], $smcFunc['htmlspecialchars']($_POST['new_email'])), false);
620
621
		// Make sure their email isn't banned.
622
		isBannedEmail($_POST['new_email'], 'cannot_register', $txt['ban_register_prohibited']);
623
624
		// Ummm... don't even dare try to take someone else's email!!
625
		$request = $smcFunc['db_query']('', '
626
			SELECT id_member
627
			FROM {db_prefix}members
628
			WHERE email_address = {string:email_address}
629
			LIMIT 1',
630
			array(
631
				'email_address' => $_POST['new_email'],
632
			)
633
		);
634
635
		if ($smcFunc['db_num_rows']($request) != 0)
636
			fatal_lang_error('email_in_use', false, array($smcFunc['htmlspecialchars']($_POST['new_email'])));
637
		$smcFunc['db_free_result']($request);
638
639
		updateMemberData($row['id_member'], array('email_address' => $_POST['new_email']));
640
		$row['email_address'] = $_POST['new_email'];
641
642
		$email_change = true;
643
	}
644
645
	// Resend the password, but only if the account wasn't activated yet.
646
	if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'resend' && ($row['is_activated'] == 0 || $row['is_activated'] == 2) && (!isset($_REQUEST['code']) || $_REQUEST['code'] == ''))
647
	{
648
		require_once($sourcedir . '/Subs-Post.php');
649
650
		$replacements = array(
651
			'REALNAME' => $row['real_name'],
652
			'USERNAME' => $row['member_name'],
653
			'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $row['id_member'] . ';code=' . $row['validation_code'],
654
			'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $row['id_member'],
655
			'ACTIVATIONCODE' => $row['validation_code'],
656
			'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder',
657
		);
658
659
		$emaildata = loadEmailTemplate('resend_activate_message', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
660
661
		sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, 'resendact', $emaildata['is_html'], 0);
662
663
		$context['page_title'] = $txt['invalid_activation_resend'];
664
665
		// This will ensure we don't actually get an error message if it works!
666
		$context['error_title'] = '';
667
668
		fatal_lang_error(!empty($email_change) ? 'change_email_success' : 'resend_email_success', false);
669
	}
670
671
	// Quit if this code is not right.
672
	if (empty($_REQUEST['code']) || $row['validation_code'] != $_REQUEST['code'])
673
	{
674
		if (!empty($row['is_activated']))
675
			fatal_lang_error('already_activated', false);
676
		elseif ($row['validation_code'] == '')
677
		{
678
			loadLanguage('Profile');
679
			fatal_error(sprintf($txt['registration_not_approved'], $scripturl . '?action=activate;user=' . $row['member_name']), false);
680
		}
681
682
		$context['sub_template'] = 'retry_activate';
683
		$context['page_title'] = $txt['invalid_activation_code'];
684
		$context['member_id'] = $row['id_member'];
685
686
		return;
687
	}
688
689
	// Let the integration know that they've been activated!
690
	call_integration_hook('integrate_activate', array($row['member_name']));
691
692
	// Validation complete - update the database!
693
	updateMemberData($row['id_member'], array('is_activated' => 1, 'validation_code' => ''));
694
695
	// Also do a proper member stat re-evaluation.
696
	updateStats('member', false);
697
698
	if (!isset($_POST['new_email']))
699
	{
700
		require_once($sourcedir . '/Subs-Post.php');
701
702
		adminNotify('activation', $row['id_member'], $row['member_name']);
703
	}
704
705
	$context += array(
706
		'page_title' => $txt['registration_successful'],
707
		'sub_template' => 'login',
708
		'default_username' => $row['member_name'],
709
		'default_password' => '',
710
		'never_expire' => false,
711
		'description' => $txt['activate_success']
712
	);
713
}
714
715
/**
716
 * This function will display the contact information for the forum, as well a form to fill in.
717
 */
718
function CoppaForm()
719
{
720
	global $context, $modSettings, $txt, $smcFunc;
721
722
	loadLanguage('Login');
723
	loadTemplate('Register');
724
725
	// No User ID??
726
	if (!isset($_GET['member']))
727
		fatal_lang_error('no_access', false);
728
729
	// Get the user details...
730
	$request = $smcFunc['db_query']('', '
731
		SELECT member_name
732
		FROM {db_prefix}members
733
		WHERE id_member = {int:id_member}
734
			AND is_activated = {int:is_coppa}',
735
		array(
736
			'id_member' => (int) $_GET['member'],
737
			'is_coppa' => 5,
738
		)
739
	);
740
	if ($smcFunc['db_num_rows']($request) == 0)
741
		fatal_lang_error('no_access', false);
742
	list ($username) = $smcFunc['db_fetch_row']($request);
743
	$smcFunc['db_free_result']($request);
744
745
	if (isset($_GET['form']))
746
	{
747
		// Some simple contact stuff for the forum.
748
		$context['forum_contacts'] = (!empty($modSettings['coppaPost']) ? $modSettings['coppaPost'] . '<br><br>' : '') . (!empty($modSettings['coppaFax']) ? $modSettings['coppaFax'] . '<br>' : '');
749
		$context['forum_contacts'] = !empty($context['forum_contacts']) ? $context['forum_name_html_safe'] . '<br>' . $context['forum_contacts'] : '';
750
751
		// Showing template?
752
		if (!isset($_GET['dl']))
753
		{
754
			// Shortcut for producing underlines.
755
			$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>';
756
			$context['template_layers'] = array();
757
			$context['sub_template'] = 'coppa_form';
758
			$context['page_title'] = $txt['coppa_form_title'];
759
			$context['coppa_body'] = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'), array($context['ul'], $context['ul'], $username), $txt['coppa_form_body']);
760
		}
761
		// Downloading.
762
		else
763
		{
764
			// The data.
765
			$ul = '                ';
766
			$crlf = "\r\n";
767
			$data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . $txt['coppa_form_body'];
768
			$data = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br>', '<br>'), array($ul, $ul, $username, $crlf, $crlf), $data);
769
770
			// Send the headers.
771
			header('connection: close');
772
			header('content-disposition: attachment; filename="approval.txt"');
773
			header('content-type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream'));
774
			header('content-length: ' . count($data));
775
776
			echo $data;
777
			obExit(false);
778
		}
779
	}
780
	else
781
	{
782
		$context += array(
783
			'page_title' => $txt['coppa_title'],
784
			'sub_template' => 'coppa',
785
		);
786
787
		$context['coppa'] = array(
788
			'body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], $txt['coppa_after_registration']),
789
			'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']),
790
			'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'],
791
			'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'],
792
			'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']),
793
			'id' => $_GET['member'],
794
		);
795
	}
796
}
797
798
/**
799
 * Show the verification code or let it be heard.
800
 */
801
function VerificationCode()
802
{
803
	global $sourcedir, $context, $scripturl;
804
805
	$verification_id = isset($_GET['vid']) ? $_GET['vid'] : '';
806
	$code = $verification_id && isset($_SESSION[$verification_id . '_vv']) ? $_SESSION[$verification_id . '_vv']['code'] : (isset($_SESSION['visual_verification_code']) ? $_SESSION['visual_verification_code'] : '');
807
808
	// Somehow no code was generated or the session was lost.
809
	if (empty($code))
810
	{
811
		header('content-type: image/gif');
812
		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");
813
	}
814
815
	// Show a window that will play the verification code.
816
	elseif (isset($_REQUEST['sound']))
817
	{
818
		loadLanguage('Login');
819
		loadTemplate('Register');
820
821
		$context['verification_sound_href'] = $scripturl . '?action=verificationcode;rand=' . md5(mt_rand()) . ($verification_id ? ';vid=' . $verification_id : '') . ';format=.wav';
822
		$context['sub_template'] = 'verification_sound';
823
		$context['template_layers'] = array();
824
825
		obExit();
826
	}
827
828
	// If we have GD, try the nice code.
829
	elseif (empty($_REQUEST['format']))
830
	{
831
		require_once($sourcedir . '/Subs-Graphics.php');
832
833
		if (in_array('gd', get_loaded_extensions()) && !showCodeImage($code))
834
			send_http_status(400);
835
836
		// Otherwise just show a pre-defined letter.
837
		elseif (isset($_REQUEST['letter']))
838
		{
839
			$_REQUEST['letter'] = (int) $_REQUEST['letter'];
840
			if ($_REQUEST['letter'] > 0 && $_REQUEST['letter'] <= strlen($code) && !showLetterImage(strtolower($code[$_REQUEST['letter'] - 1])))
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
		// You must be up to no good.
847
		else
848
		{
849
			header('content-type: image/gif');
850
			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");
851
		}
852
	}
853
854
	elseif ($_REQUEST['format'] === '.wav')
855
	{
856
		require_once($sourcedir . '/Subs-Sound.php');
857
858
		if (!createWaveFile($code))
859
			send_http_status(400);
860
	}
861
862
	// We all die one day...
863
	die();
0 ignored issues
show
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...
864
}
865
866
/**
867
 * See if a username already exists.
868
 */
869
function RegisterCheckUsername()
870
{
871
	global $sourcedir, $context;
872
873
	// This is XML!
874
	loadTemplate('Xml');
875
	$context['sub_template'] = 'check_username';
876
	$context['checked_username'] = isset($_GET['username']) ? un_htmlspecialchars($_GET['username']) : '';
877
	$context['valid_username'] = true;
878
879
	// Clean it up like mother would.
880
	$context['checked_username'] = preg_replace('~[\t\n\r \x0B\0' . ($context['utf8'] ? '\x{A0}\x{AD}\x{2000}-\x{200F}\x{201F}\x{202F}\x{3000}\x{FEFF}' : '\x00-\x08\x0B\x0C\x0E-\x19\xA0') . ']+~' . ($context['utf8'] ? 'u' : ''), ' ', $context['checked_username']);
881
882
	require_once($sourcedir . '/Subs-Auth.php');
883
	$errors = validateUsername(0, $context['checked_username'], true);
884
885
	$context['valid_username'] = empty($errors);
886
}
887
888
/**
889
 * It doesn't actually send anything, this action just shows a message for a guest.
890
 *
891
 */
892
function SendActivation()
893
{
894
	global $context, $txt;
895
896
	$context['user']['is_logged'] = false;
897
	$context['user']['is_guest'] = true;
898
899
	// Send them to the done-with-registration-login screen.
900
	loadTemplate('Register');
901
902
	$context['page_title'] = $txt['profile'];
903
	$context['sub_template'] = 'after';
904
	$context['title'] = $txt['activate_changed_email_title'];
905
	$context['description'] = $txt['activate_changed_email_desc'];
906
907
	// We're gone!
908
	obExit();
909
}
910
911
?>