Completed
Pull Request — patch_1-0-10 (#2913)
by Emanuele
08:49
created

list_getTopicNotificationCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file has the primary job of showing and editing people's profiles.
5
 * It also allows the user to change some of their or another's preferences,
6
 * and such things
7
 *
8
 * @name      ElkArte Forum
9
 * @copyright ElkArte Forum contributors
10
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
11
 *
12
 * This software is a derived product, based on:
13
 *
14
 * Simple Machines Forum (SMF)
15
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
16
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
17
 *
18
 * @version 1.0.10
19
 *
20
 */
21
22
if (!defined('ELK'))
23
	die('No access...');
24
25
/**
26
 * ProfileOptions_Controller class. Does the job of showing and editing people's profiles.
27
 * Interface to buddy list, ignore list, notifications, authenitcation options, forum profile
28
 * account settings, etc
29
 */
30
class ProfileOptions_Controller extends Action_Controller
31
{
32
	public static function getFields($area)
33
	{
34
		global $modSettings;
35
36
		$fields = array(
37
			'account' => array(
38
				'fields' => array(
39
					'member_name', 'real_name', 'date_registered', 'posts', 'lngfile', 'hr',
40
					'id_group', 'hr',
41
					'email_address', 'hide_email', 'show_online', 'hr',
42
					'passwrd1', 'passwrd2', 'hr',
43
					'secret_question', 'secret_answer',
44
				),
45
				'hook' => 'account'
46
				),
47
			'forumprofile' => array(
48
				'fields' => array(
49
					'avatar_choice', 'hr', 'personal_text', 'hr',
50
					'bday1', 'location', 'gender', 'hr',
51
					'usertitle', 'signature', 'hr',
52
					'karma_good', 'hr',
53
					'website_title', 'website_url',
54
				),
55
				'hook' => 'forum'
56
			),
57
			'theme' => array(
58
				'fields' => array(
59
					'id_theme', 'smiley_set', 'hr',
60
					'time_format', 'time_offset', 'hr',
61
					'theme_settings',
62
				),
63
				'hook' => 'themepick'
64
			),
65
			'contactprefs' => array(
66
				'fields' => array(
67
					'receive_from',
68
					'hr',
69
					'pm_settings',
70
				),
71
				'hook' => 'pmprefs'
72
			),
73
			'registration' => array(
74
				'fields' => !empty($modSettings['registration_fields']) ? explode(',', $modSettings['registration_fields']) : array(),
75
				'hook' => 'registration'
76
			)
77
		);
78
79
		if (isset($fields[$area]))
80
		{
81
			return $fields[$area];
82
		}
83
		else
84
		{
85
			return array();
86
		}
87
	}
88
	/**
89
	 * Default method, if another action is not called
90
	 * by the menu.
91
	 *
92
	 * @see Action_Controller::action_index()
93
	 */
94
	public function action_index()
95
	{
96
		// action_account() is the first to do
97
		// these subactions are mostly routed to from the profile
98
		// menu though.
99
	}
100
101
	/**
102
	 * Show all the users buddies, as well as a add/delete interface.
103
	 */
104
	public function action_editBuddyIgnoreLists()
105
	{
106
		global $context, $txt, $modSettings;
107
108
		$memID = currentMemberID();
109
110
		// Do a quick check to ensure people aren't getting here illegally!
111
		if (!$context['user']['is_owner'] || empty($modSettings['enable_buddylist']))
112
			fatal_lang_error('no_access', false);
113
114
		loadTemplate('ProfileOptions');
115
116
		// Can we email the user direct?
117
		$context['can_moderate_forum'] = allowedTo('moderate_forum');
118
		$context['can_send_email'] = allowedTo('send_email_to_members');
119
120
		$subActions = array(
121
			'buddies' => array('action_editBuddies', $txt['editBuddies']),
122
			'ignore' => array('action_editIgnoreList', $txt['editIgnoreList']),
123
		);
124
125
		// Set a subaction
126
		$subAction = isset($_GET['sa']) && isset($subActions[$_GET['sa']]) ? $_GET['sa'] : 'buddies';
127
128
		// Create the tabs for the template.
129
		$context[$context['profile_menu_name']]['tab_data'] = array(
130
			'title' => $txt['editBuddyIgnoreLists'],
131
			'description' => $txt['buddy_ignore_desc'],
132
			'class' => 'profile',
133
			'tabs' => array(
134
				'buddies' => array(),
135
				'ignore' => array(),
136
			),
137
		);
138
139
		// Pass on to the actual function.
140
		$this->{$subActions[$subAction][0]}($memID);
141
	}
142
143
	/**
144
	 * Show all the users buddies, as well as a add/delete interface.
145
	 *
146
	 * @param int $memID id_member
147
	 */
148
	public function action_editBuddies($memID)
149
	{
150
		global $context, $user_profile, $memberContext, $modSettings;
151
152
		$db = database();
153
154
		loadTemplate('ProfileOptions');
155
156
		// We want to view what we're doing :P
157
		$context['sub_template'] = 'editBuddies';
158
		loadJavascriptFile('suggest.js', array('defer' => true));
159
160
		// For making changes!
161
		$buddiesArray = explode(',', $user_profile[$memID]['buddy_list']);
162
		foreach ($buddiesArray as $k => $dummy)
163
			if ($dummy == '')
164
				unset($buddiesArray[$k]);
165
166
		// Removing a buddy?
167
		if (isset($_GET['remove']))
168
		{
169
			checkSession('get');
170
171
			call_integration_hook('integrate_remove_buddy', array($memID));
172
173
			// Heh, I'm lazy, do it the easy way...
174
			foreach ($buddiesArray as $key => $buddy)
175
				if ($buddy == (int) $_GET['remove'])
176
					unset($buddiesArray[$key]);
177
178
			// Make the changes.
179
			$user_profile[$memID]['buddy_list'] = implode(',', $buddiesArray);
180
			updateMemberData($memID, array('buddy_list' => $user_profile[$memID]['buddy_list']));
181
182
			// Redirect off the page because we don't like all this ugly query stuff to stick in the history.
183
			redirectexit('action=profile;area=lists;sa=buddies;u=' . $memID);
184
		}
185
		// Or adding a new one
186
		elseif (isset($_POST['new_buddy']))
187
		{
188
			checkSession();
189
190
			// Prepare the string for extraction...
191
			$_POST['new_buddy'] = strtr(Util::htmlspecialchars($_POST['new_buddy'], ENT_QUOTES), array('&quot;' => '"'));
192
			preg_match_all('~"([^"]+)"~', $_POST['new_buddy'], $matches);
193
			$new_buddies = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST['new_buddy']))));
