3 use wcf\acp\form\UserAddForm
;
4 use wcf\data\user\avatar\Gravatar
;
5 use wcf\data\user\avatar\UserAvatarAction
;
6 use wcf\data\user\group\UserGroup
;
7 use wcf\data\user\User
;
8 use wcf\data\user\UserAction
;
9 use wcf\data\user\UserEditor
;
10 use wcf\data\user\UserProfile
;
11 use wcf\system\captcha\CaptchaHandler
;
12 use wcf\system\exception\NamedUserException
;
13 use wcf\system\exception\PermissionDeniedException
;
14 use wcf\system\exception\SystemException
;
15 use wcf\system\exception\UserInputException
;
16 use wcf\system\language\LanguageFactory
;
17 use wcf\system\mail\Mail
;
18 use wcf\system\request\LinkHandler
;
19 use wcf\system\user\authentication\UserAuthenticationFactory
;
22 use wcf\util\HeaderUtil
;
23 use wcf\util\StringUtil
;
24 use wcf\util\UserRegistrationUtil
;
27 * Shows the user registration form.
30 * @copyright 2001-2016 WoltLab GmbH
31 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
32 * @package com.woltlab.wcf
34 * @category Community Framework
36 class RegisterForm
extends UserAddForm
{
40 public $enableTracking = true;
43 * true if external authentication is used
46 public $isExternalAuthentication = false;
51 public $neededPermissions = [];
54 * holds a language variable with information about the registration process
55 * e.g. if you need to activate your account
63 public $captchaObjectType = null;
68 public $captchaObjectTypeName = CAPTCHA_TYPE
;
73 public $useCaptcha = REGISTER_USE_CAPTCHA
;
79 public $randomFieldNames = [];
82 * min number of seconds between form request and submit
85 public static $minRegistrationTime = 10;
90 public function readParameters() {
91 parent
::readParameters();
93 // user is already registered
94 if (WCF
::getUser()->userID
) {
95 throw new PermissionDeniedException();
98 // registration disabled
99 if (REGISTER_DISABLED
) {
100 throw new NamedUserException(WCF
::getLanguage()->get('wcf.user.register.error.disabled'));
104 if (REGISTER_ENABLE_DISCLAIMER
&& !WCF
::getSession()->getVar('disclaimerAccepted')) {
105 HeaderUtil
::redirect(LinkHandler
::getInstance()->getLink('Disclaimer'));
109 if (WCF
::getSession()->getVar('__3rdPartyProvider')) {
110 $this->isExternalAuthentication
= true;
117 public function readFormParameters() {
118 parent
::readFormParameters();
120 if (!empty($this->username
) ||
!empty($this->email
)) {
121 throw new PermissionDeniedException();
124 $this->randomFieldNames
= WCF
::getSession()->getVar('registrationRandomFieldNames');
125 if ($this->randomFieldNames
=== null) {
126 throw new PermissionDeniedException();
129 if (isset($_POST[$this->randomFieldNames
['username']])) $this->username
= StringUtil
::trim($_POST[$this->randomFieldNames
['username']]);
130 if (isset($_POST[$this->randomFieldNames
['email']])) $this->email
= StringUtil
::trim($_POST[$this->randomFieldNames
['email']]);
131 if (isset($_POST[$this->randomFieldNames
['confirmEmail']])) $this->confirmEmail
= StringUtil
::trim($_POST[$this->randomFieldNames
['confirmEmail']]);
132 if (isset($_POST[$this->randomFieldNames
['password']])) $this->password
= $_POST[$this->randomFieldNames
['password']];
133 if (isset($_POST[$this->randomFieldNames
['confirmPassword']])) $this->confirmPassword
= $_POST[$this->randomFieldNames
['confirmPassword']];
135 $this->groupIDs
= [];
137 if ($this->captchaObjectType
) {
138 $this->captchaObjectType
->getProcessor()->readFormParameters();
143 * wcf\acp\form\AbstractOptionListForm::initOptionHandler()
145 protected function initOptionHandler() {
146 $this->optionHandler
->setInRegistration();
147 parent
::initOptionHandler();
153 public function validate() {
154 // validate captcha first
155 $this->validateCaptcha();
159 // validate registration time
160 if (!$this->isExternalAuthentication
&& (!WCF
::getSession()->getVar('registrationStartTime') ||
(TIME_NOW
- WCF
::getSession()->getVar('registrationStartTime')) < self
::$minRegistrationTime)) {
161 throw new UserInputException('registrationStartTime', []);
168 public function readData() {
169 if ($this->useCaptcha
&& $this->captchaObjectTypeName
) {
170 $this->captchaObjectType
= CaptchaHandler
::getInstance()->getObjectTypeByName($this->captchaObjectTypeName
);
171 if ($this->captchaObjectType
=== null) {
172 throw new SystemException("Unknown captcha object type with id '".$this->captchaObjectTypeName
."'");
175 if (!$this->captchaObjectType
->getProcessor()->isAvailable()) {
176 $this->captchaObjectType
= null;
179 if (WCF
::getSession()->getVar('noRegistrationCaptcha')) {
180 $this->captchaObjectType
= null;
187 $this->languageID
= WCF
::getLanguage()->languageID
;
189 if (WCF
::getSession()->getVar('__username')) {
190 $this->username
= WCF
::getSession()->getVar('__username');
191 WCF
::getSession()->unregister('__username');
193 if (WCF
::getSession()->getVar('__email')) {
194 $this->email
= $this->confirmEmail
= WCF
::getSession()->getVar('__email');
195 WCF
::getSession()->unregister('__email');
198 WCF
::getSession()->register('registrationStartTime', TIME_NOW
);
200 // generate random field names
201 $this->randomFieldNames
= [
202 'username' => UserRegistrationUtil
::getRandomFieldName('username'),
203 'email' => UserRegistrationUtil
::getRandomFieldName('email'),
204 'confirmEmail' => UserRegistrationUtil
::getRandomFieldName('confirmEmail'),
205 'password' => UserRegistrationUtil
::getRandomFieldName('password'),
206 'confirmPassword' => UserRegistrationUtil
::getRandomFieldName('confirmPassword')
209 WCF
::getSession()->register('registrationRandomFieldNames', $this->randomFieldNames
);
214 * Reads option tree on page init.
216 protected function readOptionTree() {
217 $this->optionTree
= $this->optionHandler
->getOptionTree('profile');
223 public function assignVariables() {
224 parent
::assignVariables();
226 WCF
::getTPL()->assign([
227 'captchaObjectType' => $this->captchaObjectType
,
228 'isExternalAuthentication' => $this->isExternalAuthentication
,
229 'randomFieldNames' => $this->randomFieldNames
236 public function show() {
237 AbstractForm
::show();
241 * Validates the captcha.
243 protected function validateCaptcha() {
244 if ($this->captchaObjectType
) {
246 $this->captchaObjectType
->getProcessor()->validate();
248 catch (UserInputException
$e) {
249 $this->errorType
[$e->getField()] = $e->getType();
257 protected function validateUsername($username) {
258 parent
::validateUsername($username);
260 // check for min-max length
261 if (!UserRegistrationUtil
::isValidUsername($username)) {
262 throw new UserInputException('username', 'notValid');
269 protected function validatePassword($password, $confirmPassword) {
270 if (!$this->isExternalAuthentication
) {
271 parent
::validatePassword($password, $confirmPassword);
273 // check security of the given password
274 if (!UserRegistrationUtil
::isSecurePassword($password)) {
275 throw new UserInputException('password', 'notSecure');
283 protected function validateEmail($email, $confirmEmail) {
284 parent
::validateEmail($email, $confirmEmail);
286 if (!UserRegistrationUtil
::isValidEmail($email)) {
287 throw new UserInputException('email', 'notValid');
294 public function save() {
295 AbstractForm
::save();
298 $saveOptions = $this->optionHandler
->save();
299 $registerVia3rdParty = false;
302 if ($this->isExternalAuthentication
) {
303 switch (WCF
::getSession()->getVar('__3rdPartyProvider')) {
306 if (WCF
::getSession()->getVar('__githubData')) {
307 $githubData = WCF
::getSession()->getVar('__githubData');
309 $this->additionalFields
['authData'] = 'github:'.$githubData['id'];
311 WCF
::getSession()->unregister('__githubData');
312 WCF
::getSession()->unregister('__githubToken');
314 if (WCF
::getSession()->getVar('__email') && WCF
::getSession()->getVar('__email') == $this->email
) {
315 $registerVia3rdParty = true;
318 if (isset($githubData['bio']) && User
::getUserOptionID('aboutMe') !== null) $saveOptions[User
::getUserOptionID('aboutMe')] = $githubData['bio'];
319 if (isset($githubData['location']) && User
::getUserOptionID('location') !== null) $saveOptions[User
::getUserOptionID('location')] = $githubData['location'];
324 if (WCF
::getSession()->getVar('__twitterData')) {
325 $twitterData = WCF
::getSession()->getVar('__twitterData');
326 $this->additionalFields
['authData'] = 'twitter:'.$twitterData['user_id'];
328 WCF
::getSession()->unregister('__twitterData');
330 if (isset($twitterData['description']) && User
::getUserOptionID('aboutMe') !== null) $saveOptions[User
::getUserOptionID('aboutMe')] = $twitterData['description'];
331 if (isset($twitterData['location']) && User
::getUserOptionID('location') !== null) $saveOptions[User
::getUserOptionID('location')] = $twitterData['location'];
336 if (WCF
::getSession()->getVar('__facebookData')) {
337 $facebookData = WCF
::getSession()->getVar('__facebookData');
338 $this->additionalFields
['authData'] = 'facebook:'.$facebookData['id'];
340 WCF
::getSession()->unregister('__facebookData');
342 if (isset($facebookData['email']) && $facebookData['email'] == $this->email
) {
343 $registerVia3rdParty = true;
346 if (isset($facebookData['gender']) && User
::getUserOptionID('gender') !== null) $saveOptions[User
::getUserOptionID('gender')] = ($facebookData['gender'] == 'male' ? UserProfile
::GENDER_MALE
: UserProfile
::GENDER_FEMALE
);
348 if (isset($facebookData['birthday']) && User
::getUserOptionID('birthday') !== null) {
349 list($month, $day, $year) = explode('/', $facebookData['birthday']);
350 $saveOptions[User
::getUserOptionID('birthday')] = $year.'-'.$month.'-'.$day;
352 if (isset($facebookData['bio']) && User
::getUserOptionID('bio') !== null) $saveOptions[User
::getUserOptionID('aboutMe')] = $facebookData['bio'];
353 if (isset($facebookData['location']) && User
::getUserOptionID('location') !== null) $saveOptions[User
::getUserOptionID('location')] = $facebookData['location']['name'];
354 if (isset($facebookData['website']) && User
::getUserOptionID('website') !== null) {
355 $urls = preg_split('/[\s,;]/', $facebookData['website'], -1, PREG_SPLIT_NO_EMPTY
);
357 if (!Regex
::compile('^https?://')->match($urls[0])) {
358 $urls[0] = 'http://' . $urls[0];
361 $saveOptions[User
::getUserOptionID('homepage')] = $urls[0];
366 if (isset($facebookData['picture']) && !$facebookData['picture']['data']['is_silhouette']) {
367 $avatarURL = $facebookData['picture']['data']['url'];
373 if (WCF
::getSession()->getVar('__googleData')) {
374 $googleData = WCF
::getSession()->getVar('__googleData');
375 $this->additionalFields
['authData'] = 'google:'.$googleData['id'];
377 WCF
::getSession()->unregister('__googleData');
379 if (isset($googleData['emails'][0]['value']) && $googleData['emails'][0]['value'] == $this->email
) {
380 $registerVia3rdParty = true;
383 if (isset($googleData['gender']) && User
::getUserOptionID('gender') !== null) {
384 switch ($googleData['gender']) {
386 $saveOptions[User
::getUserOptionID('gender')] = UserProfile
::GENDER_MALE
;
389 $saveOptions[User
::getUserOptionID('gender')] = UserProfile
::GENDER_FEMALE
;
393 if (isset($googleData['birthday']) && User
::getUserOptionID('birthday') !== null) $saveOptions[User
::getUserOptionID('birthday')] = $googleData['birthday'];
394 if (isset($googleData['placesLived']) && User
::getUserOptionID('location') !== null) {
395 // save primary location
396 $saveOptions[User
::getUserOptionID('location')] = current(array_map(
397 function ($element) { return $element['value']; },
398 array_filter($googleData['placesLived'], function ($element) { return isset($element['primary']) && $element['primary']; })
403 if (isset($googleData['image']['url'])) {
404 $avatarURL = $googleData['image']['url'];
410 // create fake password
411 $this->password
= StringUtil
::getRandomID();
414 $this->additionalFields
['languageID'] = $this->languageID
;
415 if (LOG_IP_ADDRESS
) $this->additionalFields
['registrationIpAddress'] = WCF
::getSession()->ipAddress
;
417 // generate activation code
418 $addDefaultGroups = true;
419 if ((REGISTER_ACTIVATION_METHOD
== 1 && !$registerVia3rdParty) || REGISTER_ACTIVATION_METHOD
== 2) {
420 $activationCode = UserRegistrationUtil
::getActivationCode();
421 $this->additionalFields
['activationCode'] = $activationCode;
422 $addDefaultGroups = false;
423 $this->groupIDs
= UserGroup
::getGroupIDsByType([UserGroup
::EVERYONE
, UserGroup
::GUESTS
]);
426 // check gravatar support
427 if (MODULE_GRAVATAR
&& Gravatar
::test($this->email
)) {
428 $this->additionalFields
['enableGravatar'] = 1;
433 'data' => array_merge($this->additionalFields
, [
434 'username' => $this->username
,
435 'email' => $this->email
,
436 'password' => $this->password
,
438 'groups' => $this->groupIDs
,
439 'languageIDs' => $this->visibleLanguages
,
440 'options' => $saveOptions,
441 'addDefaultGroups' => $addDefaultGroups
443 $this->objectAction
= new UserAction([], 'create', $data);
444 $result = $this->objectAction
->executeAction();
445 $user = $result['returnValues'];
446 $userEditor = new UserEditor($user);
449 WCF
::getSession()->changeUser($user);
451 // set avatar if provided
452 if (!empty($avatarURL)) {
453 $userAvatarAction = new UserAvatarAction([], 'fetchRemoteAvatar', [
455 'userEditor' => $userEditor
457 $userAvatarAction->executeAction();
460 // activation management
461 if (REGISTER_ACTIVATION_METHOD
== 0) {
462 $this->message
= 'wcf.user.register.success';
464 else if (REGISTER_ACTIVATION_METHOD
== 1) {
465 // registering via 3rdParty leads to instant activation
466 if ($registerVia3rdParty) {
467 $this->message
= 'wcf.user.register.success';
470 $mail = new Mail([$this->username
=> $this->email
],
471 WCF
::getLanguage()->getDynamicVariable('wcf.user.register.needActivation.mail.subject'),
472 WCF
::getLanguage()->getDynamicVariable('wcf.user.register.needActivation.mail', ['user' => $user])
475 $this->message
= 'wcf.user.register.needActivation';
478 else if (REGISTER_ACTIVATION_METHOD
== 2) {
479 $this->message
= 'wcf.user.register.awaitActivation';
483 if (REGISTER_ADMIN_NOTIFICATION
) {
484 // get default language
485 $language = LanguageFactory
::getInstance()->getLanguage(LanguageFactory
::getInstance()->getDefaultLanguageID());
488 $mail = new Mail(MAIL_ADMIN_ADDRESS
,
489 $language->getDynamicVariable('wcf.user.register.notification.mail.subject'),
490 $language->getDynamicVariable('wcf.user.register.notification.mail', ['user' => $user])
492 $mail->setLanguage($language);
496 if ($this->captchaObjectType
) {
497 $this->captchaObjectType
->getProcessor()->reset();
500 if (WCF
::getSession()->getVar('noRegistrationCaptcha')) {
501 WCF
::getSession()->unregister('noRegistrationCaptcha');
505 UserAuthenticationFactory
::getInstance()->getUserAuthentication()->storeAccessData($user, $this->username
, $this->password
);
506 WCF
::getSession()->unregister('registrationRandomFieldNames');
507 WCF
::getSession()->unregister('registrationStartTime');
510 // forward to index page
511 HeaderUtil
::delayedRedirect(LinkHandler
::getInstance()->getLink(), WCF
::getLanguage()->getDynamicVariable($this->message
, ['user' => $user]), 15);