<commit_before><?php

/**
 * This file has two main jobs, but they really are one.  It registers new
 * members, and it helps the administrator moderate member registrations.
 * Similarly, it handles account activation as well.
 *
 * @package   ElkArte Forum
 * @copyright ElkArte Forum contributors
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
 *
 * This file contains code covered by:
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
 *
 * @version 2.0 dev
 *
 */

namespace ElkArte\Controller;

use ElkArte\AbstractController;
use ElkArte\Action;
use ElkArte\Agreement;
use ElkArte\DataValidator;
use ElkArte\Errors\ErrorContext;
use ElkArte\Errors\Errors;
use ElkArte\Exceptions\Exception;
use ElkArte\PrivacyPolicy;
use ElkArte\Util;

/**
 * It registers new members, and it allows the administrator moderate member registration
 *
 * is_activated value key is as follows, for reference again:
 * - > 10 Banned with activation status as value - 10
 * - 5 = Awaiting COPPA consent
 * - 4 = Awaiting Deletion approval
 * - 3 = Awaiting Admin approval
 * - 2 = Awaiting reactivation from email change
 * - 1 = Approved and active
 * - 0 = Not active
 */
class Register extends AbstractController
{
	/**
	 * Holds the results of a findUser() request
	 *
	 * @var array
	 */
	private $_row;

	/**
	 * {@inheritdoc }
	 */
	public function trackStats($action = '')
	{
		if ($this->_req->get('sa') === 'verificationcode')
		{
			return false;
		}

		return parent::trackStats($action);
	}