194
195
			foreach ($new_buddies as $k => $dummy)
196
			{
197
				$new_buddies[$k] = strtr(trim($new_buddies[$k]), array('\'' => '&#039;'));
198
199
				if (strlen($new_buddies[$k]) == 0 || in_array($new_buddies[$k], array($user_profile[$memID]['member_name'], $user_profile[$memID]['real_name'])))
200
					unset($new_buddies[$k]);
201
			}
202
203
			call_integration_hook('integrate_add_buddies', array($memID, &$new_buddies));
204
205
			if (!empty($new_buddies))
206
			{
207
				// Now find out the id_member of the buddy.
208
				$request = $db->query('', '
209
					SELECT id_member
210
					FROM {db_prefix}members
211
					WHERE member_name IN ({array_string:new_buddies}) OR real_name IN ({array_string:new_buddies})
212
					LIMIT {int:count_new_buddies}',
213
					array(
214
						'new_buddies' => $new_buddies,
215
						'count_new_buddies' => count($new_buddies),
216
					)
217
				);
218
219
				// Let them know who's their buddy.
220
				if (!empty($modSettings['mentions_enabled']) && !empty($modSettings['mentions_buddy']))
221
				{
222
					require_once(CONTROLLERDIR . '/Mentions.controller.php');
223
					$mentions = new Mentions_Controller();
224
				}
225
226
				// Add the new member to the buddies array.
227
				while ($row = $db->fetch_assoc($request))
228
				{
229
					$buddiesArray[] = (int) $row['id_member'];
230
231
					if (!empty($modSettings['mentions_enabled']) && !empty($modSettings['mentions_buddy']))
232
					{
233
						// Set a mentions for our buddy.
234
						$mentions->setData(array(
0 ignored issues
show
Bug introduced by
The variable $mentions does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
235
							'id_member' => $row['id_member'],
236
							'type' => 'buddy',
237
							'id_msg' => 0,
238
						));
239
						$mentions->action_add();
240
					}
241
				}
242
				$db->free_result($request);
243
244
				// Now update the current users buddy list.
245
				$user_profile[$memID]['buddy_list'] = implode(',', $buddiesArray);
246
				updateMemberData($memID, array('buddy_list' => $user_profile[$memID]['buddy_list']));
247
			}
248
249
			// Back to the buddy list!
250
			redirectexit('action=profile;area=lists;sa=buddies;u=' . $memID);
251
		}
252
253
		// Get all the users "buddies"...
254
		$buddies = array();
255
256
		if (!empty($buddiesArray))
257
		{
258
			require_once(SUBSDIR . '/Members.subs.php');
259
			$result = getBasicMemberData($buddiesArray, array('sort' => 'real_name', 'limit' => substr_count($user_profile[$memID]['buddy_list'], ',') + 1));
260
			foreach ($result as $row)
261
				$buddies[] = $row['id_member'];
262
		}
263
264
		$context['buddy_count'] = count($buddies);
265
266
		// Load all the members up.
267
		loadMemberData($buddies, false, 'profile');
268
269
		// Setup the context for each buddy.
270
		$context['buddies'] = array();
271
		foreach ($buddies as $buddy)
272
		{
273
			loadMemberContext($buddy, true);
274
			$context['buddies'][$buddy] = $memberContext[$buddy];
275
		}
276
277
		call_integration_hook('integrate_view_buddies', array($memID));
278
	}
279
280
	/**
281
	 * Allows the user to view their ignore list,
282
	 * as well as the option to manage members on it.
283
	 *
284
	 * @param int $memID id_member
285
	 */
286
	public function action_editIgnoreList($memID)
287
	{
288
		global $context, $user_profile, $memberContext;
289
290
		$db = database();
291
292
		loadTemplate('ProfileOptions');
293
294
		// We want to view what we're doing :P
295
		$context['sub_template'] = 'editIgnoreList';
296
		loadJavascriptFile('suggest.js', array('defer' => true));
297
298
		// For making changes!
299
		$ignoreArray = explode(',', $user_profile[$memID]['pm_ignore_list']);
300
		foreach ($ignoreArray as $k => $dummy)
301
		{
302
			if ($dummy == '')
303
				unset($ignoreArray[$k]);
304
		}
305
306
		// Removing a member from the ignore list?
307
		if (isset($_GET['remove']))
308
		{
309
			checkSession('get');
310
311
			// Heh, I'm lazy, do it the easy way...
312
			foreach ($ignoreArray as $key => $id_remove)
313
				if ($id_remove == (int) $_GET['remove'])
314
					unset($ignoreArray[$key]);
315
316
			// Make the changes.
317
			$user_profile[$memID]['pm_ignore_list'] = implode(',', $ignoreArray);
318
			updateMemberData($memID, array('pm_ignore_list' => $user_profile[$memID]['pm_ignore_list']));
319
320
			// Redirect off the page because we don't like all this ugly query stuff to stick in the history.
321
			redirectexit('action=profile;area=lists;sa=ignore;u=' . $memID);
322
		}
323
		elseif (isset($_POST['new_ignore']))
324
		{
325
			checkSession();
326
327
			// Prepare the string for extraction...
328
			$_POST['new_ignore'] = strtr(Util::htmlspecialchars($_POST['new_ignore'], ENT_QUOTES), array('&quot;' => '"'));
329
			preg_match_all('~"([^"]+)"~', $_POST['new_ignore'], $matches);
330
			$new_entries = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST['new_ignore']))));
