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