	/**
	 * Pre Dispatch, called before other methods.
	 */
	public function pre_dispatch()
	{
		global $modSettings;

		// Check if the administrator has it disabled.
		if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == '3')
		{
			throw new Exception('registration_disabled', false);
		}
	}

	/**
	 * Intended entry point for this class.
	 *
	 * By default, this is called for action=register
	 *
	 * @see \ElkArte\AbstractController::action_index()
	 */
	public function action_index()
	{
		// Add an subaction array to act accordingly
		$subActions = array(
			'register' => array($this, 'action_register'),
			'register2' => array($this, 'action_register2'),
			'usernamecheck' => array($this, 'action_registerCheckUsername'),
			'activate' => array($this, 'action_activate'),
			'contact' => array($this, 'action_contact'),
			'verificationcode' => array($this, 'action_verificationcode'),
			'coppa' => array($this, 'action_coppa'),
			'agrelang' => array($this, 'action_agrelang'),
			'privacypol' => array($this, 'action_privacypol'),
			'agreement' => array($this, 'action_agreement'),
		);

		// Setup the action handler
		$action = new Action('register');
		$subAction = $action->initialize($subActions, 'register');

		// Call the action
		$action->dispatch($subAction);
	}

	/**
	 * Begin the registration process.
	 *
	 * - Triggers the prepare_context event
	 *
	 * Accessed by ?action=register
	 *
	 * @uses template_registration_agreement or template_registration_form sub template in Register.template,
	 * @uses Login language file
	 */
	public function action_register()
	{
		global $txt, $context, $modSettings, $scripturl;

		// If this user is an admin - redirect them to the admin registration page.
		if (allowedTo('moderate_forum') && $this->user->is_guest === false)
		{
			redirectexit('action=admin;area=regcenter;sa=register');
		}
		// You are not a guest, so you are a member - and members don't get to register twice!
		elseif (empty($this->user->is_guest))
		{
			redirectexit();
		}

		// Confused and want to contact the admins instead
		if (isset($this->_req->post->show_contact))
		{
			redirectexit('action=register;sa=contact');
		}

		// If we have language support enabled then they need to be loaded
		if ($this->_load_language_support())
		{
			redirectexit('action=register');
		}

		theme()->getTemplates()->loadLanguageFile('Login');
		theme()->getTemplates()->load('Register');

		// Do we need them to agree to the registration agreement, first?
		$context['require_agreement'] = !empty($modSettings['requireAgreement']);
		$context['checkbox_agreement'] = !empty($modSettings['checkboxAgreement']);
		$context['require_privacypol'] = !empty($modSettings['requirePrivacypolicy']);
		$context['registration_passed_agreement'] = !empty($_SESSION['registration_agreed']);
		$context['registration_passed_privacypol'] = !empty($_SESSION['registration_privacypolicy']);
		$context['show_coppa'] = !empty($modSettings['coppaAge']);
		$context['show_contact_button'] = !empty($modSettings['enable_contactform']) && $modSettings['enable_contactform'] === 'registration';
		if (!empty($modSettings['show_DisplayNameOnRegistration']))
		{
			$context['insert_display_name'] = true;
			theme()->getTemplates()->loadLanguageFile('Profile');
		}
		else
		{
			$context['insert_display_name'] = false;
		}

		// Under age restrictions?
		if ($context['show_coppa'])
		{
			$context['skip_coppa'] = false;
			$context['coppa_agree_above'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_above'], $modSettings['coppaAge']);
			$context['coppa_agree_below'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_below'], $modSettings['coppaAge']);
		}

		// What step are we at?
		$current_step = isset($this->_req->post->step) ? (int) $this->_req->post->step : ($context['require_agreement'] && !$context['checkbox_agreement'] ? 1 : 2);

		// Does this user agree to the registration agreement?
		if ($current_step === 1 && (isset($this->_req->post->accept_agreement) || isset($this->_req->post->accept_agreement_coppa)))
		{
			$context['registration_passed_agreement'] = $_SESSION['registration_agreed'] = true;
			$context['registration_passed_privacypol'] = $_SESSION['registration_privacypolicy'] = true;
			$current_step = 2;

			// Skip the coppa procedure if the user says he's old enough.
			if ($context['show_coppa'])
			{
				$_SESSION['skip_coppa'] = !empty($this->_req->post->accept_agreement);

				// Are they saying they're under age, while under age registration is disabled?
				if (empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
				{
					throw new Exception('Login.under_age_registration_prohibited', false, array($modSettings['coppaAge']));
				}
			}
		}
		// Make sure they don't squeeze through without agreeing.
		elseif ($current_step > 1 && $context['require_agreement'] && !$context['checkbox_agreement'] && !$context['registration_passed_agreement'])
		{
			$current_step = 1;
		}

		// Show the user the right form.
		$context['sub_template'] = $current_step === 1 ? 'registration_agreement' : 'registration_form';
		$context['page_title'] = $current_step === 1 ? $txt['registration_agreement'] : $txt['registration_form'];
		loadJavascriptFile(array('register.js', 'mailcheck.min.js'));
		theme()->addInlineJavascript('disableAutoComplete();
		$("input[type=email]").on("blur", function(event) {
			$(this).mailcheck({
				suggested: function(element, suggestion) {
				  	$("#suggestion").html("' . $txt['register_did_you'] . ' <b><i>" + suggestion.full + "</b></i>");
				},
				empty: function(element) {
				  	$("#suggestion").html("");
				}
			});
		});', true);

		// Add the register chain to the link tree.
		$context['linktree'][] = array(
			'url' => $scripturl . '?action=register',
			'name' => $txt['register'],
		);

		// Prepare the time gate! Done like this to allow later steps to reset the limit for any reason
		if (!isset($_SESSION['register']))
		{
			$_SESSION['register'] = array(
				'timenow' => time(),
				// minimum number of seconds required on this page for registration
				'limit' => 8,
			);
		}
		else
		{
			$_SESSION['register']['timenow'] = time();
		}

		// If you have to agree to the agreement, it needs to be fetched from the file.
		$agreement = new Agreement($this->user->language);
		$context['agreement'] = $agreement->getParsedText();

		if (empty($context['agreement']))
		{
			// No file found or a blank file, log the error so the admin knows there is a problem!
			theme()->getTemplates()->loadLanguageFile('Errors');
			Errors::instance()->log_error($txt['registration_agreement_missing'], 'critical');
			throw new Exception('registration_disabled', false);
		}

		if (!empty($context['require_privacypol']))
		{
			$privacypol = new PrivacyPolicy($this->user->language);
			$context['privacy_policy'] = $privacypol->getParsedText();

			if (empty($context['privacy_policy']))
			{
				// No file found or a blank file, log the error so the admin knows there is a problem!
				theme()->getTemplates()->loadLanguageFile('Errors');
				Errors::instance()::instance()->log_error($txt['registration_privacy_policy_missing'], 'critical');
				throw new \Exception('registration_disabled', false);
			}
		}

		// If we have language support enabled then they need to be loaded
		$this->_load_language_support();

		// Any custom or standard profile fields we want filled in during registration?
		$this->_load_profile_fields();

		// Trigger the prepare_context event
		$this->_events->trigger('prepare_context', array('current_step' => $current_step));

		// Are they coming from an OpenID login attempt?
		if (!empty($_SESSION['openid']['verified']) && !empty($_SESSION['openid']['openid_uri']) && !empty($_SESSION['openid']['nickname']))
		{
			$context['openid'] = $_SESSION['openid']['openid_uri'];
			$context['username'] = $this->_req->getPost('user', '\\ElkArte\\Util::htmlspecialchars', $_SESSION['openid']['nickname']);
			$context['email'] = $this->_req->getPost('email', '\\ElkArte\\Util::htmlspecialchars', $_SESSION['openid']['email']);
		}
		// See whether we have some pre filled values.
		else
		{
			$context['openid'] = $this->_req->getPost('openid_identifier', 'trim', '');
			$context['username'] = $this->_req->getPost('user', '\\ElkArte\\Util::htmlspecialchars', '');
			$context['email'] = $this->_req->getPost('email', '\\ElkArte\\Util::htmlspecialchars', '');
			$context['notify_announcements'] = (int) !empty($this->_req->post->notify_announcements);
		}

		// Were there any errors?
		$context['registration_errors'] = array();
		$reg_errors = ErrorContext::context('register', 0);
		if ($reg_errors->hasErrors())
		{
			$context['registration_errors'] = $reg_errors->prepareErrors();
		}

		createToken('register');
	}

	/**
	 * Handles the registration process for members using ElkArte registration
	 * and not (for example) OpenID.
	 *
	 * What it does:
	 *
	 * - Validates all requirements have been filled in properly
	 * - Passes final processing to do_register
	 * - Directs back to register on errors
	 * - Triggers the before_complete_register event
	 *
	 * Accessed by ?action=register;sa=register2
	 */
	public function action_register2()
	{
		global $modSettings;

		// Start collecting together any errors.
		$reg_errors = ErrorContext::context('register', 0);

		$this->_can_register();

		checkSession();
		if (!validateToken('register', 'post', true, false))
		{
			$reg_errors->addError('token_verification');
		}

		// If we're using an agreement checkbox, did they check it?
		if (!empty($modSettings['checkboxAgreement']) && !empty($this->_req->post->checkbox_agreement))
		{
			$_SESSION['registration_agreed'] = true;
		}

		// Well, if you don't agree, you can't register.
		if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed']))
		{
			redirectexit();<commit_msg>! fix #3362 registration younger where registration user click i am least 18 years old<commit_after><?php

/**
 * This file has two main jobs, but they really are one.  It registers new
 * members, and it helps the administrator moderate member registrations.
 * Similarly, it handles account activation as well.
 *
 * @package   ElkArte Forum
 * @copyright ElkArte Forum contributors
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
 *
 * This file contains code covered by:
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
 *
 * @version 2.0 dev
 *
 */

namespace ElkArte\Controller;

use ElkArte\AbstractController;
use ElkArte\Action;
use ElkArte\Agreement;
use ElkArte\DataValidator;
use ElkArte\Errors\ErrorContext;
use ElkArte\Errors\Errors;
use ElkArte\Exceptions\Exception;
use ElkArte\PrivacyPolicy;
use ElkArte\Util;

/**
 * It registers new members, and it allows the administrator moderate member registration
 *
 * is_activated value key is as follows, for reference again:
 * - > 10 Banned with activation status as value - 10
 * - 5 = Awaiting COPPA consent
 * - 4 = Awaiting Deletion approval
 * - 3 = Awaiting Admin approval
 * - 2 = Awaiting reactivation from email change
 * - 1 = Approved and active
 * - 0 = Not active
 */
class Register extends AbstractController
{
	/**
	 * Holds the results of a findUser() request
	 *
	 * @var array
	 */
	private $_row;

	/**
	 * {@inheritdoc }
	 */
	public function trackStats($action = '')
	{
		if ($this->_req->get('sa') === 'verificationcode')
		{
			return false;
		}

		return parent::trackStats($action);
	}

	/**
	 * Pre Dispatch, called before other methods.
	 */
	public function pre_dispatch()
	{
		global $modSettings;

		// Check if the administrator has it disabled.
		if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == '3')
		{
			throw new Exception('registration_disabled', false);
		}
	}

	/**
	 * Intended entry point for this class.
	 *
	 * By default, this is called for action=register
	 *
	 * @see \ElkArte\AbstractController::action_index()
	 */
	public function action_index()
	{
		// Add an subaction array to act accordingly
		$subActions = array(
			'register' => array($this, 'action_register'),
			'register2' => array($this, 'action_register2'),
			'usernamecheck' => array($this, 'action_registerCheckUsername'),
			'activate' => array($this, 'action_activate'),
			'contact' => array($this, 'action_contact'),
			'verificationcode' => array($this, 'action_verificationcode'),
			'coppa' => array($this, 'action_coppa'),
			'agrelang' => array($this, 'action_agrelang'),
			'privacypol' => array($this, 'action_privacypol'),
			'agreement' => array($this, 'action_agreement'),
		);

		// Setup the action handler
		$action = new Action('register');
		$subAction = $action->initialize($subActions, 'register');

		// Call the action
		$action->dispatch($subAction);
	}

	/**
	 * Begin the registration process.
	 *
	 * - Triggers the prepare_context event
	 *
	 * Accessed by ?action=register
	 *
	 * @uses template_registration_agreement or template_registration_form sub template in Register.template,
	 * @uses Login language file
	 */
	public function action_register()
	{
		global $txt, $context, $modSettings, $scripturl;

		// If this user is an admin - redirect them to the admin registration page.
		if (allowedTo('moderate_forum') && $this->user->is_guest === false)
		{
			redirectexit('action=admin;area=regcenter;sa=register');
		}
		// You are not a guest, so you are a member - and members don't get to register twice!
		elseif (empty($this->user->is_guest))
		{
			redirectexit();
		}

		// Confused and want to contact the admins instead
		if (isset($this->_req->post->show_contact))
		{
			redirectexit('action=register;sa=contact');
		}

		// If we have language support enabled then they need to be loaded
		if ($this->_load_language_support())
		{
			redirectexit('action=register');
		}

		theme()->getTemplates()->loadLanguageFile('Login');
		theme()->getTemplates()->load('Register');

		// Do we need them to agree to the registration agreement, first?
		$context['require_agreement'] = !empty($modSettings['requireAgreement']);
		$context['checkbox_agreement'] = !empty($modSettings['checkboxAgreement']);
		$context['require_privacypol'] = !empty($modSettings['requirePrivacypolicy']);
		$context['registration_passed_agreement'] = !empty($_SESSION['registration_agreed']);
		$context['registration_passed_privacypol'] = !empty($_SESSION['registration_privacypolicy']);
		$context['show_coppa'] = !empty($modSettings['coppaAge']);
		$context['show_contact_button'] = !empty($modSettings['enable_contactform']) && $modSettings['enable_contactform'] === 'registration';
		if (!empty($modSettings['show_DisplayNameOnRegistration']))
		{
			$context['insert_display_name'] = true;
			theme()->getTemplates()->loadLanguageFile('Profile');
		}
		else
		{
			$context['insert_display_name'] = false;
		}

		// Under age restrictions?
		if ($context['show_coppa'])
		{
			$context['skip_coppa'] = false;
			$context['coppa_agree_above'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_above'], $modSettings['coppaAge']);
			$context['coppa_agree_below'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_below'], $modSettings['coppaAge']);
		}

		// What step are we at?
		$current_step = isset($this->_req->post->step) ? (int) $this->_req->post->step : ($context['require_agreement'] && !$context['checkbox_agreement'] ? 1 : 2);

		// Does this user agree to the registration agreement?
		if ($current_step === 1 && (isset($this->_req->post->accept_agreement) || isset($this->_req->post->accept_agreement_coppa)))
		{
			$context['registration_passed_agreement'] = $_SESSION['registration_agreed'] = true;
			$context['registration_passed_privacypol'] = $_SESSION['registration_privacypolicy'] = true;
			$current_step = 2;

			// Skip the coppa procedure if the user says he's old enough.
			if ($context['show_coppa'])
			{
				$_SESSION['skip_coppa'] = !empty($this->_req->post->accept_agreement);

				// Are they saying they're under age, while under age registration is disabled?
				if (empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
				{
					throw new Exception('Login.under_age_registration_prohibited', false, array($modSettings['coppaAge']));
				}
			}
		}
		// Make sure they don't squeeze through without agreeing.
		elseif ($current_step > 1 && $context['require_agreement'] && !$context['checkbox_agreement'] && !$context['registration_passed_agreement'])
		{
			$current_step = 1;
		}

		// Show the user the right form.
		$context['sub_template'] = $current_step === 1 ? 'registration_agreement' : 'registration_form';
		$context['page_title'] = $current_step === 1 ? $txt['registration_agreement'] : $txt['registration_form'];
		loadJavascriptFile(array('register.js', 'mailcheck.min.js'));
		theme()->addInlineJavascript('disableAutoComplete();
		$("input[type=email]").on("blur", function(event) {
			$(this).mailcheck({
				suggested: function(element, suggestion) {
				  	$("#suggestion").html("' . $txt['register_did_you'] . ' <b><i>" + suggestion.full + "</b></i>");
				},
				empty: function(element) {
				  	$("#suggestion").html("");
				}
			});
		});', true);

		// Add the register chain to the link tree.
		$context['linktree'][] = array(
			'url' => $scripturl . '?action=register',
			'name' => $txt['register'],
		);

		// Prepare the time gate! Done like this to allow later steps to reset the limit for any reason
		if (!isset($_SESSION['register']))
		{
			$_SESSION['register'] = array(
				'timenow' => time(),
				// minimum number of seconds required on this page for registration
				'limit' => 8,
			);
		}
		else
		{
			$_SESSION['register']['timenow'] = time();
		}

		// If you have to agree to the agreement, it needs to be fetched from the file.
		$agreement = new Agreement($this->user->language);
		$context['agreement'] = $agreement->getParsedText();

		if (empty($context['agreement']))
		{
			// No file found or a blank file, log the error so the admin knows there is a problem!
			theme()->getTemplates()->loadLanguageFile('Errors');
			Errors::instance()->log_error($txt['registration_agreement_missing'], 'critical');
			throw new Exception('registration_disabled', false);
		}

		if (!empty($context['require_privacypol']))
		{
			$privacypol = new PrivacyPolicy($this->user->language);
			$context['privacy_policy'] = $privacypol->getParsedText();

			if (empty($context['privacy_policy']))
			{
				// No file found or a blank file, log the error so the admin knows there is a problem!
				theme()->getTemplates()->loadLanguageFile('Errors');
				Errors::instance()::instance()->log_error($txt['registration_privacy_policy_missing'], 'critical');
				throw new \Exception('registration_disabled', false);
			}
		}

		// If we have language support enabled then they need to be loaded
		$this->_load_language_support();

		// Any custom or standard profile fields we want filled in during registration?
		$this->_load_profile_fields();

		// Trigger the prepare_context event
		$this->_events->trigger('prepare_context', array('current_step' => $current_step));

		// Are they coming from an OpenID login attempt?
		if (!empty($_SESSION['openid']['verified']) && !empty($_SESSION['openid']['openid_uri']) && !empty($_SESSION['openid']['nickname']))
		{
			$context['openid'] = $_SESSION['openid']['openid_uri'];
			$context['username'] = $this->_req->getPost('user', '\\ElkArte\\Util::htmlspecialchars', $_SESSION['openid']['nickname']);
			$context['email'] = $this->_req->getPost('email', '\\ElkArte\\Util::htmlspecialchars', $_SESSION['openid']['email']);
		}
		// See whether we have some pre filled values.
		else
		{
			$context['openid'] = $this->_req->getPost('openid_identifier', 'trim', '');
			$context['username'] = $this->_req->getPost('user', '\\ElkArte\\Util::htmlspecialchars', '');
			$context['email'] = $this->_req->getPost('email', '\\ElkArte\\Util::htmlspecialchars', '');
			$context['notify_announcements'] = (int) !empty($this->_req->post->notify_announcements);
		}

		// Were there any errors?
		$context['registration_errors'] = array();
		$reg_errors = ErrorContext::context('register', 0);
		if ($reg_errors->hasErrors())
		{
			$context['registration_errors'] = $reg_errors->prepareErrors();
		}

		createToken('register');
	}

	/**
	 * Handles the registration process for members using ElkArte registration
	 * and not (for example) OpenID.
	 *
	 * What it does:
	 *
	 * - Validates all requirements have been filled in properly
	 * - Passes final processing to do_register
	 * - Directs back to register on errors
	 * - Triggers the before_complete_register event
	 *
	 * Accessed by ?action=register;sa=register2
	 */
	public function action_register2()
	{
		global $modSettings;

		// Start collecting together any errors.
		$reg_errors = ErrorContext::context('register', 0);

		$this->_can_register();

		checkSession();
		if (!validateToken('register', 'post', true, false))
		{
			$reg_errors->addError('token_verification');
		}

		// If we're using an agreement checkbox, did they check it?
		if (!empty($modSettings['checkboxAgreement']) && !empty($this->_req->post->checkbox_agreement))
		{
			$_SESSION['registration_agreed'] = true;
		}

		// Using coppa and the registration checkbox?
		if (!empty($modSettings['coppaAge']) && !empty($modSettings['checkboxAgreement']) && !empty($this->_req->post->accept_agreement))
			$_SESSION['skip_coppa'] = true;

		// Well, if you don't agree, you can't register.
		if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed']))
		{
			redirectexit();
{'fraction_non_alphanumeric': 0.16196791443850267, 'fraction_numerical': 0.0030802139037433155, 'mean_word_length': 4.6491058482358625, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 188, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6331190', 'n_tokens_mistral': 7932, 'n_tokens_neox': 6908, 'n_words': 1707}