331
332
			foreach ($new_entries as $k => $dummy)
333
			{
334
				$new_entries[$k] = strtr(trim($new_entries[$k]), array('\'' => '&#039;'));
335
336
				if (strlen($new_entries[$k]) == 0 || in_array($new_entries[$k], array($user_profile[$memID]['member_name'], $user_profile[$memID]['real_name'])))
337
					unset($new_entries[$k]);
338
			}
339
340
			if (!empty($new_entries))
341
			{
342
				// Now find out the id_member for the members in question.
343
				$request = $db->query('', '
344
					SELECT id_member
345
					FROM {db_prefix}members
346
					WHERE member_name IN ({array_string:new_entries}) OR real_name IN ({array_string:new_entries})
347
					LIMIT {int:count_new_entries}',
348
					array(
349
						'new_entries' => $new_entries,
350
						'count_new_entries' => count($new_entries),
351
					)
352
				);
353
354
				// Add the new member to the buddies array.
355
				while ($row = $db->fetch_assoc($request))
356
					$ignoreArray[] = (int) $row['id_member'];
357
				$db->free_result($request);
358
359
				// Now update the current users buddy list.
360
				$user_profile[$memID]['pm_ignore_list'] = implode(',', $ignoreArray);
361
				updateMemberData($memID, array('pm_ignore_list' => $user_profile[$memID]['pm_ignore_list']));
362
			}
363
364
			// Back to the list of pityful people!
365
			redirectexit('action=profile;area=lists;sa=ignore;u=' . $memID);
366
		}
367
368
		// Initialise the list of members we're ignoring.
369
		$ignored = array();
370
371
		if (!empty($ignoreArray))
372
		{
373
			require_once(SUBSDIR . '/Members.subs.php');
374
			$result = getBasicMemberData($ignoreArray, array('sort' => 'real_name', 'limit' => substr_count($user_profile[$memID]['pm_ignore_list'], ',') + 1));
375
			foreach ($result as $row)
376
				$ignored[] = $row['id_member'];
377
		}
378
379
		$context['ignore_count'] = count($ignored);
380
381
		// Load all the members up.
382
		loadMemberData($ignored, false, 'profile');
383
384
		// Setup the context for each buddy.
385
		$context['ignore_list'] = array();
386
		foreach ($ignored as $ignore_member)
387
		{
388
			loadMemberContext($ignore_member);
389
			$context['ignore_list'][$ignore_member] = $memberContext[$ignore_member];
390
		}
391
	}
392
393
	/**
394
	 * Allows the user to see or change their account info.
395
	 *
396
	 */
397
	public function action_account()
398
	{
399
		global $context, $txt;
400
401
		$memID = currentMemberID();
402
403
		loadTemplate('ProfileOptions');
404
		loadThemeOptions($memID);
405
406
		if (allowedTo(array('profile_identity_own', 'profile_identity_any')))
407
			loadCustomFields($memID, 'account');
408
409
		$context['sub_template'] = 'edit_options';
410
		$context['page_desc'] = $txt['account_info'];
411
412
		$fields = ProfileOptions_Controller::getFields('account');
413
		setupProfileContext($fields['fields'], $fields['hook']);
414
	}
415
416
	/**
417
	 * Allow the user to change the forum options in their profile.
418
	 *
419
	 */
420
	public function action_forumProfile()
421
	{
422
		global $context, $txt;
423
424
		$memID = currentMemberID();
425
426
		loadTemplate('ProfileOptions');
427
		loadThemeOptions($memID);
428
429
		if (allowedTo(array('profile_extra_own', 'profile_extra_any')))
430
			loadCustomFields($memID, 'forumprofile');
431
432
		$context['sub_template'] = 'edit_options';
433
		$context['page_desc'] = replaceBasicActionUrl($txt['forumProfile_info']);
434
		$context['show_preview_button'] = true;
435
436
		$fields = ProfileOptions_Controller::getFields('forumprofile');
437
		setupProfileContext($fields['fields'], $fields['hook']);
438
	}
439
440
	/**
441
	 * Allow the edit of *someone elses* personal message settings.
442
	 */
443
	public function action_pmprefs()
444
	{
445
		global $context, $txt;
446
447
		$memID = currentMemberID();
448
449
		loadThemeOptions($memID);
450
		loadCustomFields($memID, 'pmprefs');
451
		loadTemplate('ProfileOptions');
452
453
		$context['sub_template'] = 'edit_options';
454
		$context['page_desc'] = $txt['pm_settings_desc'];
455
456
		// Setup the profile context and call the 'integrate_pmprefs_profile_fields' hook
457
		$fields = ProfileOptions_Controller::getFields('contactprefs');
458
		setupProfileContext($fields['fields'], $fields['hook']);
459
	}
460
461
	/**
462
	 * Allow the user to pick a theme.
463
	 *
464
	 */
465
	public function action_themepick()
466
	{
467
		global $txt, $context;
468
469
		$memID = currentMemberID();
470
471
		loadThemeOptions($memID);
472
473
		if (allowedTo(array('profile_extra_own', 'profile_extra_any')))
474
			loadCustomFields($memID, 'theme');
475
476
		loadTemplate('ProfileOptions');
477
478
		$context['sub_template'] = 'edit_options';
479
		$context['page_desc'] = $txt['theme_info'];
480
481
		$fields = ProfileOptions_Controller::getFields('theme');
482
		setupProfileContext($fields['fields'], $fields['hook']);
483
	}
484
485
	/**
486
	 * Changing authentication method?
487
	 * Only appropriate for people using OpenID.
488
	 *
489
	 * @param bool $saving = false
490
	 */
491
	public function action_authentication($saving = false)
