Completed
Push — release-2.1 ( 6f6d35...abeae7 )
by Mathias
08:46
created

ManageRegistration.php ➔ AdminRegister()   D

Complexity

Conditions 13
Paths 8

Size

Total Lines 88
Code Lines 55

Duplication

Lines 5
Ratio 5.68 %

Importance

Changes 0
Metric Value
cc 13
eloc 55
nc 8
nop 0
dl 5
loc 88
rs 4.9922
c 0
b 0
f 0

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 helps the administrator setting registration settings and policy
5
 * as well as allow the administrator to register new members themselves.
6
 *
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines http://www.simplemachines.org
11
 * @copyright 2017 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 Beta 4
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
/**
21
 * Entrance point for the registration center, it checks permissions and forwards
22
 * to the right function based on the subaction.
23
 * Accessed by ?action=admin;area=regcenter.
24
 * Requires either the moderate_forum or the admin_forum permission.
25
 *
26
 * @uses Login language file
27
 * @uses Register template.
28
 */
29
function RegCenter()
30
{
31
	global $context, $txt;
32
33
	// Old templates might still request this.
34
	if (isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'browse')
35
		redirectexit('action=admin;area=viewmembers;sa=browse' . (isset($_REQUEST['type']) ? ';type=' . $_REQUEST['type'] : ''));
36
37
	$subActions = array(
38
		'register' => array('AdminRegister', 'moderate_forum'),
39
		'agreement' => array('EditAgreement', 'admin_forum'),
40
		'reservednames' => array('SetReserved', 'admin_forum'),
41
		'settings' => array('ModifyRegistrationSettings', 'admin_forum'),
42
	);
43
44
	// Work out which to call...
45
	$context['sub_action'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : (allowedTo('moderate_forum') ? 'register' : 'settings');
46
47
	// Must have sufficient permissions.
48
	isAllowedTo($subActions[$context['sub_action']][1]);
49
50
	// Loading, always loading.
51
	loadLanguage('Login');
52
	loadTemplate('Register');
53
54
	// Next create the tabs for the template.
55
	$context[$context['admin_menu_name']]['tab_data'] = array(
56
		'title' => $txt['registration_center'],
57
		'help' => 'registrations',
58
		'description' => $txt['admin_settings_desc'],
59
		'tabs' => array(
60
			'register' => array(
61
				'description' => $txt['admin_register_desc'],
62
			),
63
			'agreement' => array(
64
				'description' => $txt['registration_agreement_desc'],
65
			),
66
			'reservednames' => array(
67
				'description' => $txt['admin_reserved_desc'],
68
			),
69
			'settings' => array(
70
				'description' => $txt['admin_settings_desc'],
71
			)
72
		)
73
	);
74
75
	call_integration_hook('integrate_manage_registrations', array(&$subActions));
76
77
	// Finally, get around to calling the function...
78
	call_helper($subActions[$context['sub_action']][0]);
79
}
80
81
/**
82
 * This function allows the admin to register a new member by hand.
83
 * It also allows assigning a primary group to the member being registered.
84
 * Accessed by ?action=admin;area=regcenter;sa=register
85
 * Requires the moderate_forum permission.
86
 *
87
 * @uses Register template, admin_register sub-template.
88
 */
89
function AdminRegister()
90
{
91
	global $txt, $context, $sourcedir, $scripturl, $smcFunc;
92
93
	// Are there any custom profile fields required during registration?
94
	require_once($sourcedir . '/Profile.php');
95
	loadCustomFields(0, 'register');
96
97
	if (!empty($_POST['regSubmit']))
98
	{
99
		checkSession();
100
		validateToken('admin-regc');
101
102 View Code Duplication
		foreach ($_POST as $key => $value)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
103
			if (!is_array($_POST[$key]))
104
				$_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
105
106
		$regOptions = array(
107
			'interface' => 'admin',
108
			'username' => $_POST['user'],
109
			'email' => $_POST['email'],
110
			'password' => $_POST['password'],
111
			'password_check' => $_POST['password'],
112
			'check_reserved_name' => true,
113
			'check_password_strength' => false,
114
			'check_email_ban' => false,
115
			'send_welcome_email' => isset($_POST['emailPassword']) || empty($_POST['password']),
116
			'require' => isset($_POST['emailActivate']) ? 'activation' : 'nothing',
117
			'memberGroup' => empty($_POST['group']) || !allowedTo('manage_membergroups') ? 0 : (int) $_POST['group'],
118
		);
119
120
		require_once($sourcedir . '/Subs-Members.php');
121
		$memberID = registerMember($regOptions);
122
		if (!empty($memberID))
123
		{
124
			// We'll do custom fields after as then we get to use the helper function!
125
			if (!empty($_POST['customfield']))
126
			{
127
				require_once($sourcedir . '/Profile-Modify.php');
128
				makeCustomFieldChanges($memberID, 'register');
0 ignored issues
show
Bug introduced by
It seems like $memberID defined by registerMember($regOptions) on line 121 can also be of type array; however, makeCustomFieldChanges() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
129
			}
130
131
			$context['new_member'] = array(
132
				'id' => $memberID,
133
				'name' => $_POST['user'],
134
				'href' => $scripturl . '?action=profile;u=' . $memberID,
135
				'link' => '<a href="' . $scripturl . '?action=profile;u=' . $memberID . '">' . $_POST['user'] . '</a>',
136
			);
137
			$context['registration_done'] = sprintf($txt['admin_register_done'], $context['new_member']['link']);
138
		}
139
	}
140
141
142
	// Load the assignable member groups.
143
	if (allowedTo('manage_membergroups'))
144
	{
145
		$request = $smcFunc['db_query']('', '
146
			SELECT group_name, id_group
147
			FROM {db_prefix}membergroups
148
			WHERE id_group != {int:moderator_group}
149
				AND min_posts = {int:min_posts}' . (allowedTo('admin_forum') ? '' : '
150
				AND id_group != {int:admin_group}
151
				AND group_type != {int:is_protected}') . '
152
				AND hidden != {int:hidden_group}
153
			ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
154
			array(
155
				'moderator_group' => 3,
156
				'min_posts' => -1,
157
				'admin_group' => 1,
158
				'is_protected' => 1,
159
				'hidden_group' => 2,
160
				'newbie_group' => 4,
161
			)
162
		);
163
		$context['member_groups'] = array(0 => $txt['admin_register_group_none']);
164 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($request))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165
			$context['member_groups'][$row['id_group']] = $row['group_name'];
166
		$smcFunc['db_free_result']($request);
167
	}
168
	else
169
		$context['member_groups'] = array();
170
171
	// Basic stuff.
172
	$context['sub_template'] = 'admin_register';
173
	$context['page_title'] = $txt['registration_center'];
174
	createToken('admin-regc');
175
	loadJavaScriptFile('register.js', array('defer' => false), 'smf_register');
176
}
177
178
/**
179
 * Allows the administrator to edit the registration agreement, and choose whether
180
 * it should be shown or not. It writes and saves the agreement to the agreement.txt
181
 * file.
182
 * Accessed by ?action=admin;area=regcenter;sa=agreement.
183
 * Requires the admin_forum permission.
184
 *
185
 * @uses Admin template and the edit_agreement sub template.
186
 */
