Register::action_register2()   F
last analyzed

Complexity

Conditions 25
Paths 2304

Size

Total Lines 88
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 650

Importance

Changes 0
Metric Value
cc 25
eloc 32
dl 0
loc 88
rs 0
c 0
b 0
f 0
nc 2304
nop 0
ccs 0
cts 31
cp 0
crap 650

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
 * @package   ElkArte Forum
9
 * @copyright ElkArte Forum contributors
10
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
11
 *
12
 * This file contains code covered by:
13
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
14
 *
15
 * @version 2.0 Beta 1
16
 *
17
 */
18
19
namespace ElkArte\Controller;
20
21
use ElkArte\AbstractController;
22
use ElkArte\Action;
23
use ElkArte\Agreement;
24
use ElkArte\Errors\ErrorContext;
25
use ElkArte\Errors\Errors;
0 ignored issues
show
Bug introduced by
The type ElkArte\Errors\Errors was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use ElkArte\Exceptions\Exception;
27
use ElkArte\Helper\DataValidator;
28
use ElkArte\Helper\Util;
29
use ElkArte\Languages\Txt;
30
use ElkArte\PrivacyPolicy;
31
use ElkArte\Profile\ProfileFields;
32
use ElkArte\Profile\ProfileOptions;
33
use ElkArte\Request;
34
35
/**
36
 * It registers new members, and it allows the administrator to moderate member registration
37
 */