492
	{
493
		global $context, $cur_profile, $post_errors, $modSettings;
494
495
		$memID = currentMemberID();
496
497
		loadLanguage('Login');
498
		loadTemplate('ProfileOptions');
499
500
		// We are saving?
501
		if ($saving)
502
		{
503
			// Moving to password passed authentication?
504
			if ($_POST['authenticate'] == 'passwd')
505
			{
506
				// Didn't enter anything?
507
				if ($_POST['passwrd1'] == '')
508
					$post_errors[] = 'no_password';
509
				// Do the two entries for the password even match?
510
				elseif (!isset($_POST['passwrd2']) || $_POST['passwrd1'] != $_POST['passwrd2'])
511
					$post_errors[] = 'bad_new_password';
512
				// Is it valid?
513
				else
514
				{
515
					require_once(SUBSDIR . '/Auth.subs.php');
516
					$passwordErrors = validatePassword($_POST['passwrd1'], $cur_profile['member_name'], array($cur_profile['real_name'], $cur_profile['email_address']));
517
518
					// Were there errors?
519
					if ($passwordErrors != null)
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $passwordErrors of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
520
						$post_errors[] = 'password_' . $passwordErrors;
521
				}
522
523
				if (empty($post_errors))
524
				{
525
					// Integration?
526
					call_integration_hook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $_POST['passwrd1']));
527
528
					// Go then.
529
					require_once(SUBSDIR . '/Auth.subs.php');
530
					$new_pass = $_POST['passwrd1'];
531
					$passwd = validateLoginPassword($new_pass, '', $cur_profile['member_name'], true);
532
533
					// Do the important bits.
534
					updateMemberData($memID, array('openid_uri' => '', 'passwd' => $passwd));
535
					if ($context['user']['is_owner'])
536
					{
537
						setLoginCookie(60 * $modSettings['cookieTime'], $memID, hash('sha256', $new_pass . $cur_profile['password_salt']));
538
						redirectexit('action=profile;area=authentication;updated');
539
					}
540
					else
541
						redirectexit('action=profile;u=' . $memID);
542
				}
543
544
				return true;
545
			}
546
			// Not right yet!
547
			elseif ($_POST['authenticate'] == 'openid' && !empty($_POST['openid_identifier']))
548
			{
549
				require_once(SUBSDIR . '/OpenID.subs.php');
550
				require_once(SUBSDIR . '/Members.subs.php');
551
552
				$openID = new OpenID();
553
				$_POST['openid_identifier'] = $openID->canonize($_POST['openid_identifier']);
554
555
				if (memberExists($_POST['openid_identifier']))
556
					$post_errors[] = 'openid_in_use';
557
				elseif (empty($post_errors))
558
				{
559
					// Authenticate using the new OpenID URI first to make sure they didn't make a mistake.
560
					if ($context['user']['is_owner'])
561
					{
562
						$_SESSION['new_openid_uri'] = $_POST['openid_identifier'];
563
564
						$openID->validate($_POST['openid_identifier'], false, null, 'change_uri');
565
					}
566
					else
567
						updateMemberData($memID, array('openid_uri' => $_POST['openid_identifier']));
568
				}
569
			}
570
		}
571
572
		// Some stuff.
573
		$context['member']['openid_uri'] = $cur_profile['openid_uri'];
574
		$context['auth_method'] = empty($cur_profile['openid_uri']) ? 'password' : 'openid';
575
		$context['sub_template'] = 'authentication_method';
576
		loadJavascriptFile('register.js');
577
	}
578
579
	/**
580
	 * Display the notifications and settings for changes.
581
	 */
582
	public function action_notification()
