albertlast /
SMF2.1
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
|
|||
| 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
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
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
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.
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
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...
|
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.