Completed
Push — release-2.1 ( 6f6d35...abeae7 )
by Mathias
08:46
created

Register.php ➔ RegisterCheckUsername()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 2
nop 0
dl 0
loc 18
rs 9.2
c 0
b 0
f 0
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 2017 Simple Machines and individual contributors
13
 * @license http://www.simplemachines.org/about/smf/license.php BSD
14
 *
15
 * @version 2.1 Beta 4
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 View Code Duplication
			if (empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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), '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 View Code Duplication
		if (file_exists($boarddir . '/agreement.' . $user_info['language'] . '.txt'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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['userLanguage']))
132
	{
133
		$selectedLanguage = empty($_SESSION['language']) ? $language : $_SESSION['language'];
134
135
		// Do we have any languages?
136
		if (empty($context['languages']))
137
			getLanguages();
138
139
		// Try to find our selected language.
140
		foreach ($context['languages'] as $key => $lang)
141
		{
142
			$context['languages'][$key]['name'] = strtr($lang['name'], array('-utf8' => ''));
143
144
			// Found it!
145
			if ($selectedLanguage == $lang['filename'])
146
				$context['languages'][$key]['selected'] = true;
147
		}
148
	}
149
150
	// Any custom fields we want filled in?
151
	require_once($sourcedir . '/Profile.php');
152
	loadCustomFields(0, 'register');
153
154
	// Or any standard ones?
155
	if (!empty($modSettings['registration_fields']))
156
	{
157
		require_once($sourcedir . '/Profile-Modify.php');
158
159
		// Setup some important context.
160
		loadLanguage('Profile');
161
		loadTemplate('Profile');
162
163
		$context['user']['is_owner'] = true;
164
165
		// Here, and here only, emulate the permissions the user would have to do this.
166
		$user_info['permissions'] = array_merge($user_info['permissions'], array('profile_account_own', 'profile_extra_own', 'profile_other_own', 'profile_password_own'));
167
		$reg_fields = explode(',', $modSettings['registration_fields']);
168
169
		// We might have had some submissions on this front - go check.
170
		foreach ($reg_fields as $field)
171
			if (isset($_POST[$field]))
172
				$cur_profile[$field] = $smcFunc['htmlspecialchars']($_POST[$field]);
173
174
		// Load all the fields in question.
175
		setupProfileContext($reg_fields);
176
	}
177
178
	// Generate a visual verification code to make sure the user is no bot.
179
	if (!empty($modSettings['reg_verification']))
180
	{
181
		require_once($sourcedir . '/Subs-Editor.php');
182
		$verificationOptions = array(
183
			'id' => 'register',
184
		);
185
		$context['visual_verification'] = create_control_verification($verificationOptions);
186
		$context['visual_verification_id'] = $verificationOptions['id'];
187
	}
188
	// Otherwise we have nothing to show.
189
	else
190
		$context['visual_verification'] = false;
191
192
193
	$context += array(
194
		'username' => isset($_POST['user']) ? $smcFunc['htmlspecialchars']($_POST['user']) : '',
195
		'email' => isset($_POST['email']) ? $smcFunc['htmlspecialchars']($_POST['email']) : '',
196
		'notify_announcements' => !empty($_POST['notify_announcements']) ? 1 : 0,
197
	);
198
199
	// Were there any errors?
200
	$context['registration_errors'] = array();
201
	if (!empty($reg_errors))
202
		$context['registration_errors'] = $reg_errors;
203
204
	createToken('register');
205
}
206
207
/**
208
 * Actually register the member.
209
 */