187
function EditAgreement()
188
{
189
	// I hereby agree not to be a lazy bum.
190
	global $txt, $boarddir, $context, $modSettings, $smcFunc;
191
192
	// By default we look at agreement.txt.
193
	$context['current_agreement'] = '';
194
195
	// Is there more than one to edit?
196
	$context['editable_agreements'] = array(
197
		'' => $txt['admin_agreement_default'],
198
	);
199
200
	// Get our languages.
201
	getLanguages();
202
203
	// Try to figure out if we have more agreements.
204
	foreach ($context['languages'] as $lang)
0 ignored issues
show
Bug introduced by
The expression $context['languages'] of type string|array<string,?,{"":"?"}> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
205
	{
206
		if (file_exists($boarddir . '/agreement.' . $lang['filename'] . '.txt'))
207
		{
208
			$context['editable_agreements']['.' . $lang['filename']] = $lang['name'];
209
			// Are we editing this?
210
			if (isset($_POST['agree_lang']) && $_POST['agree_lang'] == '.' . $lang['filename'])
211
				$context['current_agreement'] = '.' . $lang['filename'];
212
		}
213
	}
214
215
	if (isset($_POST['agreement']))
216
	{
217
		checkSession();
218
		validateToken('admin-rega');
219
220
		// Off it goes to the agreement file.
221
		$to_write = str_replace("\r", '', $_POST['agreement']);
222
		$bytes = file_put_contents($boarddir . '/agreement' . $context['current_agreement'] . '.txt', $to_write, LOCK_EX);
223
224
		updateSettings(array('requireAgreement' => !empty($_POST['requireAgreement'])));
225
226
		if ($bytes == strlen($to_write))
227
			$context['saved_successful'] = true;
228
		else
229
			$context['could_not_save'] = true;
230
	}
231
232
	$context['agreement'] = file_exists($boarddir . '/agreement' . $context['current_agreement'] . '.txt') ? $smcFunc['htmlspecialchars'](file_get_contents($boarddir . '/agreement' . $context['current_agreement'] . '.txt')) : '';
233
	$context['warning'] = is_writable($boarddir . '/agreement' . $context['current_agreement'] . '.txt') ? '' : $txt['agreement_not_writable'];
234
	$context['require_agreement'] = !empty($modSettings['requireAgreement']);
235
236
	$context['sub_template'] = 'edit_agreement';
237
	$context['page_title'] = $txt['registration_agreement'];
238
	createToken('admin-rega');
239
}
240
241
/**
242
 * Set the names under which users are not allowed to register.
243
 * Accessed by ?action=admin;area=regcenter;sa=reservednames.
244
 * Requires the admin_forum permission.
245
 *
246
 * @uses Register template, reserved_words sub-template.
247
 */