583
	{
584
		global $txt, $scripturl, $user_profile, $context, $modSettings;
585
586
		loadTemplate('ProfileOptions');
587
588
		$memID = currentMemberID();
589
590
		// Going to need this for the list.
591
		require_once(SUBSDIR . '/GenericList.class.php');
592
		require_once(SUBSDIR . '/Boards.subs.php');
593
		require_once(SUBSDIR . '/Topic.subs.php');
594
595
		// Fine, start with the board list.
596
		$listOptions = array(
597
			'id' => 'board_notification_list',
598
			'width' => '100%',
599
			'no_items_label' => $txt['notifications_boards_none'] . '<br /><br />' . $txt['notifications_boards_howto'],
600
			'no_items_align' => 'left',
601
			'base_href' => $scripturl . '?action=profile;u=' . $memID . ';area=notification',
602
			'default_sort_col' => 'board_name',
603
			'get_items' => array(
604
				'function' => array($this, 'list_getBoardNotifications'),
605
				'params' => array(
606
					$memID,
607
				),
608
			),
609
			'columns' => array(
610
				'board_name' => array(
611
					'header' => array(
612
						'value' => $txt['notifications_boards'],
613
						'class' => 'lefttext',
614
					),
615
					'data' => array(
616
						'function' => create_function('$board', '
617
							global $txt;
618
619
							$link = $board[\'link\'];
620
621
							if ($board[\'new\'])
622
								$link .= \' <a href="\' . $board[\'href\'] . \'"><span class="new_posts">' . $txt['new'] . '</span></a>\';
623
624
							return $link;
625
						'),
626
					),
627
					'sort' => array(
628
						'default' => 'name',
629
						'reverse' => 'name DESC',
630
					),
631
				),
632
				'delete' => array(
633
					'header' => array(
634
						'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />',
635
						'class' => 'centertext',
636
						'style' => 'width:4%;',
637
					),
638
					'data' => array(
639
						'sprintf' => array(
640
							'format' => '<input type="checkbox" name="notify_boards[]" value="%1$d" class="input_check" %2$s />',
641
							'params' => array(
642
								'id' => false,
643
								'checked' => false,
644
							),
645
						),
646
						'class' => 'centertext',
647
					),
648
				),
649
			),
650
			'form' => array(
651
				'href' => $scripturl . '?action=profile;area=notification;save',
652
				'include_sort' => true,
653
				'include_start' => true,
654
				'hidden_fields' => array(
655
					'u' => $memID,
656
					'sa' => $context['menu_item_selected'],
657
					$context['session_var'] => $context['session_id'],
658
				),
659
				'token' => $context['token_check'],
660
			),
661
			'additional_rows' => array(
662
				array(
663
					'position' => 'bottom_of_list',
664
					'value' => '<input type="submit" name="edit_notify_boards" value="' . $txt['notifications_boards_update'] . '" class="right_submit" />',
665
				),
666
				array(
667
					'position' => 'after_title',
668
					'value' => getBoardNotificationsCount($memID) == 0 ? $txt['notifications_boards_none'] . '<br />' . $txt['notifications_boards_howto'] : $txt['notifications_boards_current'],
669
				),
670
			),
671
		);
672
673
		// Create the board notification list.
674
		createList($listOptions);
675
676
		// Now do the topic notifications.
677
		$listOptions = array(
678
			'id' => 'topic_notification_list',
679
			'width' => '100%',
680
			'items_per_page' => $modSettings['defaultMaxMessages'],
681
			'no_items_label' => $txt['notifications_topics_none'] . '<br /><br />' . $txt['notifications_topics_howto'],
682
			'no_items_align' => 'left',
683
			'base_href' => $scripturl . '?action=profile;u=' . $memID . ';area=notification',
684
			'default_sort_col' => 'last_post',
685
			'get_items' => array(
686
				'function' => array($this, 'list_getTopicNotifications'),
687
				'params' => array(
688
					$memID,
689
				),
690
			),
691
			'get_count' => array(
692
				'function' => array($this, 'list_getTopicNotificationCount'),
693
				'params' => array(
694
					$memID,
695
				),
696
			),
697
			'columns' => array(
698
				'subject' => array(
699
					'header' => array(
700
						'value' => $txt['notifications_topics'],
701
						'class' => 'lefttext',
702
					),
703
					'data' => array(
704
						'function' => create_function('$topic', '
705
							global $txt;
706
707
							$link = $topic[\'link\'];
708
709
							if ($topic[\'new\'])
710
								$link .= \' <a href="\' . $topic[\'new_href\'] . \'"><span class="new_posts">\' . $txt[\'new\'] . \'</span></a>\';
711
712
							$link .= \'<br /><span class="smalltext"><em>\' . $txt[\'in\'] . \' \' . $topic[\'board_link\'] . \'</em></span>\';
713
714
							return $link;
715
						'),
716
					),
717
					'sort' => array(
718
						'default' => 'ms.subject',
719
						'reverse' => 'ms.subject DESC',
720
					),
721
				),
722
				'started_by' => array(
723
					'header' => array(
724
						'value' => $txt['started_by'],
725
						'class' => 'lefttext',
726
					),
727
					'data' => array(
728
						'db' => 'poster_link',
729
					),
730
					'sort' => array(
731
						'default' => 'real_name_col',
732
						'reverse' => 'real_name_col DESC',
733
					),
734
				),
735
				'last_post' => array(
736
					'header' => array(
737
						'value' => $txt['last_post'],
738
							'class' => 'lefttext',
739
					),
740
					'data' => array(
741
						'sprintf' => array(
742
							'format' => '<span class="smalltext">%1$s<br />' . $txt['by'] . ' %2$s</span>',
743
							'params' => array(
744
								'updated' => false,
745
								'poster_updated_link' => false,
746
							),
747
						),
748
					),
749
					'sort' => array(
750
						'default' => 'ml.id_msg DESC',
751
						'reverse' => 'ml.id_msg',
752
					),
753
				),
754
				'delete' => array(
755
					'header' => array(
756
						'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />',
757
						'class' => 'centertext',
758
						'style' => 'width:4%;',
759
					),
760
					'data' => array(
761
						'sprintf' => array(
762
							'format' => '<input type="checkbox" name="notify_topics[]" value="%1$d" class="input_check" />',
763
							'params' => array(
764
								'id' => false,
765
							),
766
						),
767
						'class' => 'centertext',
768
					),
769
				),
770
			),
771
			'form' => array(
772
				'href' => $scripturl . '?action=profile;area=notification;save',
773
				'include_sort' => true,
774
				'include_start' => true,
775
				'hidden_fields' => array(
776
					'u' => $memID,
777
					'sa' => $context['menu_item_selected'],
778
					$context['session_var'] => $context['session_id'],
779
				),
780
				'token' => $context['token_check'],
781
			),
782
			'additional_rows' => array(
783
				array(
784
					'position' => 'bottom_of_list',
785
					'value' => '<input type="submit" name="edit_notify_topics" value="' . $txt['notifications_update'] . '" class="right_submit" />',
786
					'align' => 'right',
787
				),
788
			),
789
		);
790
791
		// Create the notification list.
792
		createList($listOptions);
793
794
		// What options are set?
795
		$context['member'] += array(
796
			'notify_announcements' => $user_profile[$memID]['notify_announcements'],
797
			'notify_send_body' => $user_profile[$memID]['notify_send_body'],
798
			'notify_types' => $user_profile[$memID]['notify_types'],
799
			'notify_regularity' => $user_profile[$memID]['notify_regularity'],
800
		);
801
802
		loadThemeOptions($memID);
803
	}
804
805
	/**
806
	 * Callback for createList() in action_notification()
807
	 * Retrieve topic notifications count.
808
	 *
809
	 * @param int $memID id_member
810
	 * @return integer
811
	 */
812
	public function list_getTopicNotificationCount($memID)
813
	{
814
		// Topic notifications count, for the list
815
		return topicNotificationCount($memID);
816
	}
817
818
	/**
819
	 * Callback for createList() in action_notification()
820
	 *
821
	 * @param int $start
822
	 * @param int $items_per_page
823
	 * @param string $sort
824
	 * @param int $memID id_member
825
	 * @return mixed array of topic notifications
826
	 */
827
	public function list_getTopicNotifications($start, $items_per_page, $sort, $memID)
828
	{
829
		// topic notifications, for the list
830
		return topicNotifications($start, $items_per_page, $sort, $memID);
831
	}
832
833
	/**
834
	 * Callback for createList() in action_notification()
835
	 *
836
	 * @param int $start
837
	 * @param int $items_per_page
838
	 * @param string $sort
839
	 * @param int $memID id_member
840
	 * @return mixed[] array of board notifications
841
	 */
842
	public function list_getBoardNotifications($start, $items_per_page, $sort, $memID)
843
	{
844
		// return boards you see and their notification status for the list
845
		return boardNotifications($start, $items_per_page, $sort, $memID);
846
	}
847
848
	/**
849
	 * Allows the user to see the list of their ignored boards.
850
	 * (and un-ignore them)
851
	 *
852
	 */
853
	public function action_ignoreboards()
854
	{
855
		global $context, $modSettings, $cur_profile;
856
857
		$memID = currentMemberID();
858
859
		// Have the admins enabled this option?
860
		if (empty($modSettings['allow_ignore_boards']))
861
			fatal_lang_error('ignoreboards_disallowed', 'user');
862
863
		loadTemplate('ProfileOptions');
864
865
		$context['sub_template'] = 'ignoreboards';
866
		require_once(SUBSDIR . '/Boards.subs.php');
867
		$context += getBoardList(array('not_redirection' => true, 'ignore' => !empty($cur_profile['ignore_boards']) ? explode(',', $cur_profile['ignore_boards']) : array()));
868
869
		// Include a list of boards per category for easy toggling.
870
		foreach ($context['categories'] as $cat => &$category)
871
		{
872
			$context['boards_in_category'][$cat] = count($category['boards']);
873
			$category['child_ids'] = array_keys($category['boards']);
874
		}
875
876
		loadThemeOptions($memID);
877
	}
878
879
	/**
880
	 * Function to allow the user to choose group membership etc...
881
	 *
882
	 */
883
	public function action_groupMembership()
884
	{
885
		global $txt, $user_profile, $context;
886
887
		$db = database();
888
889
		$memID = currentMemberID();
890
891
		loadTemplate('ProfileOptions');
892
		$context['sub_template'] = 'groupMembership';
893
894
		$curMember = $user_profile[$memID];
895
		$context['primary_group'] = $curMember['id_group'];
896
897
		// Can they manage groups?
898
		$context['can_manage_membergroups'] = allowedTo('manage_membergroups');
899
		$context['can_manage_protected'] = allowedTo('admin_forum');
900
		$context['can_edit_primary'] = $context['can_manage_protected'];
901
		$context['update_message'] = isset($_GET['msg']) && isset($txt['group_membership_msg_' . $_GET['msg']]) ? $txt['group_membership_msg_' . $_GET['msg']] : '';
902
903
		// Get all the groups this user is a member of.
904
		$groups = explode(',', $curMember['additional_groups']);
905
		$groups[] = $curMember['id_group'];
906
907
		// Ensure the query doesn't croak!
908
		if (empty($groups))
909
			$groups = array(0);
910
911
		// Just to be sure...
912
		foreach ($groups as $k => $v)
913
			$groups[$k] = (int) $v;
914
915
		// Get all the membergroups they can join.
916
		$request = $db->query('', '
917
			SELECT mg.id_group, mg.group_name, mg.description, mg.group_type, mg.online_color, mg.hidden,
918
				IFNULL(lgr.id_member, 0) AS pending
919
			FROM {db_prefix}membergroups AS mg
920
				LEFT JOIN {db_prefix}log_group_requests AS lgr ON (lgr.id_member = {int:selected_member} AND lgr.id_group = mg.id_group)
921
			WHERE (mg.id_group IN ({array_int:group_list})
922
				OR mg.group_type > {int:nonjoin_group_id})
923
				AND mg.min_posts = {int:min_posts}
924
				AND mg.id_group != {int:moderator_group}
925
			ORDER BY group_name',
926
			array(
927
				'group_list' => $groups,
928
				'selected_member' => $memID,
929
				'nonjoin_group_id' => 1,
930
				'min_posts' => -1,
931
				'moderator_group' => 3,
932
			)
933
		);
934
		// This beast will be our group holder.
935
		$context['groups'] = array(
936
			'member' => array(),
937
			'available' => array()
938
		);
939
		while ($row = $db->fetch_assoc($request))
940
		{
941
			// Can they edit their primary group?
942
			if (($row['id_group'] == $context['primary_group'] && $row['group_type'] > 1) || ($row['hidden'] != 2 && $context['primary_group'] == 0 && in_array($row['id_group'], $groups)))
943
				$context['can_edit_primary'] = true;
944
945
			// If they can't manage (protected) groups, and it's not publically joinable or already assigned, they can't see it.
946
			if (((!$context['can_manage_protected'] && $row['group_type'] == 1) || (!$context['can_manage_membergroups'] && $row['group_type'] == 0)) && $row['id_group'] != $context['primary_group'])
947
				continue;
948
949
			$context['groups'][in_array($row['id_group'], $groups) ? 'member' : 'available'][$row['id_group']] = array(
950
				'id' => $row['id_group'],
951
				'name' => $row['group_name'],
952
				'desc' => $row['description'],
953
				'color' => $row['online_color'],
954
				'type' => $row['group_type'],
955
				'pending' => $row['pending'],
956
				'is_primary' => $row['id_group'] == $context['primary_group'],
957
				'can_be_primary' => $row['hidden'] != 2,
958
				// Anything more than this needs to be done through account settings for security.
959
				'can_leave' => $row['id_group'] != 1 && $row['group_type'] > 1 ? true : false,
960
			);
961
		}
962
		$db->free_result($request);
963
964
		// Add registered members on the end.
965
		$context['groups']['member'][0] = array(
966
			'id' => 0,
967
			'name' => $txt['regular_members'],
968
			'desc' => $txt['regular_members_desc'],
969
			'type' => 0,
970
			'is_primary' => $context['primary_group'] == 0 ? true : false,
971
			'can_be_primary' => true,
972
			'can_leave' => 0,
973
		);
974
975
		// No changing primary one unless you have enough groups!
976
		if (count($context['groups']['member']) < 2)
977
			$context['can_edit_primary'] = false;
978
979
		// In the special case that someone is requesting membership of a group, setup some special context vars.
980
		if (isset($_REQUEST['request']) && isset($context['groups']['available'][(int) $_REQUEST['request']]) && $context['groups']['available'][(int) $_REQUEST['request']]['type'] == 2)
981
			$context['group_request'] = $context['groups']['available'][(int) $_REQUEST['request']];
982
	}
983
984
	/**
985
	 * This function actually makes all the group changes
986
	 *
987
	 * @return string
988
	 */
989
	public function action_groupMembership2()
990
	{
991
		global $context, $user_profile, $modSettings, $scripturl, $language;
992
993
		$db = database();
994
		$memID = currentMemberID();
995
996
		// Let's be extra cautious...
997
		if (!$context['user']['is_owner'] || empty($modSettings['show_group_membership']))
998
			isAllowedTo('manage_membergroups');
999
1000
		if (!isset($_REQUEST['gid']) && !isset($_POST['primary']))
1001
			fatal_lang_error('no_access', false);
1002
1003
		checkSession(isset($_GET['gid']) ? 'get' : 'post');
1004
1005
		require_once(SUBSDIR . '/Membergroups.subs.php');
1006
1007
		$old_profile = &$user_profile[$memID];
1008
		$context['can_manage_membergroups'] = allowedTo('manage_membergroups');
1009
		$context['can_manage_protected'] = allowedTo('admin_forum');
1010
1011
		// By default the new primary is the old one.
1012
		$newPrimary = $old_profile['id_group'];
1013
		$addGroups = array_flip(explode(',', $old_profile['additional_groups']));
1014
		$canChangePrimary = $old_profile['id_group'] == 0 ? 1 : 0;
1015
		$changeType = isset($_POST['primary']) ? 'primary' : (isset($_POST['req']) ? 'request' : 'free');
1016
1017
		// One way or another, we have a target group in mind...
1018
		$group_id = isset($_REQUEST['gid']) ? (int) $_REQUEST['gid'] : (int) $_POST['primary'];
1019
		$foundTarget = $changeType == 'primary' && $group_id == 0 ? true : false;
1020
1021
		// Sanity check!!
1022
		if ($group_id == 1)
1023
			isAllowedTo('admin_forum');
1024
1025
		// What ever we are doing, we need to determine if changing primary is possible!
1026
		$groups_details = membergroupsById(array($group_id, $old_profile['id_group']), 0, true);
1027
1028
		// Protected groups require proper permissions!
1029
		if ($group_id != 1 && $groups_details[$group_id]['group_type'] == 1)
1030
			isAllowedTo('admin_forum');
1031
1032
		foreach ($groups_details as $key => $row)
1033
		{
1034
			// Is this the new group?
1035
			if ($row['id_group'] == $group_id)
1036
			{
1037
				$foundTarget = true;
1038
				$group_name = $row['group_name'];
1039
1040
				// Does the group type match what we're doing - are we trying to request a non-requestable group?
1041
				if ($changeType == 'request' && $row['group_type'] != 2)
1042
					fatal_lang_error('no_access', false);
1043
				// What about leaving a requestable group we are not a member of?
1044
				elseif ($changeType == 'free' && $row['group_type'] == 2 && $old_profile['id_group'] != $row['id_group'] && !isset($addGroups[$row['id_group']]))
1045
					fatal_lang_error('no_access', false);
1046
				elseif ($changeType == 'free' && $row['group_type'] != 3 && $row['group_type'] != 2)
1047
					fatal_lang_error('no_access', false);
1048
1049
				// We can't change the primary group if this is hidden!
1050
				if ($row['hidden'] == 2)
1051
					$canChangePrimary = false;
1052
			}
1053
1054
			// If this is their old primary, can we change it?
1055
			if ($row['id_group'] == $old_profile['id_group'] && ($row['group_type'] > 1 || $context['can_manage_membergroups']) && $canChangePrimary !== false)
1056
				$canChangePrimary = 1;
1057
1058
			// If we are not doing a force primary move, don't do it automatically if current primary is not 0.
1059
			if ($changeType != 'primary' && $old_profile['id_group'] != 0)
1060
				$canChangePrimary = false;
1061
1062
			// If this is the one we are acting on, can we even act?
1063
			if ((!$context['can_manage_protected'] && $row['group_type'] == 1) || (!$context['can_manage_membergroups'] && $row['group_type'] == 0))
1064
				$canChangePrimary = false;
1065
		}
1066
1067
		// Didn't find the target?
1068
		if (!$foundTarget)
1069
			fatal_lang_error('no_access', false);
1070
1071
		// Final security check, don't allow users to promote themselves to admin.
1072
		if ($context['can_manage_membergroups'] && !allowedTo('admin_forum'))
1073
		{
1074
			$request = $db->query('', '
1075
				SELECT COUNT(permission)
1076
				FROM {db_prefix}permissions
1077
				WHERE id_group = {int:selected_group}
1078
					AND permission = {string:admin_forum}
1079
					AND add_deny = {int:not_denied}',
1080
				array(
1081
					'selected_group' => $group_id,
1082
					'not_denied' => 1,
1083
					'admin_forum' => 'admin_forum',
1084
				)
1085
			);
1086
			list ($disallow) = $db->fetch_row($request);
1087
			$db->free_result($request);
1088
1089
			if ($disallow)
1090
				isAllowedTo('admin_forum');
1091
		}
1092
1093
		// If we're requesting, add the note then return.
1094
		if ($changeType == 'request')
1095
		{
1096
			$request = $db->query('', '
1097
				SELECT id_member
1098
				FROM {db_prefix}log_group_requests
1099
				WHERE id_member = {int:selected_member}
1100
					AND id_group = {int:selected_group}',
1101
				array(
1102
					'selected_member' => $memID,
1103
					'selected_group' => $group_id,
1104
				)
1105
			);
1106
			if ($db->num_rows($request) != 0)
1107
				fatal_lang_error('profile_error_already_requested_group');
1108
			$db->free_result($request);
1109
1110
			// Log the request.
1111
			$db->insert('',
1112
				'{db_prefix}log_group_requests',
1113
				array(
1114
					'id_member' => 'int', 'id_group' => 'int', 'time_applied' => 'int', 'reason' => 'string-65534',
1115
				),
1116
				array(
1117
					$memID, $group_id, time(), $_POST['reason'],
1118
				),
1119
				array('id_request')
1120
			);
1121
1122
			// Send an email to all group moderators etc.
1123
			require_once(SUBSDIR . '/Mail.subs.php');
1124
1125
			// Do we have any group moderators?
1126
			$request = $db->query('', '
1127
				SELECT id_member
1128
				FROM {db_prefix}group_moderators
1129
				WHERE id_group = {int:selected_group}',
1130
				array(
1131
					'selected_group' => $group_id,
1132
				)
1133
			);
1134
			$moderators = array();
1135
			while ($row = $db->fetch_assoc($request))
1136
				$moderators[] = $row['id_member'];
1137
			$db->free_result($request);
1138
1139
			// Otherwise this is the backup!
1140
			if (empty($moderators))
1141
			{
1142
				require_once(SUBSDIR . '/Members.subs.php');
1143
				$moderators = membersAllowedTo('manage_membergroups');
1144
			}
1145
1146
			if (!empty($moderators))
1147
			{
1148
				require_once(SUBSDIR . '/Members.subs.php');
1149
				$members = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile'));
1150
1151
				foreach ($members as $member)
1152
				{
1153
					if ($member['notify_types'] != 4)
1154
						continue;
1155
1156
					// Check whether they are interested.
1157
					if (!empty($member['mod_prefs']))
1158
					{
1159
						list (,, $pref_binary) = explode('|', $member['mod_prefs']);
1160
						if (!($pref_binary & 4))
1161
							continue;
1162
					}
1163
1164
					$replacements = array(
1165
						'RECPNAME' => $member['member_name'],
1166
						'APPYNAME' => $old_profile['member_name'],
1167
						'GROUPNAME' => $group_name,
0 ignored issues
show
Bug introduced by
The variable $group_name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1168
						'REASON' => $_POST['reason'],
1169
						'MODLINK' => $scripturl . '?action=moderate;area=groups;sa=requests',
1170
					);
1171
1172
					$emaildata = loadEmailTemplate('request_membership', $replacements, empty($member['lngfile']) || empty($modSettings['userLanguage']) ? $language : $member['lngfile']);
1173
					sendmail($member['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 2);
1174
				}
1175
			}
1176
1177
			return $changeType;
1178
		}
1179
		// Otherwise we are leaving/joining a group.
1180
		elseif ($changeType == 'free')
1181
		{
1182
			// Are we leaving?
1183
			if ($old_profile['id_group'] == $group_id || isset($addGroups[$group_id]))
1184
			{
1185
				if ($old_profile['id_group'] == $group_id)
1186
					$newPrimary = 0;
1187
				else
1188
					unset($addGroups[$group_id]);
1189
			}
1190
			// ... if not, must be joining.
1191
			else
1192
			{
1193
				// Can we change the primary, and do we want to?
1194
				if ($canChangePrimary)
0 ignored issues
show
Bug Best Practice introduced by
The expression $canChangePrimary of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1195
				{
1196
					if ($old_profile['id_group'] != 0)
1197
						$addGroups[$old_profile['id_group']] = -1;
1198
					$newPrimary = $group_id;
1199
				}
1200
				// Otherwise it's an additional group...
1201
				else
1202
					$addGroups[$group_id] = -1;
1203
			}
1204
		}
1205
		// Finally, we must be setting the primary.
1206
		elseif ($canChangePrimary)
0 ignored issues
show
Bug Best Practice introduced by
The expression $canChangePrimary of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1207
		{
1208
			if ($old_profile['id_group'] != 0)
1209
				$addGroups[$old_profile['id_group']] = -1;
1210
			if (isset($addGroups[$group_id]))
1211
				unset($addGroups[$group_id]);
1212
			$newPrimary = $group_id;
1213
		}
1214
1215
		// Finally, we can make the changes!
1216
		foreach ($addGroups as $id => $dummy)
1217
		{
1218
			if (empty($id))
1219
				unset($addGroups[$id]);
1220
		}
1221
		$addGroups = implode(',', array_flip($addGroups));
1222
1223
		// Ensure that we don't cache permissions if the group is changing.
1224
		if ($context['user']['is_owner'])
1225
			$_SESSION['mc']['time'] = 0;
1226
		else
1227
			updateSettings(array('settings_updated' => time()));
1228
1229
		updateMemberData($memID, array('id_group' => $newPrimary, 'additional_groups' => $addGroups));
1230
1231
		return $changeType;
1232
	}
1233
}
1234
1235
/**
1236
 * Load the options for an user.
1237
 *
1238
 * @param int $memID id_member
1239
 */
1240
function loadThemeOptions($memID)
1241
{
1242
	global $context, $options, $cur_profile;
1243
1244
	if (isset($_POST['default_options']))
1245
		$_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
1246
1247
	if ($context['user']['is_owner'])
1248
	{
1249
		$context['member']['options'] = $options;
1250
		if (isset($_POST['options']) && is_array($_POST['options']))
1251
			foreach ($_POST['options'] as $k => $v)
1252
				$context['member']['options'][$k] = $v;
1253
	}
1254
	else
1255
	{
1256
		require_once(SUBSDIR . '/Themes.subs.php');
1257
		$context['member']['options'] = loadThemeOptionsInto(array(1, (int) $cur_profile['id_theme']), array(-1, $memID), $context['member']['options']);
0 ignored issues
show
Documentation introduced by
array(-1, $memID) is of type array<integer,integer,{"...nteger","1":"integer"}>, but the function expects a integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1258
		if (isset($_POST['options']))
1259
		{
1260
			foreach ($_POST['options'] as $var => $val)
1261
				$context['member']['options'][$var] = $val;
1262
		}
1263
	}
1264
}