PageRenderTime 87ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Sources/Register.php

https://github.com/smf-portal/SMF2.1
PHP | 851 lines | 579 code | 132 blank | 140 comment | 174 complexity | 69c3ad270a5c9c31c0132afd88416c4d MD5 | raw file
  1. <?php
  2. /**
  3. * This file has two main jobs, but they really are one. It registers new
  4. * members, and it helps the administrator moderate member registrations.
  5. * Similarly, it handles account activation as well.
  6. *
  7. * Simple Machines Forum (SMF)
  8. *
  9. * @package SMF
  10. * @author Simple Machines http://www.simplemachines.org
  11. * @copyright 2012 Simple Machines
  12. * @license http://www.simplemachines.org/about/smf/license.php BSD
  13. *
  14. * @version 2.1 Alpha 1
  15. */
  16. if (!defined('SMF'))
  17. die('Hacking attempt...');
  18. /**
  19. * Begin the registration process.
  20. *
  21. * @param array $reg_errors = array()
  22. */
  23. function Register($reg_errors = array())
  24. {
  25. global $txt, $boarddir, $context, $settings, $modSettings, $user_info;
  26. global $language, $scripturl, $smcFunc, $sourcedir, $smcFunc, $cur_profile;
  27. // Is this an incoming AJAX check?
  28. if (isset($_GET['sa']) && $_GET['sa'] == 'usernamecheck')
  29. return RegisterCheckUsername();
  30. // Check if the administrator has it disabled.
  31. if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == '3')
  32. fatal_lang_error('registration_disabled', false);
  33. // If this user is an admin - redirect them to the admin registration page.
  34. if (allowedTo('moderate_forum') && !$user_info['is_guest'])
  35. redirectexit('action=admin;area=regcenter;sa=register');
  36. // You are not a guest, so you are a member - and members don't get to register twice!
  37. elseif (empty($user_info['is_guest']))
  38. redirectexit();
  39. loadLanguage('Login');
  40. loadTemplate('Register');
  41. // Do we need them to agree to the registration agreement, first?
  42. $context['require_agreement'] = !empty($modSettings['requireAgreement']);
  43. $context['registration_passed_agreement'] = !empty($_SESSION['registration_agreed']);
  44. $context['show_coppa'] = !empty($modSettings['coppaAge']);
  45. // Under age restrictions?
  46. if ($context['show_coppa'])
  47. {
  48. $context['skip_coppa'] = false;
  49. $context['coppa_agree_above'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_above'], $modSettings['coppaAge']);
  50. $context['coppa_agree_below'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_below'], $modSettings['coppaAge']);
  51. }
  52. // What step are we at?
  53. $current_step = isset($_REQUEST['step']) ? (int) $_REQUEST['step'] : ($context['require_agreement'] ? 1 : 2);
  54. // Does this user agree to the registation agreement?
  55. if ($current_step == 1 && (isset($_POST['accept_agreement']) || isset($_POST['accept_agreement_coppa'])))
  56. {
  57. $context['registration_passed_agreement'] = $_SESSION['registration_agreed'] = true;
  58. $current_step = 2;
  59. // Skip the coppa procedure if the user says he's old enough.
  60. if ($context['show_coppa'])
  61. {
  62. $_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']);
  63. // Are they saying they're under age, while under age registration is disabled?
  64. if (empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
  65. {
  66. loadLanguage('Login');
  67. fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
  68. }
  69. }
  70. }
  71. // Make sure they don't squeeze through without agreeing.
  72. elseif ($current_step > 1 && $context['require_agreement'] && !$context['registration_passed_agreement'])
  73. $current_step = 1;
  74. // Show the user the right form.
  75. $context['sub_template'] = $current_step == 1 ? 'registration_agreement' : 'registration_form';
  76. $context['page_title'] = $current_step == 1 ? $txt['registration_agreement'] : $txt['registration_form'];
  77. // Add the register chain to the link tree.
  78. $context['linktree'][] = array(
  79. 'url' => $scripturl . '?action=register',
  80. 'name' => $txt['register'],
  81. );
  82. // If you have to agree to the agreement, it needs to be fetched from the file.
  83. if ($context['require_agreement'])
  84. {
  85. // Have we got a localized one?
  86. if (file_exists($boarddir . '/agreement.' . $user_info['language'] . '.txt'))
  87. $context['agreement'] = parse_bbc(file_get_contents($boarddir . '/agreement.' . $user_info['language'] . '.txt'), true, 'agreement_' . $user_info['language']);
  88. elseif (file_exists($boarddir . '/agreement.txt'))
  89. $context['agreement'] = parse_bbc(file_get_contents($boarddir . '/agreement.txt'), true, 'agreement');
  90. else
  91. $context['agreement'] = '';
  92. // Nothing to show, lets disable registration and inform the admin of this error
  93. if (empty($context['agreement']))
  94. {
  95. // No file found or a blank file, log the error so the admin knows there is a problem!
  96. log_error($txt['registration_agreement_missing'], 'critical');
  97. fatal_lang_error('registration_disabled', false);
  98. }
  99. }
  100. if (!empty($modSettings['userLanguage']))
  101. {
  102. $selectedLanguage = empty($_SESSION['language']) ? $language : $_SESSION['language'];
  103. // Do we have any languages?
  104. if (empty($context['languages']))
  105. getLanguages();
  106. // Try to find our selected language.
  107. foreach ($context['languages'] as $key => $lang)
  108. {
  109. $context['languages'][$key]['name'] = strtr($lang['name'], array('-utf8' => ''));
  110. // Found it!
  111. if ($selectedLanguage == $lang['filename'])
  112. $context['languages'][$key]['selected'] = true;
  113. }
  114. }
  115. // Any custom fields we want filled in?
  116. require_once($sourcedir . '/Profile.php');
  117. loadCustomFields(0, 'register');
  118. // Or any standard ones?
  119. if (!empty($modSettings['registration_fields']))
  120. {
  121. require_once($sourcedir . '/Profile-Modify.php');
  122. // Setup some important context.
  123. loadLanguage('Profile');
  124. loadTemplate('Profile');
  125. $context['user']['is_owner'] = true;
  126. // Here, and here only, emulate the permissions the user would have to do this.
  127. $user_info['permissions'] = array_merge($user_info['permissions'], array('profile_account_own', 'profile_extra_own'));
  128. $reg_fields = explode(',', $modSettings['registration_fields']);
  129. // We might have had some submissions on this front - go check.
  130. foreach ($reg_fields as $field)
  131. if (isset($_POST[$field]))
  132. $cur_profile[$field] = $smcFunc['htmlspecialchars']($_POST[$field]);
  133. // Load all the fields in question.
  134. setupProfileContext($reg_fields);
  135. }
  136. // Generate a visual verification code to make sure the user is no bot.
  137. if (!empty($modSettings['reg_verification']))
  138. {
  139. require_once($sourcedir . '/Subs-Editor.php');
  140. $verificationOptions = array(
  141. 'id' => 'register',
  142. );
  143. $context['visual_verification'] = create_control_verification($verificationOptions);
  144. $context['visual_verification_id'] = $verificationOptions['id'];
  145. }
  146. // Otherwise we have nothing to show.
  147. else
  148. $context['visual_verification'] = false;
  149. // Are they coming from an OpenID login attempt?
  150. if (!empty($_SESSION['openid']['verified']) && !empty($_SESSION['openid']['openid_uri']))
  151. {
  152. $context['openid'] = $_SESSION['openid']['openid_uri'];
  153. $context['username'] = $smcFunc['htmlspecialchars'](!empty($_POST['user']) ? $_POST['user'] : $_SESSION['openid']['nickname']);
  154. $context['email'] = $smcFunc['htmlspecialchars'](!empty($_POST['email']) ? $_POST['email'] : $_SESSION['openid']['email']);
  155. }
  156. // See whether we have some prefiled values.
  157. else
  158. {
  159. $context += array(
  160. 'openid' => isset($_POST['openid_identifier']) ? $_POST['openid_identifier'] : '',
  161. 'username' => isset($_POST['user']) ? $smcFunc['htmlspecialchars']($_POST['user']) : '',
  162. 'email' => isset($_POST['email']) ? $smcFunc['htmlspecialchars']($_POST['email']) : '',
  163. );
  164. }
  165. // @todo Why isn't this a simple set operation?
  166. // Were there any errors?
  167. $context['registration_errors'] = array();
  168. if (!empty($reg_errors))
  169. foreach ($reg_errors as $error)
  170. $context['registration_errors'][] = $error;
  171. createToken('register');
  172. }
  173. /**
  174. * Actually register the member.
  175. *
  176. * @param bool $verifiedOpenID = false
  177. */
  178. function Register2($verifiedOpenID = false)
  179. {
  180. global $scripturl, $txt, $modSettings, $context, $sourcedir;
  181. global $user_info, $options, $settings, $smcFunc;
  182. checkSession();
  183. validateToken('register');
  184. // Start collecting together any errors.
  185. $reg_errors = array();
  186. // Did we save some open ID fields?
  187. if ($verifiedOpenID && !empty($context['openid_save_fields']))
  188. {
  189. foreach ($context['openid_save_fields'] as $id => $value)
  190. $_POST[$id] = $value;
  191. }
  192. // You can't register if it's disabled.
  193. if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3)
  194. fatal_lang_error('registration_disabled', false);
  195. // Things we don't do for people who have already confirmed their OpenID allegances via register.
  196. if (!$verifiedOpenID)
  197. {
  198. // Well, if you don't agree, you can't register.
  199. if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed']))
  200. redirectexit();
  201. // Make sure they came from *somewhere*, have a session.
  202. if (!isset($_SESSION['old_url']))
  203. redirectexit('action=register');
  204. // If we don't require an agreement, we need a extra check for coppa.
  205. if (empty($modSettings['requireAgreement']) && !empty($modSettings['coppaAge']))
  206. $_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']);
  207. // Are they under age, and under age users are banned?
  208. if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
  209. {
  210. // @todo This should be put in Errors, imho.
  211. loadLanguage('Login');
  212. fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
  213. }
  214. // Check whether the visual verification code was entered correctly.
  215. if (!empty($modSettings['reg_verification']))
  216. {
  217. require_once($sourcedir . '/Subs-Editor.php');
  218. $verificationOptions = array(
  219. 'id' => 'register',
  220. );
  221. $context['visual_verification'] = create_control_verification($verificationOptions, true);
  222. if (is_array($context['visual_verification']))
  223. {
  224. loadLanguage('Errors');
  225. foreach ($context['visual_verification'] as $error)
  226. $reg_errors[] = $txt['error_' . $error];
  227. }
  228. }
  229. }
  230. foreach ($_POST as $key => $value)
  231. {
  232. if (!is_array($_POST[$key]))
  233. $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
  234. }
  235. // Collect all extra registration fields someone might have filled in.
  236. $possible_strings = array(
  237. 'website_url', 'website_title',
  238. 'aim', 'yim',
  239. 'location', 'birthdate',
  240. 'time_format',
  241. 'buddy_list',
  242. 'pm_ignore_list',
  243. 'smiley_set',
  244. 'signature', 'personal_text', 'avatar',
  245. 'lngfile',
  246. 'secret_question', 'secret_answer',
  247. );
  248. $possible_ints = array(
  249. 'pm_email_notify',
  250. 'notify_types',
  251. 'icq',
  252. 'gender',
  253. 'id_theme',
  254. );
  255. $possible_floats = array(
  256. 'time_offset',
  257. );
  258. $possible_bools = array(
  259. 'notify_announcements', 'notify_regularity', 'notify_send_body',
  260. 'hide_email', 'show_online',
  261. );
  262. if (isset($_POST['secret_answer']) && $_POST['secret_answer'] != '')
  263. $_POST['secret_answer'] = md5($_POST['secret_answer']);
  264. // Needed for isReservedName() and registerMember().
  265. require_once($sourcedir . '/Subs-Members.php');
  266. // Validation... even if we're not a mall.
  267. if (isset($_POST['real_name']) && (!empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum')))
  268. {
  269. $_POST['real_name'] = trim(preg_replace('~[\s]~' . ($context['utf8'] ? 'u' : ''), ' ', $_POST['real_name']));
  270. if (trim($_POST['real_name']) != '' && !isReservedName($_POST['real_name']) && $smcFunc['strlen']($_POST['real_name']) < 60)
  271. $possible_strings[] = 'real_name';
  272. }
  273. if (isset($_POST['msn']) && preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $_POST['msn']) != 0)
  274. $profile_strings[] = 'msn';
  275. // Handle a string as a birthdate...
  276. if (isset($_POST['birthdate']) && $_POST['birthdate'] != '')
  277. $_POST['birthdate'] = strftime('%Y-%m-%d', strtotime($_POST['birthdate']));
  278. // Or birthdate parts...
  279. elseif (!empty($_POST['bday1']) && !empty($_POST['bday2']))
  280. $_POST['birthdate'] = sprintf('%04d-%02d-%02d', empty($_POST['bday3']) ? 0 : (int) $_POST['bday3'], (int) $_POST['bday1'], (int) $_POST['bday2']);
  281. // By default assume email is hidden, only show it if we tell it to.
  282. $_POST['hide_email'] = !empty($_POST['allow_email']) ? 0 : 1;
  283. // Validate the passed language file.
  284. if (isset($_POST['lngfile']) && !empty($modSettings['userLanguage']))
  285. {
  286. // Do we have any languages?
  287. if (empty($context['languages']))
  288. getLanguages();
  289. // Did we find it?
  290. if (isset($context['languages'][$_POST['lngfile']]))
  291. $_SESSION['language'] = $_POST['lngfile'];
  292. else
  293. unset($_POST['lngfile']);
  294. }
  295. else
  296. unset($_POST['lngfile']);
  297. // Set the options needed for registration.
  298. $regOptions = array(
  299. 'interface' => 'guest',
  300. 'username' => !empty($_POST['user']) ? $_POST['user'] : '',
  301. 'email' => !empty($_POST['email']) ? $_POST['email'] : '',
  302. 'password' => !empty($_POST['passwrd1']) ? $_POST['passwrd1'] : '',
  303. 'password_check' => !empty($_POST['passwrd2']) ? $_POST['passwrd2'] : '',
  304. 'openid' => !empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : '',
  305. 'auth_method' => !empty($_POST['authenticate']) ? $_POST['authenticate'] : '',
  306. 'check_reserved_name' => true,
  307. 'check_password_strength' => true,
  308. 'check_email_ban' => true,
  309. 'send_welcome_email' => !empty($modSettings['send_welcomeEmail']),
  310. 'require' => !empty($modSettings['coppaAge']) && !$verifiedOpenID && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')),
  311. 'extra_register_vars' => array(),
  312. 'theme_vars' => array(),
  313. );
  314. // Include the additional options that might have been filled in.
  315. foreach ($possible_strings as $var)
  316. if (isset($_POST[$var]))
  317. $regOptions['extra_register_vars'][$var] = $smcFunc['htmlspecialchars']($_POST[$var], ENT_QUOTES);
  318. foreach ($possible_ints as $var)
  319. if (isset($_POST[$var]))
  320. $regOptions['extra_register_vars'][$var] = (int) $_POST[$var];
  321. foreach ($possible_floats as $var)
  322. if (isset($_POST[$var]))
  323. $regOptions['extra_register_vars'][$var] = (float) $_POST[$var];
  324. foreach ($possible_bools as $var)
  325. if (isset($_POST[$var]))
  326. $regOptions['extra_register_vars'][$var] = empty($_POST[$var]) ? 0 : 1;
  327. // Registration options are always default options...
  328. if (isset($_POST['default_options']))
  329. $_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
  330. $regOptions['theme_vars'] = isset($_POST['options']) && is_array($_POST['options']) ? $_POST['options'] : array();
  331. // Make sure they are clean, dammit!
  332. $regOptions['theme_vars'] = htmlspecialchars__recursive($regOptions['theme_vars']);
  333. // Check whether we have fields that simply MUST be displayed?
  334. $request = $smcFunc['db_query']('', '
  335. SELECT col_name, field_name, field_type, field_length, mask, show_reg
  336. FROM {db_prefix}custom_fields
  337. WHERE active = {int:is_active}',
  338. array(
  339. 'is_active' => 1,
  340. )
  341. );
  342. $custom_field_errors = array();
  343. while ($row = $smcFunc['db_fetch_assoc']($request))
  344. {
  345. // Don't allow overriding of the theme variables.
  346. if (isset($regOptions['theme_vars'][$row['col_name']]))
  347. unset($regOptions['theme_vars'][$row['col_name']]);
  348. // Not actually showing it then?
  349. if (!$row['show_reg'])
  350. continue;
  351. // Prepare the value!
  352. $value = isset($_POST['customfield'][$row['col_name']]) ? trim($_POST['customfield'][$row['col_name']]) : '';
  353. // We only care for text fields as the others are valid to be empty.
  354. if (!in_array($row['field_type'], array('check', 'select', 'radio')))
  355. {
  356. // Is it too long?
  357. if ($row['field_length'] && $row['field_length'] < $smcFunc['strlen']($value))
  358. $custom_field_errors[] = array('custom_field_too_long', array($row['field_name'], $row['field_length']));
  359. // Any masks to apply?
  360. if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none')
  361. {
  362. // @todo We never error on this - just ignore it at the moment...
  363. if ($row['mask'] == 'email' && (preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $value) === 0 || strlen($value) > 255))
  364. $custom_field_errors[] = array('custom_field_invalid_email', array($row['field_name']));
  365. elseif ($row['mask'] == 'number' && preg_match('~[^\d]~', $value))
  366. $custom_field_errors[] = array('custom_field_not_number', array($row['field_name']));
  367. elseif (substr($row['mask'], 0, 5) == 'regex' && preg_match(substr($row['mask'], 5), $value) === 0)
  368. $custom_field_errors[] = array('custom_field_inproper_format', array($row['field_name']));
  369. }
  370. }
  371. // Is this required but not there?
  372. if (trim($value) == '' && $row['show_reg'] > 1)
  373. $custom_field_errors[] = array('custom_field_empty', array($row['field_name']));
  374. }
  375. $smcFunc['db_free_result']($request);
  376. // Process any errors.
  377. if (!empty($custom_field_errors))
  378. {
  379. loadLanguage('Errors');
  380. foreach ($custom_field_errors as $error)
  381. $reg_errors[] = vsprintf($txt['error_' . $error[0]], $error[1]);
  382. }
  383. // Lets check for other errors before trying to register the member.
  384. if (!empty($reg_errors))
  385. {
  386. $_REQUEST['step'] = 2;
  387. return Register($reg_errors);
  388. }
  389. // If they're wanting to use OpenID we need to validate them first.
  390. if (empty($_SESSION['openid']['verified']) && !empty($_POST['authenticate']) && $_POST['authenticate'] == 'openid')
  391. {
  392. // What do we need to save?
  393. $save_variables = array();
  394. foreach ($_POST as $k => $v)
  395. if (!in_array($k, array('sc', 'sesc', $context['session_var'], 'passwrd1', 'passwrd2', 'regSubmit')))
  396. $save_variables[$k] = $v;
  397. require_once($sourcedir . '/Subs-OpenID.php');
  398. smf_openID_validate($_POST['openid_identifier'], false, $save_variables);
  399. }
  400. // If we've come from OpenID set up some default stuff.
  401. elseif ($verifiedOpenID || (!empty($_POST['openid_identifier']) && $_POST['authenticate'] == 'openid'))
  402. {
  403. $regOptions['username'] = !empty($_POST['user']) && trim($_POST['user']) != '' ? $_POST['user'] : $_SESSION['openid']['nickname'];
  404. $regOptions['email'] = !empty($_POST['email']) && trim($_POST['email']) != '' ? $_POST['email'] : $_SESSION['openid']['email'];
  405. $regOptions['auth_method'] = 'openid';
  406. $regOptions['openid'] = !empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : $_SESSION['openid']['openid_uri'];
  407. }
  408. $memberID = registerMember($regOptions, true);
  409. // What there actually an error of some kind dear boy?
  410. if (is_array($memberID))
  411. {
  412. $reg_errors = array_merge($reg_errors, $memberID);
  413. $_REQUEST['step'] = 2;
  414. return Register($reg_errors);
  415. }
  416. // Do our spam protection now.
  417. spamProtection('register');
  418. // We'll do custom fields after as then we get to use the helper function!
  419. if (!empty($_POST['customfield']))
  420. {
  421. require_once($sourcedir . '/Profile.php');
  422. require_once($sourcedir . '/Profile-Modify.php');
  423. makeCustomFieldChanges($memberID, 'register');
  424. }
  425. // If COPPA has been selected then things get complicated, setup the template.
  426. if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']))
  427. redirectexit('action=coppa;member=' . $memberID);
  428. // Basic template variable setup.
  429. elseif (!empty($modSettings['registration_method']))
  430. {
  431. loadTemplate('Register');
  432. $context += array(
  433. 'page_title' => $txt['register'],
  434. 'title' => $txt['registration_successful'],
  435. 'sub_template' => 'after',
  436. 'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']
  437. );
  438. }
  439. else
  440. {
  441. call_integration_hook('integrate_activate', array($regOptions['username']));
  442. setLoginCookie(60 * $modSettings['cookieTime'], $memberID, sha1(sha1(strtolower($regOptions['username']) . $regOptions['password']) . $regOptions['register_vars']['password_salt']));
  443. redirectexit('action=login2;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
  444. }
  445. }
  446. /**
  447. * @todo needs description
  448. */
  449. function Activate()
  450. {
  451. global $context, $txt, $modSettings, $scripturl, $sourcedir, $smcFunc, $language, $user_info;
  452. // Logged in users should not bother to activate their accounts
  453. if (!empty($user_info['id']))
  454. redirectexit();
  455. loadLanguage('Login');
  456. loadTemplate('Login');
  457. if (empty($_REQUEST['u']) && empty($_POST['user']))
  458. {
  459. if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == '3')
  460. fatal_lang_error('no_access', false);
  461. $context['member_id'] = 0;
  462. $context['sub_template'] = 'resend';
  463. $context['page_title'] = $txt['invalid_activation_resend'];
  464. $context['can_activate'] = empty($modSettings['registration_method']) || $modSettings['registration_method'] == '1';
  465. $context['default_username'] = isset($_GET['user']) ? $_GET['user'] : '';
  466. return;
  467. }
  468. // Get the code from the database...
  469. $request = $smcFunc['db_query']('', '
  470. SELECT id_member, validation_code, member_name, real_name, email_address, is_activated, passwd, lngfile
  471. FROM {db_prefix}members' . (empty($_REQUEST['u']) ? '
  472. WHERE member_name = {string:email_address} OR email_address = {string:email_address}' : '
  473. WHERE id_member = {int:id_member}') . '
  474. LIMIT 1',
  475. array(
  476. 'id_member' => isset($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0,
  477. 'email_address' => isset($_POST['user']) ? $_POST['user'] : '',
  478. )
  479. );
  480. // Does this user exist at all?
  481. if ($smcFunc['db_num_rows']($request) == 0)
  482. {
  483. $context['sub_template'] = 'retry_activate';
  484. $context['page_title'] = $txt['invalid_userid'];
  485. $context['member_id'] = 0;
  486. return;
  487. }
  488. $row = $smcFunc['db_fetch_assoc']($request);
  489. $smcFunc['db_free_result']($request);
  490. // Change their email address? (they probably tried a fake one first :P.)
  491. if (isset($_POST['new_email'], $_REQUEST['passwd']) && sha1(strtolower($row['member_name']) . $_REQUEST['passwd']) == $row['passwd'])
  492. {
  493. if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == 3)
  494. fatal_lang_error('no_access', false);
  495. // @todo Separate the sprintf?
  496. if (preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $_POST['new_email']) == 0)
  497. fatal_error(sprintf($txt['valid_email_needed'], htmlspecialchars($_POST['new_email'])), false);
  498. // Make sure their email isn't banned.
  499. isBannedEmail($_POST['new_email'], 'cannot_register', $txt['ban_register_prohibited']);
  500. // Ummm... don't even dare try to take someone else's email!!
  501. $request = $smcFunc['db_query']('', '
  502. SELECT id_member
  503. FROM {db_prefix}members
  504. WHERE email_address = {string:email_address}
  505. LIMIT 1',
  506. array(
  507. 'email_address' => $_POST['new_email'],
  508. )
  509. );
  510. // @todo Separate the sprintf?
  511. if ($smcFunc['db_num_rows']($request) != 0)
  512. fatal_lang_error('email_in_use', false, array(htmlspecialchars($_POST['new_email'])));
  513. $smcFunc['db_free_result']($request);
  514. updateMemberData($row['id_member'], array('email_address' => $_POST['new_email']));
  515. $row['email_address'] = $_POST['new_email'];
  516. $email_change = true;
  517. }
  518. // Resend the password, but only if the account wasn't activated yet.
  519. if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'resend' && ($row['is_activated'] == 0 || $row['is_activated'] == 2) && (!isset($_REQUEST['code']) || $_REQUEST['code'] == ''))
  520. {
  521. require_once($sourcedir . '/Subs-Post.php');
  522. $replacements = array(
  523. 'REALNAME' => $row['real_name'],
  524. 'USERNAME' => $row['member_name'],
  525. 'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $row['id_member'] . ';code=' . $row['validation_code'],
  526. 'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $row['id_member'],
  527. 'ACTIVATIONCODE' => $row['validation_code'],
  528. 'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder',
  529. );
  530. $emaildata = loadEmailTemplate('resend_activate_message', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
  531. sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 0);
  532. $context['page_title'] = $txt['invalid_activation_resend'];
  533. // This will ensure we don't actually get an error message if it works!
  534. $context['error_title'] = '';
  535. fatal_lang_error(!empty($email_change) ? 'change_email_success' : 'resend_email_success', false);
  536. }
  537. // Quit if this code is not right.
  538. if (empty($_REQUEST['code']) || $row['validation_code'] != $_REQUEST['code'])
  539. {
  540. if (!empty($row['is_activated']))
  541. fatal_lang_error('already_activated', false);
  542. elseif ($row['validation_code'] == '')
  543. {
  544. loadLanguage('Profile');
  545. fatal_error($txt['registration_not_approved'] . ' <a href="' . $scripturl . '?action=activate;user=' . $row['member_name'] . '">' . $txt['here'] . '</a>.', false);
  546. }
  547. $context['sub_template'] = 'retry_activate';
  548. $context['page_title'] = $txt['invalid_activation_code'];
  549. $context['member_id'] = $row['id_member'];
  550. return;
  551. }
  552. // Let the integration know that they've been activated!
  553. call_integration_hook('integrate_activate', array($row['member_name']));
  554. // Validation complete - update the database!
  555. updateMemberData($row['id_member'], array('is_activated' => 1, 'validation_code' => ''));
  556. // Also do a proper member stat re-evaluation.
  557. updateStats('member', false);
  558. if (!isset($_POST['new_email']))
  559. {
  560. require_once($sourcedir . '/Subs-Post.php');
  561. adminNotify('activation', $row['id_member'], $row['member_name']);
  562. }
  563. $context += array(
  564. 'page_title' => $txt['registration_successful'],
  565. 'sub_template' => 'login',
  566. 'default_username' => $row['member_name'],
  567. 'default_password' => '',
  568. 'never_expire' => false,
  569. 'description' => $txt['activate_success']
  570. );
  571. }
  572. /**
  573. * This function will display the contact information for the forum, as well a form to fill in.
  574. */
  575. function CoppaForm()
  576. {
  577. global $context, $modSettings, $txt, $smcFunc;
  578. loadLanguage('Login');
  579. loadTemplate('Register');
  580. // No User ID??
  581. if (!isset($_GET['member']))
  582. fatal_lang_error('no_access', false);
  583. // Get the user details...
  584. $request = $smcFunc['db_query']('', '
  585. SELECT member_name
  586. FROM {db_prefix}members
  587. WHERE id_member = {int:id_member}
  588. AND is_activated = {int:is_coppa}',
  589. array(
  590. 'id_member' => (int) $_GET['member'],
  591. 'is_coppa' => 5,
  592. )
  593. );
  594. if ($smcFunc['db_num_rows']($request) == 0)
  595. fatal_lang_error('no_access', false);
  596. list ($username) = $smcFunc['db_fetch_row']($request);
  597. $smcFunc['db_free_result']($request);
  598. if (isset($_GET['form']))
  599. {
  600. // Some simple contact stuff for the forum.
  601. $context['forum_contacts'] = (!empty($modSettings['coppaPost']) ? $modSettings['coppaPost'] . '<br /><br />' : '') . (!empty($modSettings['coppaFax']) ? $modSettings['coppaFax'] . '<br />' : '');
  602. $context['forum_contacts'] = !empty($context['forum_contacts']) ? $context['forum_name_html_safe'] . '<br />' . $context['forum_contacts'] : '';
  603. // Showing template?
  604. if (!isset($_GET['dl']))
  605. {
  606. // Shortcut for producing underlines.
  607. $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>';
  608. $context['template_layers'] = array();
  609. $context['sub_template'] = 'coppa_form';
  610. $context['page_title'] = $txt['coppa_form_title'];
  611. $context['coppa_body'] = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'), array($context['ul'], $context['ul'], $username), $txt['coppa_form_body']);
  612. }
  613. // Downloading.
  614. else
  615. {
  616. // The data.
  617. $ul = ' ';
  618. $crlf = "\r\n";
  619. $data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . $txt['coppa_form_body'];
  620. $data = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br>', '<br />'), array($ul, $ul, $username, $crlf, $crlf), $data);
  621. // Send the headers.
  622. header('Connection: close');
  623. header('Content-Disposition: attachment; filename="approval.txt"');
  624. header('Content-Type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream'));
  625. header('Content-Length: ' . count($data));
  626. echo $data;
  627. obExit(false);
  628. }
  629. }
  630. else
  631. {
  632. $context += array(
  633. 'page_title' => $txt['coppa_title'],
  634. 'sub_template' => 'coppa',
  635. );
  636. $context['coppa'] = array(
  637. 'body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], $txt['coppa_after_registration']),
  638. 'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']),
  639. 'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'],
  640. 'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'],
  641. 'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']),
  642. 'id' => $_GET['member'],
  643. );
  644. }
  645. }
  646. /**
  647. * Show the verification code or let it hear.
  648. */
  649. function VerificationCode()
  650. {
  651. global $sourcedir, $modSettings, $context, $scripturl;
  652. $verification_id = isset($_GET['vid']) ? $_GET['vid'] : '';
  653. $code = $verification_id && isset($_SESSION[$verification_id . '_vv']) ? $_SESSION[$verification_id . '_vv']['code'] : (isset($_SESSION['visual_verification_code']) ? $_SESSION['visual_verification_code'] : '');
  654. // Somehow no code was generated or the session was lost.
  655. if (empty($code))
  656. {
  657. header('Content-Type: image/gif');
  658. 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");
  659. }
  660. // Show a window that will play the verification code.
  661. elseif (isset($_REQUEST['sound']))
  662. {
  663. loadLanguage('Login');
  664. loadTemplate('Register');
  665. $context['verification_sound_href'] = $scripturl . '?action=verificationcode;rand=' . md5(mt_rand()) . ($verification_id ? ';vid=' . $verification_id : '') . ';format=.wav';
  666. $context['sub_template'] = 'verification_sound';
  667. $context['template_layers'] = array();
  668. obExit();
  669. }
  670. // If we have GD, try the nice code.
  671. elseif (empty($_REQUEST['format']))
  672. {
  673. require_once($sourcedir . '/Subs-Graphics.php');
  674. if (in_array('gd', get_loaded_extensions()) && !showCodeImage($code))
  675. header('HTTP/1.1 400 Bad Request');
  676. // Otherwise just show a pre-defined letter.
  677. elseif (isset($_REQUEST['letter']))
  678. {
  679. $_REQUEST['letter'] = (int) $_REQUEST['letter'];
  680. if ($_REQUEST['letter'] > 0 && $_REQUEST['letter'] <= strlen($code) && !showLetterImage(strtolower($code{$_REQUEST['letter'] - 1})))
  681. {
  682. header('Content-Type: image/gif');
  683. 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");
  684. }
  685. }
  686. // You must be up to no good.
  687. else
  688. {
  689. header('Content-Type: image/gif');
  690. 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");
  691. }
  692. }
  693. elseif ($_REQUEST['format'] === '.wav')
  694. {
  695. require_once($sourcedir . '/Subs-Sound.php');
  696. if (!createWaveFile($code))
  697. header('HTTP/1.1 400 Bad Request');
  698. }
  699. // We all die one day...
  700. die();
  701. }
  702. /**
  703. * See if a username already exists.
  704. */
  705. function RegisterCheckUsername()
  706. {
  707. global $sourcedir, $smcFunc, $context, $txt;
  708. // This is XML!
  709. loadTemplate('Xml');
  710. $context['sub_template'] = 'check_username';
  711. $context['checked_username'] = isset($_GET['username']) ? un_htmlspecialchars($_GET['username']) : '';
  712. $context['valid_username'] = true;
  713. // Clean it up like mother would.
  714. $context['checked_username'] = preg_replace('~[\t\n\r\x0B\0' . ($context['utf8'] ? '\x{A0}' : '\xA0') . ']+~' . ($context['utf8'] ? 'u' : ''), ' ', $context['checked_username']);
  715. require_once($sourcedir . '/Subs-Auth.php');
  716. $errors = validateUsername(0, $context['checked_username'], true);
  717. $context['valid_username'] = empty($errors);
  718. }
  719. ?>