248
function SetReserved()
249
{
250
	global $txt, $context, $modSettings;
251
252
	// Submitting new reserved words.
253
	if (!empty($_POST['save_reserved_names']))
254
	{
255
		checkSession();
256
		validateToken('admin-regr');
257
258
		// Set all the options....
259
		updateSettings(array(
260
			'reserveWord' => (isset($_POST['matchword']) ? '1' : '0'),
261
			'reserveCase' => (isset($_POST['matchcase']) ? '1' : '0'),
262
			'reserveUser' => (isset($_POST['matchuser']) ? '1' : '0'),
263
			'reserveName' => (isset($_POST['matchname']) ? '1' : '0'),
264
			'reserveNames' => str_replace("\r", '', $_POST['reserved'])
265
		));
266
		$context['saved_successful'] = true;
267
	}
268
269
	// Get the reserved word options and words.
270
	$modSettings['reserveNames'] = str_replace('\n', "\n", $modSettings['reserveNames']);
271
	$context['reserved_words'] = explode("\n", $modSettings['reserveNames']);
272
	$context['reserved_word_options'] = array();
273
	$context['reserved_word_options']['match_word'] = $modSettings['reserveWord'] == '1';
274
	$context['reserved_word_options']['match_case'] = $modSettings['reserveCase'] == '1';
275
	$context['reserved_word_options']['match_user'] = $modSettings['reserveUser'] == '1';
276
	$context['reserved_word_options']['match_name'] = $modSettings['reserveName'] == '1';
277
278
	// Ready the template......
279
	$context['sub_template'] = 'edit_reserved_words';
280
	$context['page_title'] = $txt['admin_reserved_set'];
281
	createToken('admin-regr');
282
}
283
284
/**
285
 * This function handles registration settings, and provides a few pretty stats too while it's at it.
286
 * General registration settings and Coppa compliance settings.
287
 * Accessed by ?action=admin;area=regcenter;sa=settings.
288
 * Requires the admin_forum permission.
289
 *
290
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
291
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
292
 */
