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

Sources/ManageRegistration.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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');
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
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)
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
?>