210
function Register2()
211
{
212
	global $txt, $modSettings, $context, $sourcedir;
213
	global $smcFunc, $maintenance;
214
215
	checkSession();
216
	validateToken('register');
217
218
	// Check to ensure we're forcing SSL for authentication
219 View Code Duplication
	if (!empty($modSettings['force_ssl']) && empty($maintenance) && (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
220
		fatal_lang_error('register_ssl_required');
221
222
	// Start collecting together any errors.
223
	$reg_errors = array();
224
225
	// You can't register if it's disabled.
226 View Code Duplication
	if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
227
		fatal_lang_error('registration_disabled', false);
228
229
	// Well, if you don't agree, you can't register.
230
	if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed']))
231
		redirectexit();
232
233
	// Make sure they came from *somewhere*, have a session.
234
	if (!isset($_SESSION['old_url']))
235
		redirectexit('action=signup');
236
237
	// If we don't require an agreement, we need a extra check for coppa.
238
	if (empty($modSettings['requireAgreement']) && !empty($modSettings['coppaAge']))
239
		$_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']);
240
	// Are they under age, and under age users are banned?
241 View Code Duplication
	if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
242
	{
243
		loadLanguage('Errors');
244
		fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
245
	}
246
247
	// Check the time gate for miscreants. First make sure they came from somewhere that actually set it up.
248
	if (empty($_SESSION['register']['timenow']) || empty($_SESSION['register']['limit']))
249
		redirectexit('action=signup');
250
	// Failing that, check the time on it.
251
	if (time() - $_SESSION['register']['timenow'] < $_SESSION['register']['limit'])
252
	{
253
		loadLanguage('Errors');
254
		$reg_errors[] = $txt['error_too_quickly'];
255
	}
256
257
	// Check whether the visual verification code was entered correctly.
258
	if (!empty($modSettings['reg_verification']))
259
	{
260
		require_once($sourcedir . '/Subs-Editor.php');
261
		$verificationOptions = array(
262
			'id' => 'register',
263
		);
264
		$context['visual_verification'] = create_control_verification($verificationOptions, true);
265
266
		if (is_array($context['visual_verification']))
267
		{
268
			loadLanguage('Errors');
269
			foreach ($context['visual_verification'] as $error)
270
				$reg_errors[] = $txt['error_' . $error];
271
		}
272
	}
273
274 View Code Duplication
	foreach ($_POST as $key => $value)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
275
	{
276
		if (!is_array($_POST[$key]))
277
			$_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
278
	}
279
280
	// Collect all extra registration fields someone might have filled in.
281
	$possible_strings = array(
282
		'birthdate',
283
		'time_format',
284
		'buddy_list',
285
		'pm_ignore_list',
286
		'smiley_set',
287
		'personal_text', 'avatar',
288
		'lngfile',
289
		'secret_question', 'secret_answer',
290
	);
291
	$possible_ints = array(
292
		'id_theme',
293
	);
294
	$possible_floats = array(
295
		'time_offset',
296
	);
297
	$possible_bools = array(
298
		'show_online',
299
	);
300
301
	// We may want to add certain things to these if selected in the admin panel.
302
	if (!empty($modSettings['registration_fields']))
303
	{
304
		$reg_fields = explode(',', $modSettings['registration_fields']);
305
306
		// Website is a little different
307
		if (in_array('website', $reg_fields))
308
			$possible_strings += array('website_url', 'website_title');
309
	}
310
311
	if (isset($_POST['secret_answer']) && $_POST['secret_answer'] != '')
312
		$_POST['secret_answer'] = md5($_POST['secret_answer']);
313
314
	// Needed for isReservedName() and registerMember().
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
315
	require_once($sourcedir . '/Subs-Members.php');
316
317
	// Maybe you want set the displayed name during registration
318
	if (isset($_POST['real_name']))
319
	{
320
		// Are you already allowed to edit the displayed name?
321 View Code Duplication
		if (allowedTo('profile_displayed_name') || allowedTo('moderate_forum'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
322
			$canEditDisplayName = true;
323
324
		// If you are a guest, will you be allowed to once you register?
325
		else
326
		{
327
			$request = $smcFunc['db_query']('', '
328
				SELECT add_deny
329
				FROM {db_prefix}permissions
330
				WHERE id_group = {int:id_group} AND permission = {string:permission}',
331
				array(
332
					'id_group' => 0,
333
					'permission' => 'profile_displayed_name_own',
334
				)
335
			);
336
			list($canEditDisplayName) = $smcFunc['db_fetch_row']($request);
337
			$smcFunc['db_free_result']($request);
338
		}
339
340
		if ($canEditDisplayName)
341
		{
342
			// Sanitize it
343
			$_POST['real_name'] = trim(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' : ''), ' ', $_POST['real_name']));
344
345
			// Only set it if we are sure it is good
346
			if (trim($_POST['real_name']) != '' && !isReservedName($_POST['real_name']) && $smcFunc['strlen']($_POST['real_name']) < 60)
347
				$possible_strings[] = 'real_name';
348
		}
349
	}
350
351
	// Handle a string as a birthdate...
352
	if (isset($_POST['birthdate']) && $_POST['birthdate'] != '')
353
		$_POST['birthdate'] = strftime('%Y-%m-%d', strtotime($_POST['birthdate']));
354
	// Or birthdate parts...
355
	elseif (!empty($_POST['bday1']) && !empty($_POST['bday2']))
356
		$_POST['birthdate'] = sprintf('%04d-%02d-%02d', empty($_POST['bday3']) ? 0 : (int) $_POST['bday3'], (int) $_POST['bday1'], (int) $_POST['bday2']);
357
358
	// Validate the passed language file.
359
	if (isset($_POST['lngfile']) && !empty($modSettings['userLanguage']))
360
	{
361
		// Do we have any languages?
362
		if (empty($context['languages']))
363
			getLanguages();
364
365
		// Did we find it?
366
		if (isset($context['languages'][$_POST['lngfile']]))
367
			$_SESSION['language'] = $_POST['lngfile'];
368
		else
369
			unset($_POST['lngfile']);
370
	}
371
	else
372
		unset($_POST['lngfile']);
373
374
	// Set the options needed for registration.
375
	$regOptions = array(
376
		'interface' => 'guest',
377
		'username' => !empty($_POST['user']) ? $_POST['user'] : '',
378
		'email' => !empty($_POST['email']) ? $_POST['email'] : '',
379
		'password' => !empty($_POST['passwrd1']) ? $_POST['passwrd1'] : '',
380
		'password_check' => !empty($_POST['passwrd2']) ? $_POST['passwrd2'] : '',
381
		'check_reserved_name' => true,
382
		'check_password_strength' => true,
383
		'check_email_ban' => true,
384
		'send_welcome_email' => !empty($modSettings['send_welcomeEmail']),
385
		'require' => !empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')),
386
		'extra_register_vars' => array(),
387
		'theme_vars' => array(),
388
		'timezone' => !empty($modSettings['default_timezone']) ? $modSettings['default_timezone'] : '',
389
	);
390
391
	// Include the additional options that might have been filled in.
392
	foreach ($possible_strings as $var)
393
		if (isset($_POST[$var]))
394
			$regOptions['extra_register_vars'][$var] = $smcFunc['htmlspecialchars']($_POST[$var], ENT_QUOTES);
395 View Code Duplication
	foreach ($possible_ints as $var)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
396
		if (isset($_POST[$var]))
397
			$regOptions['extra_register_vars'][$var] = (int) $_POST[$var];
398 View Code Duplication
	foreach ($possible_floats as $var)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
399
		if (isset($_POST[$var]))
400
			$regOptions['extra_register_vars'][$var] = (float) $_POST[$var];
401
	foreach ($possible_bools as $var)
402
		if (isset($_POST[$var]))
403
			$regOptions['extra_register_vars'][$var] = empty($_POST[$var]) ? 0 : 1;
404
405
	// Registration options are always default options...
406 View Code Duplication
	if (isset($_POST['default_options']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
407
		$_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
408
	$regOptions['theme_vars'] = isset($_POST['options']) && is_array($_POST['options']) ? $_POST['options'] : array();
409
410
	// Make sure they are clean, dammit!
411
	$regOptions['theme_vars'] = htmlspecialchars__recursive($regOptions['theme_vars']);
412
413
	// Check whether we have fields that simply MUST be displayed?
414
	$request = $smcFunc['db_query']('', '
415
		SELECT col_name, field_name, field_type, field_length, mask, show_reg
416
		FROM {db_prefix}custom_fields
417
		WHERE active = {int:is_active}
418
		ORDER BY field_order',
419
		array(
420
			'is_active' => 1,
421
		)
422
	);
423
	$custom_field_errors = array();
424
	while ($row = $smcFunc['db_fetch_assoc']($request))
425
	{
426
		// Don't allow overriding of the theme variables.
427
		if (isset($regOptions['theme_vars'][$row['col_name']]))
428
			unset($regOptions['theme_vars'][$row['col_name']]);
429
430
		// Not actually showing it then?
431
		if (!$row['show_reg'])
432
			continue;
433
434
		// Prepare the value!
435
		$value = isset($_POST['customfield'][$row['col_name']]) ? trim($_POST['customfield'][$row['col_name']]) : '';
436
437
		// We only care for text fields as the others are valid to be empty.
438
		if (!in_array($row['field_type'], array('check', 'select', 'radio')))
439
		{
440
			// Is it too long?
441
			if ($row['field_length'] && $row['field_length'] < $smcFunc['strlen']($value))
442
				$custom_field_errors[] = array('custom_field_too_long', array($row['field_name'], $row['field_length']));
443
444
			// Any masks to apply?
445
			if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none')
446
			{
447
				if ($row['mask'] == 'email' && (!filter_var($value, FILTER_VALIDATE_EMAIL) || strlen($value) > 255))
448
					$custom_field_errors[] = array('custom_field_invalid_email', array($row['field_name']));
449
				elseif ($row['mask'] == 'number' && preg_match('~[^\d]~', $value))
450
					$custom_field_errors[] = array('custom_field_not_number', array($row['field_name']));
451
				elseif (substr($row['mask'], 0, 5) == 'regex' && trim($value) != '' && preg_match(substr($row['mask'], 5), $value) === 0)
452
					$custom_field_errors[] = array('custom_field_inproper_format', array($row['field_name']));
453
			}
454
		}
455
456
		// Is this required but not there?
457
		if (trim($value) == '' && $row['show_reg'] > 1)
458
			$custom_field_errors[] = array('custom_field_empty', array($row['field_name']));
459
	}
460
	$smcFunc['db_free_result']($request);
461
462
	// Process any errors.
463 View Code Duplication
	if (!empty($custom_field_errors))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
464
	{
465
		loadLanguage('Errors');
466
		foreach ($custom_field_errors as $error)
467
			$reg_errors[] = vsprintf($txt['error_' . $error[0]], $error[1]);
468
	}
469
470
	// Lets check for other errors before trying to register the member.
471
	if (!empty($reg_errors))
472
	{
473
		$_REQUEST['step'] = 2;
474
		$_SESSION['register']['limit'] = 5; // If they've filled in some details, they won't need the full 10 seconds of the limit.
475
		return Register($reg_errors);
476
	}
477
478
	$memberID = registerMember($regOptions, true);
479
480
	// What there actually an error of some kind dear boy?
481
	if (is_array($memberID))
482
	{
483
		$reg_errors = array_merge($reg_errors, $memberID);
484
		$_REQUEST['step'] = 2;
485
		return Register($reg_errors);
486
	}
487
488
	// Do our spam protection now.
489
	spamProtection('register');
490
491
	// Do they want to recieve announcements?
492
	require_once($sourcedir . '/Subs-Notify.php');
493
	$prefs = getNotifyPrefs($memberID, 'announcements', true);
494
	$var = !empty($_POST['notify_announcements']);
495
	$pref = !empty($prefs[$memberID]['announcements']);
496
497
	// Don't update if the default is the same.
498
	if ($var != $pref)
499
	{
500
		setNotifyPrefs($memberID, array('announcements' => (int) !empty($_POST['notify_announcements'])));
501
	}
502
503
	// We'll do custom fields after as then we get to use the helper function!
504
	if (!empty($_POST['customfield']))
505
	{
506
		require_once($sourcedir . '/Profile.php');
507
		require_once($sourcedir . '/Profile-Modify.php');
508
		makeCustomFieldChanges($memberID, 'register');
509
	}
510
511
	// If COPPA has been selected then things get complicated, setup the template.
512
	if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']))
513
		redirectexit('action=coppa;member=' . $memberID);
514
	// Basic template variable setup.
515
	elseif (!empty($modSettings['registration_method']))
516
	{
517
		loadTemplate('Register');
518
519
		$context += array(
520
			'page_title' => $txt['register'],
521
			'title' => $txt['registration_successful'],
522
			'sub_template' => 'after',
523
			'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']
524
		);
525
	}
526
	else
527
	{
528
		call_integration_hook('integrate_activate', array($regOptions['username']));
529
530
		setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash_salt($regOptions['register_vars']['passwd'], $regOptions['register_vars']['password_salt']));
531
532
		redirectexit('action=login2;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
533
	}
534
}
535
536
/**
537
 * Activate an users account.
538
 *
539
 * Checks for mail changes, resends password if needed.
540
 */
541
function Activate()
542
{
543
	global $context, $txt, $modSettings, $scripturl, $sourcedir, $smcFunc, $language, $user_info;
544
545
	// Logged in users should not bother to activate their accounts
546
	if (!empty($user_info['id']))
547
		redirectexit();
548
549
	loadLanguage('Login');
550
	loadTemplate('Login');
551
552
	if (empty($_REQUEST['u']) && empty($_POST['user']))
553
	{
554 View Code Duplication
		if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == '3')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
555
			fatal_lang_error('no_access', false);
556
557
		$context['member_id'] = 0;
558
		$context['sub_template'] = 'resend';
559
		$context['page_title'] = $txt['invalid_activation_resend'];
560
		$context['can_activate'] = empty($modSettings['registration_method']) || $modSettings['registration_method'] == '1';
561
		$context['default_username'] = isset($_GET['user']) ? $_GET['user'] : '';
562
563
		return;
564
	}
565
566
	// Get the code from the database...
567
	$request = $smcFunc['db_query']('', '
568
		SELECT id_member, validation_code, member_name, real_name, email_address, is_activated, passwd, lngfile
569
		FROM {db_prefix}members' . (empty($_REQUEST['u']) ? '
570
		WHERE member_name = {string:email_address} OR email_address = {string:email_address}' : '
571
		WHERE id_member = {int:id_member}') . '
572
		LIMIT 1',
573
		array(
574
			'id_member' => isset($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0,
575
			'email_address' => isset($_POST['user']) ? $_POST['user'] : '',
576
		)
577
	);
578
579
	// Does this user exist at all?
580
	if ($smcFunc['db_num_rows']($request) == 0)
581
	{
582
		$context['sub_template'] = 'retry_activate';
583
		$context['page_title'] = $txt['invalid_userid'];
584
		$context['member_id'] = 0;
585
586
		return;
587
	}
588
589
	$row = $smcFunc['db_fetch_assoc']($request);
590
	$smcFunc['db_free_result']($request);
591
592
	// Change their email address? (they probably tried a fake one first :P.)
593
	if (isset($_POST['new_email'], $_REQUEST['passwd']) && hash_password($row['member_name'], $_REQUEST['passwd']) == $row['passwd'] && ($row['is_activated'] == 0 || $row['is_activated'] == 2))
594
	{
595 View Code Duplication
		if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == 3)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
596
			fatal_lang_error('no_access', false);
597
598
		if (!filter_var($_POST['new_email'], FILTER_VALIDATE_EMAIL))
599
			fatal_error(sprintf($txt['valid_email_needed'], $smcFunc['htmlspecialchars']($_POST['new_email'])), false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
600
601
		// Make sure their email isn't banned.
602
		isBannedEmail($_POST['new_email'], 'cannot_register', $txt['ban_register_prohibited']);
603
604
		// Ummm... don't even dare try to take someone else's email!!
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
605
		$request = $smcFunc['db_query']('', '
606
			SELECT id_member
607
			FROM {db_prefix}members
608
			WHERE email_address = {string:email_address}
609
			LIMIT 1',
610
			array(
611
				'email_address' => $_POST['new_email'],
612
			)
613
		);
614
615
		if ($smcFunc['db_num_rows']($request) != 0)
616
			fatal_lang_error('email_in_use', false, array($smcFunc['htmlspecialchars']($_POST['new_email'])));
617
		$smcFunc['db_free_result']($request);
618
619
		updateMemberData($row['id_member'], array('email_address' => $_POST['new_email']));
620
		$row['email_address'] = $_POST['new_email'];
621
622
		$email_change = true;
623
	}
624
625
	// Resend the password, but only if the account wasn't activated yet.
626
	if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'resend' && ($row['is_activated'] == 0 || $row['is_activated'] == 2) && (!isset($_REQUEST['code']) || $_REQUEST['code'] == ''))
627
	{
628
		require_once($sourcedir . '/Subs-Post.php');
629
630
		$replacements = array(
631
			'REALNAME' => $row['real_name'],
632
			'USERNAME' => $row['member_name'],
633
			'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $row['id_member'] . ';code=' . $row['validation_code'],
634
			'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $row['id_member'],
635
			'ACTIVATIONCODE' => $row['validation_code'],
636
			'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder',
637
		);
638
639
		$emaildata = loadEmailTemplate('resend_activate_message', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
640
641
		sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, 'resendact', $emaildata['is_html'], 0);
642
643
		$context['page_title'] = $txt['invalid_activation_resend'];
644
645
		// This will ensure we don't actually get an error message if it works!
646
		$context['error_title'] = '';
647
648
		fatal_lang_error(!empty($email_change) ? 'change_email_success' : 'resend_email_success', false);
649
	}
650
651
	// Quit if this code is not right.
652
	if (empty($_REQUEST['code']) || $row['validation_code'] != $_REQUEST['code'])
653
	{
654
		if (!empty($row['is_activated']))
655
			fatal_lang_error('already_activated', false);
656
		elseif ($row['validation_code'] == '')
657
		{
658
			loadLanguage('Profile');
659
			fatal_error(sprintf($txt['registration_not_approved'], $scripturl . '?action=activate;user=' . $row['member_name']), false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
660
		}
661
662
		$context['sub_template'] = 'retry_activate';
663
		$context['page_title'] = $txt['invalid_activation_code'];
664
		$context['member_id'] = $row['id_member'];
665
666
		return;
667
	}
668
669
	// Let the integration know that they've been activated!
670
	call_integration_hook('integrate_activate', array($row['member_name']));
671
672
	// Validation complete - update the database!
673
	updateMemberData($row['id_member'], array('is_activated' => 1, 'validation_code' => ''));
674
675
	// Also do a proper member stat re-evaluation.
676
	updateStats('member', false);
677
678
	if (!isset($_POST['new_email']))
679
	{
680
		require_once($sourcedir . '/Subs-Post.php');
681
682
		adminNotify('activation', $row['id_member'], $row['member_name']);
683
	}
684
685
	$context += array(
686
		'page_title' => $txt['registration_successful'],
687
		'sub_template' => 'login',
688
		'default_username' => $row['member_name'],
689
		'default_password' => '',
690
		'never_expire' => false,
691
		'description' => $txt['activate_success']
692
	);
693
}
694
695
/**
696
 * This function will display the contact information for the forum, as well a form to fill in.
697
 */
698
function CoppaForm()
699
{
700
	global $context, $modSettings, $txt, $smcFunc;
701
702
	loadLanguage('Login');
703
	loadTemplate('Register');
704
705
	// No User ID??
706
	if (!isset($_GET['member']))
707
		fatal_lang_error('no_access', false);
708
709
	// Get the user details...
710
	$request = $smcFunc['db_query']('', '
711
		SELECT member_name
712
		FROM {db_prefix}members
713
		WHERE id_member = {int:id_member}
714
			AND is_activated = {int:is_coppa}',
715
		array(
716
			'id_member' => (int) $_GET['member'],
717
			'is_coppa' => 5,
718
		)
719
	);
720
	if ($smcFunc['db_num_rows']($request) == 0)
721
		fatal_lang_error('no_access', false);
722
	list ($username) = $smcFunc['db_fetch_row']($request);
723
	$smcFunc['db_free_result']($request);
724
725
	if (isset($_GET['form']))
726
	{
727
		// Some simple contact stuff for the forum.
728
		$context['forum_contacts'] = (!empty($modSettings['coppaPost']) ? $modSettings['coppaPost'] . '<br><br>' : '') . (!empty($modSettings['coppaFax']) ? $modSettings['coppaFax'] . '<br>' : '');
729
		$context['forum_contacts'] = !empty($context['forum_contacts']) ? $context['forum_name_html_safe'] . '<br>' . $context['forum_contacts'] : '';
730
731
		// Showing template?
732
		if (!isset($_GET['dl']))
733
		{
734
			// Shortcut for producing underlines.
735
			$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>';
736
			$context['template_layers'] = array();
737
			$context['sub_template'] = 'coppa_form';
738
			$context['page_title'] = $txt['coppa_form_title'];
739
			$context['coppa_body'] = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'), array($context['ul'], $context['ul'], $username), $txt['coppa_form_body']);
740
		}
741
		// Downloading.
742
		else
743
		{
744
			// The data.
745
			$ul = '                ';
746
			$crlf = "\r\n";
747
			$data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . $txt['coppa_form_body'];
748
			$data = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br>', '<br>'), array($ul, $ul, $username, $crlf, $crlf), $data);
749
750
			// Send the headers.
751
			header('Connection: close');
752
			header('Content-Disposition: attachment; filename="approval.txt"');
753
			header('Content-Type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream'));
754
			header('Content-Length: ' . count($data));
755
756
			echo $data;
757
			obExit(false);
758
		}
759
	}
760
	else
761
	{
762
		$context += array(
763
			'page_title' => $txt['coppa_title'],
764
			'sub_template' => 'coppa',
765
		);
766
767
		$context['coppa'] = array(
768
			'body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], $txt['coppa_after_registration']),
769
			'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']),
770
			'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'],
771
			'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'],
772
			'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']),
773
			'id' => $_GET['member'],
774
		);
775
	}