293
function ModifyRegistrationSettings($return_config = false)
294
{
295
	global $txt, $context, $scripturl, $modSettings, $sourcedir;
296
297
	// This is really quite wanting.
298
	require_once($sourcedir . '/ManageServer.php');
299
300
	$config_vars = array(
301
			array('select', 'registration_method', array($txt['setting_registration_standard'], $txt['setting_registration_activate'], $txt['setting_registration_approval'], $txt['setting_registration_disabled'])),
302
			array('check', 'send_welcomeEmail'),
303
		'',
304
			array('int', 'coppaAge', 'subtext' => $txt['zero_to_disable'], 'onchange' => 'checkCoppa();', 'onkeyup' => 'checkCoppa();'),
305
			array('select', 'coppaType', array($txt['setting_coppaType_reject'], $txt['setting_coppaType_approval']), 'onchange' => 'checkCoppa();'),
306
			array('large_text', 'coppaPost', 'subtext' => $txt['setting_coppaPost_desc']),
307
			array('text', 'coppaFax'),
308
			array('text', 'coppaPhone'),
309
	);
310
311
	call_integration_hook('integrate_modify_registration_settings', array(&$config_vars));
312
313
	if ($return_config)
314
		return $config_vars;
315
316
	// Setup the template
317
	$context['sub_template'] = 'show_settings';
318
	$context['page_title'] = $txt['registration_center'];
319
320
	if (isset($_GET['save']))
321
	{
322
		checkSession();
323
324
		// Are there some contacts missing?
325
		if (!empty($_POST['coppaAge']) && !empty($_POST['coppaType']) && empty($_POST['coppaPost']) && empty($_POST['coppaFax']))
326
			fatal_lang_error('admin_setting_coppa_require_contact');
327
328
		// Post needs to take into account line breaks.
329
		$_POST['coppaPost'] = str_replace("\n", '<br>', empty($_POST['coppaPost']) ? '' : $_POST['coppaPost']);
330
331
		call_integration_hook('integrate_save_registration_settings');
332
333
		saveDBSettings($config_vars);
334
		$_SESSION['adm-save'] = true;
335
		redirectexit('action=admin;area=regcenter;sa=settings');
336
	}
337
338
	$context['post_url'] = $scripturl . '?action=admin;area=regcenter;save;sa=settings';
339
	$context['settings_title'] = $txt['settings'];
340
341
	// Define some javascript for COPPA.
342
	$context['settings_post_javascript'] = '
343
		function checkCoppa()
344
		{
345
			var coppaDisabled = document.getElementById(\'coppaAge\').value == 0;
346
			document.getElementById(\'coppaType\').disabled = coppaDisabled;
347
348
			var disableContacts = coppaDisabled || document.getElementById(\'coppaType\').options[document.getElementById(\'coppaType\').selectedIndex].value != 1;
349
			document.getElementById(\'coppaPost\').disabled = disableContacts;
350
			document.getElementById(\'coppaFax\').disabled = disableContacts;
351
			document.getElementById(\'coppaPhone\').disabled = disableContacts;
352
		}
353
		checkCoppa();';
354
355
	// Turn the postal address into something suitable for a textbox.
356
	$modSettings['coppaPost'] = !empty($modSettings['coppaPost']) ? preg_replace('~<br ?/?' . '>~', "\n", $modSettings['coppaPost']) : '';
357
358
	prepareDBSettingContext($config_vars);
359
}
360
361
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...