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> </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
|
|||
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 | ?> |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.