776
}
777
778
/**
779
 * Show the verification code or let it be heard.
780
 */
781
function VerificationCode()
782
{
783
	global $sourcedir, $context, $scripturl;
784
785
	$verification_id = isset($_GET['vid']) ? $_GET['vid'] : '';
786
	$code = $verification_id && isset($_SESSION[$verification_id . '_vv']) ? $_SESSION[$verification_id . '_vv']['code'] : (isset($_SESSION['visual_verification_code']) ? $_SESSION['visual_verification_code'] : '');
787
788
	// Somehow no code was generated or the session was lost.
789
	if (empty($code))
790
	{
791
		header('Content-Type: image/gif');
792
		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");
793
	}
794
795
	// Show a window that will play the verification code.
796
	elseif (isset($_REQUEST['sound']))
797
	{
798
		loadLanguage('Login');
799
		loadTemplate('Register');
800
801
		$context['verification_sound_href'] = $scripturl . '?action=verificationcode;rand=' . md5(mt_rand()) . ($verification_id ? ';vid=' . $verification_id : '') . ';format=.wav';
802
		$context['sub_template'] = 'verification_sound';
803
		$context['template_layers'] = array();
804
805
		obExit();
806
	}
807
808
	// If we have GD, try the nice code.
809
	elseif (empty($_REQUEST['format']))
810
	{
811
		require_once($sourcedir . '/Subs-Graphics.php');
812
813
		if (in_array('gd', get_loaded_extensions()) && !showCodeImage($code))
814
			header('HTTP/1.1 400 Bad Request');
815
816
		// Otherwise just show a pre-defined letter.
817
		elseif (isset($_REQUEST['letter']))
818
		{
819
			$_REQUEST['letter'] = (int) $_REQUEST['letter'];
820
			if ($_REQUEST['letter'] > 0 && $_REQUEST['letter'] <= strlen($code) && !showLetterImage(strtolower($code{$_REQUEST['letter'] - 1})))
821
			{
822
				header('Content-Type: image/gif');
823
				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");
824
			}
825
		}
826
		// You must be up to no good.
827
		else
828
		{
829
			header('Content-Type: image/gif');
830
			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");
831
		}
832
	}
833
834
	elseif ($_REQUEST['format'] === '.wav')
835
	{
836
		require_once($sourcedir . '/Subs-Sound.php');
837
838
		if (!createWaveFile($code))
839
			header('HTTP/1.1 400 Bad Request');
840
	}
841
842
	// We all die one day...
843
	die();
844
}
845
846
/**
847
 * See if a username already exists.
848
 */
