Issues (1027)

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