Register > Start * @copyright Tamaranga */ class Start extends AuthForm { /** @var string */ public $title = ''; /** @var string */ public $back = ''; /** @var bool */ public $pass_confirm = false; /** @var string */ public $captcha = '0'; /** @var string */ public $captcha_key = 'users-auth-register'; public function init() { parent::init(); $this->setKey('users-auth-register'); $this->setTemplate('register/start', 'users'); $this->setTitle(_t('@users', 'Registration Form')); } public function data() { $data = parent::data(); if ($this->request->user()) { return Users::redirectToAccountSettings(); } if (empty($this->back)) { $data['back'] = $this->request->referer($this->router->url('index')); } $data['email_on'] = $this->hasEmail(); $data['phone_on'] = $this->hasPhoneNumber(); $data['agreement_on'] = $this->hasAgreement(); $data['agreement_url'] = Users::url('agreement'); $data['password_on'] = $this->hasPassword(); $data['password_confirm_on'] = $this->hasPasswordConfirm(); $data['captcha_on'] = $this->hasCaptcha(); $data['providers'] = Users::social()->getProvidersEnabled(); $data['login_url'] = $this->loginUrl(); $data['login_social_url'] = Users::url('login.social'); return $data; } public function validate($data = []) { $data = $this->validateUsingRules($data, [ 'phone_number' => [TYPE_NOTAGS, 'limit' => 30], # Phone number 'email' => [TYPE_NOTAGS, 'limit' => 100], # E-mail 'password' => [TYPE_NOTRIM], # Password 'password2' => [TYPE_NOTRIM], # Password confirmation 'agreement' => [TYPE_BOOL], # Agreement confirmation ]); do { # Email if ($this->hasEmail()) { if (! $this->validateEmail($data['email'])) { break; } if ($this->isEmailExists($data['email'])) { $this->errors->set( _t('users', 'A user with this email address is already registered. Forgot password?', [ 'link_forgot' => 'href="' . $this->forgotUrl() . '"' ]), 'email' ); break; } } # Phone if ($this->hasPhoneNumber()) { if (! $this->validatePhone($data['phone_number'])) { break; } if ($this->isPhoneExists($data['phone_number'])) { $this->errors->set( _t('users', 'A user with this phone number is already registered. Forgot password?', [ 'link_forgot' => 'href="' . $this->forgotUrl() . '"', ]), 'phone_number' ); break; } } # Password if ($this->hasPassword()) { if (empty($data['password'])) { $this->errors->set(_t('users', 'Enter password'), 'password'); break; } if (! $this->security->validatePassword($data['password'])) { break; } if ( $this->hasPasswordConfirm() && (empty($data['password2']) || $data['password'] !== $data['password2']) ) { $this->errors->set(_t('users', 'Incorrect password confirmation'), 'password2'); break; } } # Blocks $data = $this->validateBlocks($data); if ($this->errors->any()) { break; } # Captcha if ($this->hasCaptcha()) { if (! $this->isCaptchaValid($this->captcha_key)) { break; } } # Agreement if (! $this->validateAgreement($data['agreement'])) { break; } } while (false); # Only data to store in database unset($data['agreement'], $data['password2']); if ($this->phoneOnly()) { unset($data['email']); } if ($this->emailOnly()) { unset($data['phone_number']); } if (! $this->hasPassword()) { unset($data['password']); } return $data; } public function submit() { do { if ($this->request->user()) { $this->respond('redirect', $this->router->url('index')); break; } if (! $this->security->validateReferer()) { $this->errors->reloadPage(); break; } $data = $this->validate(); if ($this->errors->any()) { break; } if ($this->tooManyRequests($this->getKey(), 10)) { break; } $registered = $this->registerAndNotify($data); if (empty($registered)) { break; } # Store data for next steps $this->startData($registered); # Response $this->respond('success', true); if ($this->emailOnly()) { $this->respond('redirect', $this->registrationUrl('emailed')); } else { $this->respond('redirect', $this->registrationUrl('phone')); } } while (false); # Preserve Return url $this->respond('back', $this->request->post('back', TYPE_NOTAGS)); return parent::submit(); } /** * Validate data and register user * @param array $data to create user account [?email, ?phone_number, ?password, ...] * @return array|bool registered data or false (something went wrong) */ public function registerAndNotify(array $data = []): array { $response = false; do { $email = $data['email'] ?? ''; $phone = $data['phone_number'] ?? ''; # Create new user account $user = Users::userRegister($data); if (empty($user)) { $this->errors->set(_t('users', 'Registration error, contact the administrator')); break; } $userId = $user['user_id']; $password = $user['password']; # Send confirmation notification via email/sms $response = [ 'id' => $userId, 'password' => $password, 'activate_link' => $user['activate_link'], ]; if ($this->emailOnly()) { # Send email notification with link (activate_link) (validate on "Activate" step) Users::sendEmailRegistrationConfirmation($userId, $email, $password, $user['activate_link']); } elseif ($this->phoneOnly()) { $password = $this->updateUserPassword($userId, $user['activate_key']); # Send activation key as password via sms (validate on "PhoneConfirmation" step) Users::sms(false)->sendPassword($phone, $password); } elseif ($this->phoneAndEmail()) { # Send activation code via sms (validate on "PhoneConfirmation" step) Users::sms(false)->sendActivationCode($phone, $user['activate_key']); } } while (false); return $response; } /** * Use email field in form * @return bool */ public function hasEmail() { return ( $this->emailOnly() || $this->phoneAndEmail() ); } /** * Use phone number field in form * @return bool */ public function hasPhoneNumber() { return ( $this->phoneOnly() || $this->phoneAndEmail() ); } /** * Use password field in form * @return bool */ public function hasPassword() { return ! $this->phoneOnly(); } /** * Use password confirmation field in form * @return bool */ public function hasPasswordConfirm() { if ($this->hasPassword()) { return $this->pass_confirm; } return false; } /** * Use captcha field in form * @return bool */ public function hasCaptcha() { return Captcha::enabled($this->captcha_key); } /** * @inheritdoc */ public function settingsForm($form) { $form->text('title', _t('@site', 'Form Title'), _t('users', 'Registration', true)); $form->checkbox('pass_confirm', _t('@users', 'Password confirmation'), $this->pass_confirm) ->tip(_t('@users', 'Show the repeat password field in the registration form')); $form->select('captcha', _t('@users', 'Captcha at Sign Up'), $this->captcha, function () { return Captcha::actionDriverOptions(); }) ->sysAdmin('captcha.enabled.' . $this->captcha_key); } }