849
function RegisterCheckUsername()
850
{
851
	global $sourcedir, $context;
852
853
	// This is XML!
854
	loadTemplate('Xml');
855
	$context['sub_template'] = 'check_username';
856
	$context['checked_username'] = isset($_GET['username']) ? un_htmlspecialchars($_GET['username']) : '';
857
	$context['valid_username'] = true;
858
859
	// Clean it up like mother would.
860
	$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']);
861
862
	require_once($sourcedir . '/Subs-Auth.php');
863
	$errors = validateUsername(0, $context['checked_username'], true);
864
865
	$context['valid_username'] = empty($errors);
866
}
867
868
/**
869
 * It doesn't actually send anything, this action just shows a message for a guest.
870
 *
871
 */
872
function SendActivation()
873
{
874
	global $context, $txt;
875
876
	$context['user']['is_logged'] = false;
877
	$context['user']['is_guest'] = true;
878
879
	// Send them to the done-with-registration-login screen.
880
	loadTemplate('Register');
881
882
	$context['page_title'] = $txt['profile'];
883
	$context['sub_template'] = 'after';
884
	$context['title'] = $txt['activate_changed_email_title'];
885
	$context['description'] = $txt['activate_changed_email_desc'];
886
887
	// We're gone!
888
	obExit();
889
}
890
891
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...