38
class Register extends AbstractController
39
{
40
	/** @var int is_activated value key is as follows */
41
	private const STATUS_NOT_ACTIVE = 0;
42
	private const STATUS_APPROVED_AND_ACTIVE = 1;
43
	private const STATUS_AWAITING_REACTIVATION = 2;
44
	private const STATUS_AWAITING_COPPA = 5;
45
46
	/** @var array Holds the results of a findUser() request */
47
	private $_row;
48
49
	/**
50
	 * {@inheritDoc}
51
	 */
52
	public function trackStats($action = '')
53
	{
54
		return parent::trackStats($action);
55
	}
56
57
	/**
58
	 * Pre-dispatch, called before other methods.
59
	 */
60
	public function pre_dispatch()
61
	{
62
		global $modSettings;
63
64
		// Check if the administrator has it disabled.
65
		if (empty($modSettings['registration_method']))
66
		{
67
			return;
68
		}
69
70
		if ((int) $modSettings['registration_method'] !== 3)
71
		{
72
			return;
73
		}
74
75
		throw new Exception('registration_disabled', false);
76
	}
77
78
	/**
79
	 * Intended entry point for this class.
80
	 *
81
	 * By default, this is called for action=register
82
	 *
83
	 * @see AbstractController::action_index
84
	 */
85
	public function action_index()
86
	{
87
		// Add the sub-action array to dispatch accordingly
88
		$subActions = [
89
			'register' => [$this, 'action_register'],
90
			'register2' => [$this, 'action_register2'],
91
			'usernamecheck' => [$this, 'action_registerCheckUsername'],
92
			'activate' => [$this, 'action_activate'],
93
			'agrelang' => [$this, 'action_agrelang'],
94
			'privacypol' => [$this, 'action_privacypol'],
95
			'agreement' => [$this, 'action_agreement'],
96
		];
97
98
		// Set up the action handler
99
		$action = new Action('register');
100
		$subAction = $action->initialize($subActions, 'register');
101
102
		// Call the action
103
		$action->dispatch($subAction);
104
	}
105
106
	/**
107
	 * Begin the registration process.
108
	 *
109
	 * - Triggers the prepare_context event
110
	 *
111
	 * Accessed by ?action=register
112
	 *
113
	 * @uses template_registration_agreement or template_registration_form sub template in Register.template,
114
	 * @uses Login language file
115
	 */
116
	public function action_register(): void
117
	{
118
		global $txt, $context, $modSettings, $scripturl;
119
120
		// If this user is an admin - redirect them to the admin registration page.
121
		if ($this->user->is_guest === false && allowedTo('moderate_forum'))
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
122
		{
123
			redirectexit('action=admin;area=regcenter;sa=register');
124
		}
125
		// You are not a guest, so you are a member - and members don't get to register twice!
126
		elseif (empty($this->user->is_guest))
127
		{
128
			redirectexit();
129
		}
130
131
		// Confused and want to contact the admins instead
132
		if (isset($this->_req->post->show_contact))
133
		{
134
			redirectexit('action=about;sa=contact');
135
		}
136
137
		// If we have language support enabled, then they need to be loaded
138
		if ($this->_load_language_support())
139
		{
140
			redirectexit('action=register');
141
		}
142
143
		Txt::load('Login+Profile');
144
		theme()->getTemplates()->load('Register');
145
		theme()->getTemplates()->load('ProfileOptions');
146
147
		// Do we need them to agree to the registration agreement, first?
148
		$context['require_agreement'] = !empty($modSettings['requireAgreement']);
149
		$context['checkbox_agreement'] = !empty($modSettings['checkboxAgreement']);
150
		$context['require_privacypol'] = !empty($modSettings['requirePrivacypolicy']);
151
		$context['registration_passed_agreement'] = !empty($_SESSION['registration_agreed']);
152
		$context['registration_passed_privacypol'] = !empty($_SESSION['registration_privacypolicy']);
153
		$context['show_coppa'] = !empty($modSettings['coppaAge']);
154
		$context['show_contact_button'] = !empty($modSettings['enable_contactform']) && $modSettings['enable_contactform'] === 'registration';
155
		$context['insert_display_name'] = !empty($modSettings['show_DisplayNameOnRegistration']);
156
157
		// Underage restrictions?
158
		if ($context['show_coppa'])
159
		{
160
			$context['skip_coppa'] = false;
161
			$context['coppa_agree_above'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_above'], $modSettings['coppaAge']);
162
			$context['coppa_agree_below'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_below'], $modSettings['coppaAge']);
163
		}
164
165
		// What step are we at?
166
		$current_step = $this->_req->getPost('step', 'intval', ($context['require_agreement'] && !$context['checkbox_agreement'] ? 1 : 2));
167
168
		// Does this user agree to the registration agreement?
169
		if ($current_step === 1 && (isset($this->_req->post->accept_agreement) || isset($this->_req->post->accept_agreement_coppa)))
170
		{
171
			$context['registration_passed_agreement'] = $_SESSION['registration_agreed'] = true;
172
			$context['registration_passed_privacypol'] = $_SESSION['registration_privacypolicy'] = true;
173
			$current_step = 2;
174
175
			// Skip the coppa procedure if the user says he's old enough.
176
			if ($context['show_coppa'])
177
			{
178
				$_SESSION['skip_coppa'] = !empty($this->_req->post->accept_agreement);
179
180
				// Are they saying they're underage, while underage registration is disabled?
181
				if (empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
182
				{
183
					throw new Exception('Login.under_age_registration_prohibited', false, [$modSettings['coppaAge']]);
184
				}
185
			}
186
		}
187
		// Make sure they don't squeeze through without agreeing.
188
		elseif ($current_step > 1 && $context['require_agreement'] && !$context['checkbox_agreement'] && !$context['registration_passed_agreement'])
189
		{
190
			$current_step = 1;
191
		}
192
193
		// Show the user the right form.
194
		$context['sub_template'] = $current_step === 1 ? 'registration_agreement' : 'registration_form';
195
		$context['page_title'] = $current_step === 1 ? $txt['registration_agreement'] : $txt['registration_form'];
196
		loadJavascriptFile(['register.js', 'ext/mailcheck.min.js']);
197
198
		// Add the register chain to the link tree.
199
		$context['breadcrumbs'][] = [
200
			'url' => $scripturl . '?action=register',
201
			'name' => $txt['register'],
202
		];
203
204
		// Prepare the time gate! Done like this to allow later steps to reset the limit for any reason
205
		if (!isset($_SESSION['register']))
206
		{
207
			$_SESSION['register'] = [
208
				'timenow' => time(),
209
				// minimum number of seconds required on this page for registration
210
				'limit' => 8,
211
			];
212
		}
213
		else
214
		{
215
			$_SESSION['register']['timenow'] = time();
216
		}
217
218
		// If you have to agree to the agreement, it needs to be fetched from the file.
219
		$agreement = new Agreement($this->user->language);
0 ignored issues
show
Bug Best Practice introduced by
The property language does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
220
		$context['agreement'] = $agreement->getParsedText();
221
222
		if (empty($context['agreement']))
223
		{
224
			// No file found or a blank file, log the error so the admin knows there is a problem!
225
			Txt::load('Errors');
226
			Errors::instance()->log_error($txt['registration_agreement_missing'], 'critical');
227
			throw new Exception('registration_disabled', false);
228
		}
229
230
		if (!empty($context['require_privacypol']))
231
		{
232
			$privacypol = new PrivacyPolicy($this->user->language);
233
			$context['privacy_policy'] = $privacypol->getParsedText();
234
235
			if (empty($context['privacy_policy']))
236
			{
237
				// No file found or a blank file, log the error so the admin knows there is a problem!
238
				Txt::load('Errors');
239
				Errors::instance()::instance()->log_error($txt['registration_privacy_policy_missing'], 'critical');
240
				throw new \Exception('registration_disabled', false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $code of Exception::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

240
				throw new \Exception('registration_disabled', /** @scrutinizer ignore-type */ false);
Loading history...
241
			}
242
		}
243
244
		// If we have language support enabled, then they need to be loaded
245
		$this->_load_language_support();
246
247
		// Any custom or standard profile fields we want filled in during registration?
248
		$this->_load_profile_fields();
249
250
		// Trigger the prepare_context event
251
		$this->_events->trigger('prepare_context', ['current_step' => $current_step]);
252
253
		// See whether we have some pre-filled values.
254
		$context['username'] = $this->_req->getPost('user', 'Util::htmlspecialchars', '');
255
		$context['email'] = $this->_req->getPost('email', 'Util::htmlspecialchars', '');
256
		$context['notify_announcements'] = (int) !empty($this->_req->post->notify_announcements);
257
258
		// Were there any errors?
259
		$context['registration_errors'] = [];
260
		$reg_errors = ErrorContext::context('register', 0);
261
		if ($reg_errors->hasErrors())
262
		{
263
			$context['registration_errors'] = $reg_errors->prepareErrors();
264
		}
265
266
		createToken('register');
267
	}
268
269
	/**
270
	 * Handles the registration process for members using ElkArte registration
271
	 *
272
	 * What it does:
273
	 *
274
	 * - Validates all requirements have been filled in properly
275
	 * - Passes final processing to do_register
276
	 * - Directs back to register on errors
277
	 * - Triggers the before_complete_register event
278
	 *
279
	 * Accessed by ?action=register;sa=register2
280
	 */
281
	public function action_register2(): void
282
	{
283
		global $modSettings;
284
285
		// Start collecting together any errors.
286
		$reg_errors = ErrorContext::context('register', 0);
287
288
		// Make sure registration is enabled
289
		$this->_can_register();
290
291
		checkSession();
292
		if (!validateToken('register', 'post', true, false))
293
		{
294
			$reg_errors->addError('token_verification');
295
		}
296
297
		// If we're using an agreement checkbox, did they check it?
298
		if (!empty($modSettings['checkboxAgreement']) && !empty($this->_req->post->checkbox_agreement))
299
		{
300
			$_SESSION['registration_agreed'] = true;
301
		}
302
303
		// Using coppa and the registration checkbox?
304
		if (!empty($modSettings['coppaAge']) && !empty($modSettings['checkboxAgreement']) && !empty($this->_req->post->accept_agreement))
305
		{
306
			$_SESSION['skip_coppa'] = true;
307
		}
308
309
		// Well, if you don't agree to the Registration Agreement, you can't register.
310
		if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed']))
311
		{
312
			redirectexit();
313
		}
314
315
		if (!empty($modSettings['requireAgreement']) && !empty($modSettings['requirePrivacypolicy']) && !empty($this->_req->post->checkbox_privacypol))
316
		{
317
			$_SESSION['registration_privacypolicy'] = true;
318
		}
319
320
		// Well, if you don't agree to the Privacy Policy, you can't register.
321
		if (!empty($modSettings['requireAgreement']) && !empty($modSettings['requirePrivacypolicy']) && empty($_SESSION['registration_privacypolicy']))
322
		{
323
			redirectexit();
324
		}
325
326
		// Make sure they came from *somewhere*, have a session.
327
		if (!isset($_SESSION['old_url']))
328
		{
329
			redirectexit('action=register');
330
		}
331
332
		// If we don't require an agreement, we need an extra check for coppa.
333
		if (empty($modSettings['requireAgreement']) && !empty($modSettings['coppaAge']))
334
		{
335
			$_SESSION['skip_coppa'] = !empty($this->_req->post->accept_agreement);
336
		}
337
338
		// Are they underage, and underage users are banned?
339
		if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa']))
340
		{
341
			throw new Exception('Login.under_age_registration_prohibited', false, [$modSettings['coppaAge']]);
342
		}
343
344
		// Check the time gate for miscreants. First, make sure they came from somewhere that actually set it up.
345
		if (empty($_SESSION['register']['timenow']) || empty($_SESSION['register']['limit']))
346
		{
347
			redirectexit('action=register');
348
		}
349
350
		// Failing that, check the time limit for excessive speed.
351
		if (time() - $_SESSION['register']['timenow'] < $_SESSION['register']['limit'])
352
		{
353
			Txt::load('Login');
354
			$reg_errors->addError('too_quickly');
355
		}
356
357
		// Maybe they filled in our hidden honey pot form field like a good bot would
358
		if (!empty($this->_req->getPost('reason_for_joining_hp', 'trim', '')))
359
		{
360
			// It's not missing, it just should not be there
361
			Txt::load('Login');
362
			$reg_errors->addError('error_missing_information');
363
		}
364
365
		// Trigger any events required before we complete registration, like captcha verification
366
		$this->_events->trigger('before_complete_register', ['reg_errors' => $reg_errors]);
367
368
		$this->do_register();
369
	}
370
371
	/**
372
	 * Actually register the member.
373
	 *
374
	 * - Called from Register controller
375
	 * - Does the actual registration to the system
376
	 */
377
	public function do_register(): ?bool
378
	{
379
		global $txt, $modSettings, $context;
380
381
		// Start collecting together any errors.
382
		$reg_errors = ErrorContext::context('register', 0);
383
384
		// Clean the form values
385
		foreach ($this->_req->post as $key => $value)
386
		{
387
			if (!is_array($value))
388
			{
389
				$this->_req->post->{$key} = Util::htmltrim__recursive(str_replace(["\n", "\r"], '', $value));
390
			}
391
		}
392
393
		// A little security to any secret answer ... @todo increase?
394
		if ($this->_req->getPost('secret_answer', 'trim', '') !== '')
395
		{
396
			$this->_req->post->secret_answer = md5($this->_req->post->secret_answer);
397
		}
398
399
		// Needed for isReservedName() and registerMember().
400
		require_once(SUBSDIR . '/Members.subs.php');
401
402
		// Validation... even if we're not a mall.
403
		if (isset($this->_req->post->real_name) && (!empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum')))
404
		{
405
			$this->_req->post->real_name = trim(preg_replace('~[\t\n\r \x0B\0\x{A0}\x{AD}\x{2000}-\x{200F}\x{201F}\x{202F}\x{3000}\x{FEFF}]+~u', ' ', $this->_req->post->real_name));
406
			$has_real_name = true;
407
		}
408
		else
409
		{
410
			$has_real_name = false;
411
		}
412
413
		// Handle a string as a birthdate...
414
		if ($this->_req->getPost('birthdate', 'trim', '') !== '')
415
		{
416
			$this->_req->post->birthdate = Util::strftime('%Y-%m-%d', strtotime($this->_req->post->birthdate));
417
		}
418
		// Or birthdate parts...
419
		elseif (!empty($this->_req->post->bday1) && !empty($this->_req->post->bday2))
420
		{
421
			$this->_req->post->birthdate = sprintf('%04d-%02d-%02d', empty($this->_req->post->bday3) ? 0 : (int) $this->_req->post->bday3, (int) $this->_req->post->bday1, (int) $this->_req->post->bday2);
422
		}
423
424
		// Validate the passed language file.
425
		if (isset($this->_req->post->lngfile) && !empty($modSettings['userLanguage']))
426
		{
427
			// Do we have any languages?
428
			$context['languages'] = getLanguages();
429
430
			// Did we find it?
431
			if (isset($context['languages'][$this->_req->post->lngfile]))
432
			{
433
				$_SESSION['language'] = $this->_req->post->lngfile;
434
			}
435
			else
436
			{
437
				$this->_req->clearValue('lngfile', 'post');
438
			}
439
		}
440
		elseif (isset($this->_req->post->lngfile))
441
		{
442
			$this->_req->clearValue('lngfile', 'post');
443
		}
444
445
		// Set the options needed for registration.
446
		$regOptions = [
447
			'interface' => 'guest',
448
			'username' => empty($this->_req->post->user) ? '' : $this->_req->post->user,
449
			'email' => empty($this->_req->post->email) ? '' : $this->_req->post->email,
450
			'password' => empty($this->_req->post->passwrd1) ? '' : $this->_req->post->passwrd1,
451
			'password_check' => empty($this->_req->post->passwrd2) ? '' : $this->_req->post->passwrd2,
452
			'auth_method' => empty($this->_req->post->authenticate) ? '' : $this->_req->post->authenticate,
453
			'check_reserved_name' => true,
454
			'check_password_strength' => true,
455
			'check_email_ban' => true,
456
			'send_welcome_email' => !empty($modSettings['send_welcomeEmail']),
457
			'require' => !empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')),
458
			'extra_register_vars' => $this->_extra_vars($has_real_name),
459
		];
460
461
		// Registration options are always default options...
462
		if (isset($this->_req->post->default_options))
463
		{
464
			$this->_req->post->options = isset($this->_req->post->options) ? $this->_req->post->options + $this->_req->post->default_options : $this->_req->post->default_options;
465
		}
466
467
		$regOptions['theme_vars'] = isset($this->_req->post->options) && is_array($this->_req->post->options) ? $this->_req->post->options : [];
468
469
		// Make sure they are clean, dammit!
470
		$regOptions['theme_vars'] = Util::htmlspecialchars__recursive($regOptions['theme_vars']);
471
472
		// Check whether we have fields that simply MUST be displayed?
473
		$profileFields = new ProfileFields();
474
		$profileFields->loadCustomFields(0, 'register', $this->_req->post->customfield ?? []);
475
476
		foreach ($context['custom_fields'] as $row)
477
		{
478
			// Don't allow overriding of the theme variables.
479
			if (isset($regOptions['theme_vars'][$row['colname']]))
480
			{
481
				unset($regOptions['theme_vars'][$row['colname']]);
482
			}
483
484
			// Prepare the value!
485
			$value = isset($this->_req->post->customfield[$row['colname']]) ? trim($this->_req->post->customfield[$row['colname']]) : '';
486
487
			// We only care for text fields as the others are valid to be empty.
488
			if (!in_array($row['field_type'], ['check', 'select', 'radio']))
489
			{
490
				$is_valid = isCustomFieldValid($row, $value);
491
				if ($is_valid !== true)
492
				{
493
					$err_params = [$row['name']];
494
					if ($is_valid === 'custom_field_too_long')
495
					{
496
						$err_params[] = $row['field_length'];
497
					}
498
499
					$reg_errors->addError([$is_valid, $err_params]);
500
				}
501
			}
502
503
			// Is this required but not there?
504
			if ($row['show_reg'] > 1 && trim($value) === '')
505
			{
506
				$reg_errors->addError(['custom_field_empty', [$row['name']]]);
507
			}
508
		}
509
510
		// Let's check for other errors before trying to register the member.
511
		if ($reg_errors->hasErrors())
512
		{
513
			$this->_req->post->step = 2;
514
515
			// If they've filled in some details but made an error, then they need less time to finish
516
			$_SESSION['register']['limit'] = 4;
517
518
			$this->action_register();
519
520
			return false;
521
		}
522
523
		// Registration needs to know your IP
524
		$req = Request::instance();
525
526
		$regOptions['ip'] = $this->user->ip;
0 ignored issues
show
Bug Best Practice introduced by
The property ip does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
527
		$regOptions['ip2'] = $req->ban_ip();
528
		$memberID = registerMember($regOptions);
529
530
		// If there are "important" errors, and you are not an admin: log the first error
531
		// Otherwise grab all of them and don't log anything
532
		if ($reg_errors->hasErrors(1) && $this->user->is_admin === false)
0 ignored issues
show
Bug Best Practice introduced by
The property is_admin does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
533
		{
534
			$errors = $reg_errors->prepareErrors(1);
535
			throw new Exception(reset($errors), 'general');
536
		}
537
538
		// Was there actually an error of some kind, dear boy?
539
		if ($reg_errors->hasErrors())
540
		{
541
			$this->_req->post->step = 2;
542
			$this->action_register();
543
544
			return false;
545
		}
546
547
		$lang = empty($modSettings['userLanguage']) ? 'english' : $modSettings['userLanguage'];
548
		$agreement = new Agreement($lang);
549
		$agreement->accept($memberID, $this->user->ip, empty($modSettings['agreementRevision']) ? Util::strftime('%Y-%m-%d', forum_time(false)) : $modSettings['agreementRevision']);
550
551
		if (!empty($modSettings['requirePrivacypolicy']))
552
		{
553
			$policy = new PrivacyPolicy($lang);
554
			$policy->accept($memberID, $this->user->ip, empty($modSettings['privacypolicyRevision']) ? Util::strftime('%Y-%m-%d', forum_time(false)) : $modSettings['privacypolicyRevision']);
555
		}
556
557
		// Do our spam protection now.
558
		spamProtection('register');
559
560
		// We'll do custom fields after as then we get to use the helper function!
561
		if (!empty($this->_req->post->customfield))
562
		{
563
			require_once(SUBSDIR . '/Profile.subs.php');
564
			makeCustomFieldChanges($memberID, 'register');
565
		}
566
567
		// If COPPA has been selected, then things get complicated, set up the template.
568
		if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa']))
569
		{
570
			redirectexit('action=about;sa=coppa;member=' . $memberID);
571
		}
572
		// Basic template variable setup.
573
		elseif (!empty($modSettings['registration_method']))
574
		{
575
			theme()->getTemplates()->load('Register');
576
577
			$context += [
578
				'page_title' => $txt['register'],
579
				'title' => $txt['registration_successful'],
580
				'sub_template' => 'after',
581
				'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']
582
			];
583
		}
584
		else
585
		{
586
			call_integration_hook('integrate_activate', [$regOptions['username'], 1, 1]);
587
588
			setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash('sha256', $regOptions['register_vars']['passwd'] . $regOptions['register_vars']['password_salt']));
589
590
			redirectexit('action=auth;sa=check;member=' . $memberID);
591
		}
592
593
		return null;
594
	}
595
596
	/**
597
	 * Checks if registrations are enabled and the user didn't just register
598
	 */
599
	private function _can_register(): void
600
	{
601
		global $modSettings;
602
603
		// You can't register if it's disabled.
604
		if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3)
605
		{
606
			throw new Exception('registration_disabled', false);
607
		}
608
609
		// Make sure they didn't just register with this session.
610
		if (!empty($_SESSION['just_registered']) && empty($modSettings['disableRegisterCheck']))
611
		{
612
			throw new Exception('register_only_once', false);
613
		}
614
	}
615
616
	/**
617
	 * Collect all extra registration fields someone might have filled in.
618
	 *
619
	 * What it does:
620
	 *
621
	 * - Classifies variables as possible string, int, float, or bool
622
	 * - Casts all posted data to the proper type (string, float, etc.)
623
	 * - Drops fields that we specially exclude during registration
624
	 *
625
	 * @param bool $has_real_name - if true adds 'real_name' as well
626
	 *
627
	 * @return array
628
	 * @throws Exception
629
	 */
630
	private function _extra_vars($has_real_name): array
631
	{
632
		global $modSettings;
633
634
		// Define the fields that may be enabled for registration
635
		$possible_strings = [
636
			'birthdate',
637
			'time_format',
638
			'buddy_list',
639
			'pm_ignore_list',
640
			'smiley_set',
641
			'avatar',
642
			'lngfile',
643
			'secret_question', 'secret_answer',
644
			'website_url', 'website_title',
645
		];
646
647
		$possible_ints = [
648
			'pm_email_notify',
649
			'notify_types',
650
			'notify_from',
651
			'id_theme',
652
		];
653
654
		$possible_floats = [
655
			'time_offset',
656
		];
657
658
		$possible_bools = [
659
			'notify_announcements', 'notify_regularity', 'notify_send_body', 'show_online',
660
		];
661
662
		if ($has_real_name && trim($this->_req->post->real_name) !== '' && !isReservedName($this->_req->post->real_name) && Util::strlen($this->_req->post->real_name) < 60)
663
		{
664
			$possible_strings[] = 'real_name';
665
		}
666
667
		// Some of these fields we may not want.
668
		if (!empty($modSettings['registration_fields']))
669
		{
670
			// But we might want some of them if the admin asks for them.
671
			$reg_fields = explode(',', $modSettings['registration_fields']);
672
673
			$exclude_fields = [];
674
675
			// Website is a little different
676
			if (!in_array('website', $reg_fields))
677
			{
678
				$exclude_fields = array_merge($exclude_fields, ['website_url', 'website_title']);
679
			}
680
681
			// We used to accept signature on registration, but it's being abused by spammers these days, so no more.
682
			$exclude_fields[] = 'signature';
683
		}
684
		else
685
		{
686
			$exclude_fields = ['signature', 'website_url', 'website_title'];
687
		}
688
689
		$possible_strings = array_diff($possible_strings, $exclude_fields);
690
		$possible_ints = array_diff($possible_ints, $exclude_fields);
691
		$possible_floats = array_diff($possible_floats, $exclude_fields);
692
		$possible_bools = array_diff($possible_bools, $exclude_fields);
693
694
		$extra_register_vars = [];
695
696
		// Include the additional options that might have been filled in.
697
		foreach ($possible_strings as $var)
698
		{
699
			if (isset($this->_req->post->{$var}))
700
			{
701
				$extra_register_vars[$var] = Util::htmlspecialchars($this->_req->post->{$var}, ENT_QUOTES);
702
			}
703
		}
704
705
		foreach ($possible_ints as $var)
706
		{
707
			if (isset($this->_req->post->{$var}))
708
			{
709
				$extra_register_vars[$var] = (int) $this->_req->post->{$var};
710
			}
711
		}
712
713
		foreach ($possible_floats as $var)
714
		{
715
			if (isset($this->_req->post->{$var}))
716
			{
717
				$extra_register_vars[$var] = (float) $this->_req->post->{$var};
718
			}
719
		}
720
721
		foreach ($possible_bools as $var)
722
		{
723
			if (isset($this->_req->post->{$var}))
724
			{
725
				$extra_register_vars[$var] = empty($this->_req->post->{$var}) ? 0 : 1;
726
			}
727
		}
728
729
		return $extra_register_vars;
730
	}
731
732
	/**
733
	 * Sets the users language file
734
	 *
735
	 * What it does:
736
	 *
737
	 * - If language support is enabled, loads what's available
738
	 * - Verifies the users choice is available
739
	 * - Sets in context / session
740
	 *
741
	 * @return bool true if the language was changed, false if not.
742
	 */
743
	private function _load_language_support(): bool
744
	{
745
		global $context, $modSettings, $language;
746
747
		// Language support enabled
748
		if (!empty($modSettings['userLanguage']))
749
		{
750
			// Do we have any languages?
751
			$languages = getLanguages();
752
753
			if (isset($this->_req->post->lngfile, $languages[$this->_req->post->lngfile]))
754
			{
755
				$_SESSION['language'] = $this->_req->post->lngfile;
756
				if ($_SESSION['language'] !== ucfirst($this->user->language))
0 ignored issues
show
Bug introduced by
It seems like $this->user->language can also be of type null; however, parameter $string of ucfirst() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

756
				if ($_SESSION['language'] !== ucfirst(/** @scrutinizer ignore-type */ $this->user->language))
Loading history...
Bug Best Practice introduced by
The property language does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
757
				{
758
					return true;
759
				}
760
			}
761
762
			// Not selected, or not found, use the site default
763
			$selectedLanguage = empty($_SESSION['language']) ? $language : $_SESSION['language'];
764
765
			// Try to find our selected language.
766
			foreach ($languages as $key => $lang)
767
			{
768
				$context['languages'][$key]['name'] = $lang['name'];
769
770
				// Found it!
771
				if (ucfirst($selectedLanguage) === $lang['name'])
772
				{
773
					$context['languages'][$key]['selected'] = true;
774
				}
775
			}
776
		}
777
778
		return false;
779
	}
780
781
	/**
782
	 * Load standard and custom registration profile fields
783
	 *
784
	 * @uses ProfileFields->loadCustomFields() Loads standard fields in to context
785
	 * @uses setupProfileContext() Loads supplied fields in to context
786
	 */
787
	private function _load_profile_fields(): void
788
	{
789
		global $context, $modSettings, $cur_profile;
790
791
		// Any custom fields to load?
792
		$profileFields = new ProfileFields();
793
		$profileFields->loadCustomFields(0, 'register');
794
795
		// Or any standard ones?
796
		if (!empty($modSettings['registration_fields']))
797
		{
798
			// Set up some important context.
799
			Txt::load('Profile');
800
			theme()->getTemplates()->load('Profile');
801
802
			$context['user']['is_owner'] = true;
803
804
			// Here, and here only, emulate the permissions the user would have to do this.
805
			$this->user->permissions = array_merge($this->user->permissions, ['profile_account_own', 'profile_extra_own']);
0 ignored issues
show
Bug introduced by
It seems like $this->user->permissions can also be of type null; however, parameter $arrays of array_merge() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

805
			$this->user->permissions = array_merge(/** @scrutinizer ignore-type */ $this->user->permissions, ['profile_account_own', 'profile_extra_own']);
Loading history...
Bug Best Practice introduced by
The property permissions does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property permissions does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __set, consider adding a @property annotation.
Loading history...
806
			$reg_fields = ProfileOptions::getFields('registration');
807
808
			// We might have had some submissions on this front - go check.
809
			foreach ($reg_fields['fields'] as $field)
810
			{
811
				if (isset($this->_req->post->{$field}))
812
				{
813
					$cur_profile[$field] = Util::htmlspecialchars($this->_req->post->{$field});
814
				}
815
			}
816
817
			// Load all the fields in question.
818
			setupProfileContext($reg_fields['fields'], $reg_fields['hook']);
819
		}
820
	}
821
822
	/**
823
	 * Verify the activation code and activate the user if correct.
824
	 *
825
	 * What it does:
826
	 *
827
	 * - Accessed by ?action=register;sa=activate
828
	 * - Processes activation code requests
829
	 * - Checks if the user is already activated and if so does nothing
830
	 * - Prevents a user from using an existing email
831
	 */
832
	public function action_activate(): void
833
	{
834
		global $context, $txt, $modSettings;
835
836
		require_once(SUBSDIR . '/Auth.subs.php');
837
838
		// Logged-in users should not bother to activate their accounts
839
		if (!empty($this->user->id))
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
840
		{
841
			redirectexit();
842
		}
843
844
		Txt::load('Login');
845
		theme()->getTemplates()->load('Login');
846
847
		// Need a user id to activate
848
		if (empty($this->_req->query->u) && empty($this->_req->post->user))
849
		{
850
			// Immediate 0 or disabled 3 means no need to try and activate
851
			if (empty($modSettings['registration_method']) || $modSettings['registration_method'] === '3')
852
			{
853
				throw new Exception('no_access', false);
854
			}
855
856
			// Otherwise it's simply invalid
857
			$context['member_id'] = 0;
858
			$context['sub_template'] = 'resend';
859
			$context['page_title'] = $txt['invalid_activation_resend'];
860
			$context['can_activate'] = $modSettings['registration_method'] === '1';
861
			$context['default_username'] = $this->_req->getPost('user', 'trim', '');
862
863
			return;
864
		}
865
866
		// Get the user from the database...
867
		$this->_row = findUser(empty($this->_req->query->u)
0 ignored issues
show
Documentation Bug introduced by
It seems like findUser(empty($this->_r...', 'trim', '')), false) can also be of type boolean. However, the property $_row is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
868
			? 'member_name = {string:email_address} OR email_address = {string:email_address}'
869
			: 'id_member = {int:id_member}',
870
			[
871
				'id_member' => $this->_req->getQuery('u', 'intval', 0),
872
				'email_address' => $this->_req->getPost('user', 'trim', ''),
873
			], false
874
		);
875
876
		// Does this user exist at all?
877
		if (empty($this->_row))
878
		{
879
			$context['sub_template'] = 'retry_activate';
880
			$context['page_title'] = $txt['invalid_userid'];
881
			$context['member_id'] = 0;
882
883
			return;
884
		}
885
886
		// Change their email address if not active 0 or awaiting reactivation 2? (they probably tried a fake one first :P)
887
		$email_change = $this->_activate_change_email();
888
889
		// Resend the password, but only if the account wasn't activated yet (0 or 2)
890
		$this->_activate_resend($email_change);
891
892
		// Quit if this code is not right.
893
		if ($this->_activate_validate_code() === false)
894
		{
895
			return;
896
		}
897
898
		// Validation completed - update the database!
899
		require_once(SUBSDIR . '/Members.subs.php');
900
		approveMembers(['members' => [$this->_row['id_member']], 'activated_status' => $this->_row['is_activated']]);
901
902
		// Also do a proper member stat re-evaluation.
903
		require_once(SUBSDIR . '/Members.subs.php');
904
		updateMemberStats();
905
906
		if (!isset($this->_req->post->new_email) && empty($this->_row['is_activated']))
907
		{
908
			require_once(SUBSDIR . '/Notification.subs.php');
909
			sendAdminNotifications('activation', $this->_row['id_member'], $this->_row['member_name']);
910
		}
911
912
		$context += [
913
			'page_title' => $txt['registration_successful'],
914
			'sub_template' => 'login',
915
			'default_username' => $this->_row['member_name'],
916
			'default_password' => '',
917
			'never_expire' => false,
918
			'description' => $txt['activate_success']
919
		];
920
	}
921
922
	/**
923
	 * Change their email address if not active
924
	 *
925
	 * What it does:
926
	 *
927
	 * - Requires the user to enter the id/password for the account
928
	 * - The account must not be active 0 or awaiting reactivation 2
929
	 */
930
	private function _activate_change_email(): bool
931
	{
932
		global $modSettings, $txt;
933
934
		if (isset($this->_req->post->new_email, $this->_req->post->passwd)
935
			&& ($this->_row['is_activated'] === self::STATUS_NOT_ACTIVE || $this->_row['is_activated'] === self::STATUS_AWAITING_REACTIVATION)
936
			&& validateLoginPassword($this->_req->post->passwd, $this->_row['passwd'], $this->_row['member_name'], true))
937
		{
938
			if (empty($modSettings['registration_method']) || $modSettings['registration_method'] == 3)
939
			{
940
				throw new Exception('no_access', false);
941
			}
942
943
			// @todo Separate the sprintf?
944
			if (!DataValidator::is_valid($this->_req->post, ['new_email' => 'valid_email|required|max_length[255]'], ['new_email' => 'trim']))
945
			{
946
				throw new Exception(sprintf($txt['valid_email_needed'], htmlspecialchars($this->_req->post->new_email, ENT_COMPAT, 'UTF-8')), false);
947
			}
948
949
			// Make sure their email isn't banned.
950
			isBannedEmail($this->_req->post->new_email, 'cannot_register', $txt['ban_register_prohibited']);
951
952
			// Ummm... don't take someone else's email during the change
953
			// @todo Separate the sprintf?
954
			if (userByEmail($this->_req->post->new_email) === false)
955
			{
956
				throw new Exception('email_in_use', false, [htmlspecialchars($this->_req->post->new_email, ENT_COMPAT, 'UTF-8')]);
957
			}
958
959
			require_once(SUBSDIR . '/Members.subs.php');
960
			updateMemberData($this->_row['id_member'], ['email_address' => $this->_req->post->new_email]);
961
			$this->_row['email_address'] = $this->_req->post->new_email;
962
963
			return true;
964
		}
965
966
		return false;
967
	}
968
969
	/**
970
	 * Resend an activation code to a user
971
	 *
972
	 * What it does:
973
	 *
974
	 * - Called with action=register;sa=activate;resend
975
	 * - Will resend an activation code to non-active account
976
	 *
977
	 * @param bool $email_change if the email was changed or not
978
	 *
979
	 * @throws Exception
980
	 */
981
	private function _activate_resend($email_change): void
982
	{
983
		global $scripturl, $modSettings, $language, $txt, $context;
984
985
		if (isset($this->_req->query->resend)
986
			&& ($this->_row['is_activated'] === self::STATUS_NOT_ACTIVE || $this->_row['is_activated'] === self::STATUS_AWAITING_REACTIVATION)
987
			&& $this->_req->getPost('code', 'trim', '') === '')
988
		{
989
			require_once(SUBSDIR . '/Mail.subs.php');
990
991
			// Since you lost it, you get a nice new code
992
			$validation_code = generateValidationCode(14);
993
			$this->_row['validation_code'] = substr(hash('sha256', $validation_code), 0, 10);
994
995
			require_once(SUBSDIR . '/Members.subs.php');
996
			updateMemberData($this->_row['id_member'], ['validation_code' => $this->_row['validation_code']]);
997
998
			$replacements = [
999
				'REALNAME' => $this->_row['real_name'],
1000
				'USERNAME' => $this->_row['member_name'],
1001
				'ACTIVATIONLINK' => $scripturl . '?action=register;sa=activate;u=' . $this->_row['id_member'] . ';code=' . $validation_code,
1002
				'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=register;sa=activate;u=' . $this->_row['id_member'],
1003
				'ACTIVATIONCODE' => $validation_code,
1004
				'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder',
1005
			];
1006
1007
			$emaildata = loadEmailTemplate('resend_activate_message', $replacements, empty($this->_row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $this->_row['lngfile']);
1008
			sendmail($this->_row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 0);
1009
1010
			$context['page_title'] = $txt['invalid_activation_resend'];
1011
1012
			// Don't let them wack away on their resend
1013
			spamProtection('remind');
1014
1015
			// This will ensure we don't actually get an error message if it works!
1016
			$context['error_title'] = $txt['invalid_activation_resend'];
1017
			throw new Exception(empty($email_change) ? 'resend_email_success' : 'change_email_success', false);
1018
		}
1019
	}
1020
1021
	/**
1022
	 * Validates a supplied activation code is valid
1023
	 *
1024
	 * @throws Exception already_activated, registration_not_approved
1025
	 */
1026
	private function _activate_validate_code(): bool
1027
	{
1028
		global $txt, $scripturl, $context;
1029
1030
		$code = substr(hash('sha256', $this->_req->getQuery('code', 'trim', '')), 0, 10);
1031
1032
		if ($code !== $this->_row['validation_code'])
1033
		{
1034
			if (!empty($this->_row['is_activated']) && $this->_row['is_activated'] === self::STATUS_APPROVED_AND_ACTIVE)
1035
			{
1036
				throw new Exception('already_activated', false);
1037
			}
1038
			if ($this->_row['validation_code'] === '')
1039
			{
1040
				Txt::load('Profile');
1041
				throw new Exception($txt['registration_not_approved'] . ' <a href="' . $scripturl . '?action=register;sa=activate;user=' . $this->_row['member_name'] . '">' . $txt['here'] . '</a>.', false);
1042
			}
1043
			$context['sub_template'] = 'retry_activate';
1044
			$context['page_title'] = $txt['invalid_activation_code'];
1045
			$context['member_id'] = $this->_row['id_member'];
1046
			return false;
1047
		}
1048
1049
		return true;
1050
	}
1051
1052
	/**
1053
	 * See if a username already exists.
1054
	 *
1055
	 * - Used by registration template via XML request
1056
	 */
1057
	public function action_registerCheckUsername(): void
1058
	{
1059
		global $context;
1060
1061
		// This is XML!
1062
		theme()->getTemplates()->load('Xml');
1063
		$context['sub_template'] = 'check_username';
1064
		$context['checked_username'] = isset($this->_req->query->username) ? un_htmlspecialchars($this->_req->query->username) : '';
1065
		$context['valid_username'] = true;
1066
1067
		// Clean it up like mother would.
1068
		$context['checked_username'] = preg_replace('~[\t\n\r \x0B\0\x{A0}\x{AD}\x{2000}-\x{200F}\x{201F}\x{202F}\x{3000}\x{FEFF}]+~u', ' ', $context['checked_username']);
1069
1070
		$errors = ErrorContext::context('valid_username', 0);
1071
1072
		require_once(SUBSDIR . '/Auth.subs.php');
1073
		validateUsername(0, $context['checked_username'], 'valid_username', true, false);
1074
1075
		$context['valid_username'] = !$errors->hasErrors();
1076
	}
1077
1078
	public function action_agreement(): void
1079
	{
1080
		global $context, $modSettings, $txt;
1081
1082
		if (isset($this->_req->post->accept_agreement))
1083
		{
1084
			$agreement = new Agreement($this->user->language);
0 ignored issues
show
Bug Best Practice introduced by
The property language does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
1085
			$agreement->accept($this->user->id, $this->user->ip, empty($modSettings['agreementRevision']) ? Util::strftime('%Y-%m-%d', forum_time(false)) : $modSettings['agreementRevision']);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property ip does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
1086
1087
			$_SESSION['agreement_accepted'] = true;
1088
			if (isset($_SESSION['agreement_url_redirect']))
1089
			{
1090
				redirectexit($_SESSION['agreement_url_redirect']);
1091
			}
1092
			else
1093
			{
1094
				redirectexit();
1095
			}
1096
		}
1097
		elseif (isset($this->_req->post->no_accept))
1098
		{
1099
			redirectexit('action=profile;area=deleteaccount');
1100
		}
1101
		else
1102
		{
1103
			$context['sub_template'] = 'registration_agreement';
1104
			$context['register_subaction'] = 'agreement';
1105
		}
1106
1107
		Txt::load('Login');
1108
		Txt::load('Profile');
1109
		theme()->getTemplates()->load('Register');
1110
1111
		// If you have to agree to the agreement, it needs to be fetched from the file.
1112
		$agreement = new Agreement($this->user->language);
1113
		$context['agreement'] = $agreement->getParsedText();
1114
		$context['page_title'] = $txt['registration_agreement'];
1115
1116
		$context['show_coppa'] = !empty($modSettings['coppaAge']);
1117
		$context['show_contact_button'] = !empty($modSettings['enable_contactform']) && $modSettings['enable_contactform'] === 'registration';
1118
1119
		// Underage restrictions?
1120
		if ($context['show_coppa'])
1121
		{
1122
			$context['skip_coppa'] = false;
1123
			$context['coppa_agree_above'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_above'], $modSettings['coppaAge']);
1124
			$context['coppa_agree_below'] = sprintf($txt[($context['require_agreement'] ? 'agreement_' : '') . 'agree_coppa_below'], $modSettings['coppaAge']);
1125
		}
1126
1127
		createToken('register');
1128
	}
1129
1130
	/**
1131
	 * Action for handling privacy policy acceptance during registration.
1132
	 *
1133
	 * - Called from Register controller
1134
	 * - Handles the acceptance and redirection
1135
	 *    - If the user accepts the privacy policy, it updates the user's acceptance status in the database,
1136
	 *      sets a session variable indicating acceptance, and redirects the user to the specified URL.
1137
	 *    - If the user declines the privacy policy, it redirects the user to the account deletion page.
1138
	 *    - If the user has not yet made a decision, it loads the registration agreement template for displaying the privacy policy.
1139
	 */
1140
	public function action_privacypol(): void
1141
	{
1142
		global $context, $modSettings, $txt;
1143
1144
		$policy = new PrivacyPolicy($this->user->language);
0 ignored issues
show
Bug Best Practice introduced by
The property language does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
1145
1146
		if (isset($this->_req->post->accept_agreement))
1147
		{
1148
			$policy->accept($this->user->id, $this->user->ip, empty($modSettings['privacypolicyRevision']) ? Util::strftime('%Y-%m-%d', forum_time(false)) : $modSettings['privacypolicyRevision']);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property ip does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
1149
1150
			$_SESSION['privacypolicy_accepted'] = true;
1151
			if (isset($_SESSION['privacypolicy_url_redirect']))
1152
			{
1153
				redirectexit($_SESSION['privacypolicy_url_redirect']);
1154
			}
1155
			else
1156
			{
1157
				redirectexit();
1158
			}
1159
		}
1160
		elseif (isset($this->_req->post->no_accept))
1161
		{
1162
			redirectexit('action=profile;area=deleteaccount');
1163
		}
1164
		else
1165
		{
1166
			$context['sub_template'] = 'registration_agreement';
1167
			$context['register_subaction'] = 'privacypol';
1168
		}
1169
1170
		Txt::load('Login');
1171
		Txt::load('Profile');
1172
		theme()->getTemplates()->load('Register');
1173
1174
		$txt['agreement_agree'] = $txt['policy_agree'];
1175
		$txt['agreement_no_agree'] = $txt['policy_no_agree'];
1176
		$txt['registration_agreement'] = $txt['registration_privacy_policy'];
1177
		$context['page_title'] = $txt['registration_agreement'];
1178
1179
		// If you have to agree to the privacy policy, it needs to be fetched from the file.
1180
		$context['agreement'] = $policy->getParsedText();
1181
1182
		$context['show_coppa'] = false;
1183
		$context['skip_coppa'] = true;
1184
		$context['show_contact_button'] = !empty($modSettings['enable_contactform']) && $modSettings['enable_contactform'] === 'registration';
1185
1186
		createToken('register');
1187
	}
1188
}
1189