1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14/**
15* @ignore
16*/
17define('IN_PHPBB', true);
18$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
19$phpEx = substr(strrchr(__FILE__, '.'), 1);
20include($phpbb_root_path . 'common.' . $phpEx);
21include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
22
23$mode = $request->variable('mode', '');
24
25if ($mode === 'contactadmin')
26{
27	define('SKIP_CHECK_BAN', true);
28	define('SKIP_CHECK_DISABLED', true);
29}
30
31// Start session management
32$user->session_begin();
33$auth->acl($user->data);
34$user->setup(array('memberlist', 'groups'));
35
36// Setting a variable to let the style designer know where he is...
37$template->assign_var('S_IN_MEMBERLIST', true);
38
39// Grab data
40$action		= $request->variable('action', '');
41$user_id	= $request->variable('u', ANONYMOUS);
42$username	= $request->variable('un', '', true);
43$group_id	= $request->variable('g', 0);
44$topic_id	= $request->variable('t', 0);
45
46// Redirect when old mode is used
47if ($mode == 'leaders')
48{
49	send_status_line(301, 'Moved Permanently');
50	redirect(append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=team'));
51}
52
53// Check our mode...
54if (!in_array($mode, array('', 'group', 'viewprofile', 'email', 'contact', 'contactadmin', 'searchuser', 'team', 'livesearch')))
55{
56	trigger_error('NO_MODE');
57}
58
59switch ($mode)
60{
61	case 'email':
62	case 'contactadmin':
63	break;
64
65	case 'livesearch':
66		if (!$config['allow_live_searches'])
67		{
68			trigger_error('LIVE_SEARCHES_NOT_ALLOWED');
69		}
70		// No break
71
72	default:
73		// Can this user view profiles/memberlist?
74		if (!$auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel'))
75		{
76			if ($user->data['user_id'] != ANONYMOUS)
77			{
78				send_status_line(403, 'Forbidden');
79				trigger_error('NO_VIEW_USERS');
80			}
81
82			login_box('', ((isset($user->lang['LOGIN_EXPLAIN_' . strtoupper($mode)])) ? $user->lang['LOGIN_EXPLAIN_' . strtoupper($mode)] : $user->lang['LOGIN_EXPLAIN_MEMBERLIST']));
83		}
84	break;
85}
86
87/** @var \phpbb\group\helper $group_helper */
88$group_helper = $phpbb_container->get('group_helper');
89
90$start	= $request->variable('start', 0);
91$submit = (isset($_POST['submit'])) ? true : false;
92
93$default_key = 'c';
94$sort_key = $request->variable('sk', $default_key);
95$sort_dir = $request->variable('sd', 'a');
96
97$user_types = array(USER_NORMAL, USER_FOUNDER);
98if ($auth->acl_get('a_user'))
99{
100	$user_types[] = USER_INACTIVE;
101}
102
103// What do you want to do today? ... oops, I think that line is taken ...
104switch ($mode)
105{
106	case 'team':
107		// Display a listing of board admins, moderators
108		if (!function_exists('user_get_id_name'))
109		{
110			include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
111		}
112
113		$page_title = $user->lang['THE_TEAM'];
114		$template_html = 'memberlist_team.html';
115
116		$sql = 'SELECT *
117			FROM ' . TEAMPAGE_TABLE . '
118			ORDER BY teampage_position ASC';
119		$result = $db->sql_query($sql, 3600);
120		$teampage_data = $db->sql_fetchrowset($result);
121		$db->sql_freeresult($result);
122
123		$sql_ary = array(
124			'SELECT'	=> 'g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id as ug_user_id, t.teampage_id',
125
126			'FROM'		=> array(GROUPS_TABLE => 'g'),
127
128			'LEFT_JOIN'	=> array(
129				array(
130					'FROM'	=> array(TEAMPAGE_TABLE => 't'),
131					'ON'	=> 't.group_id = g.group_id',
132				),
133				array(
134					'FROM'	=> array(USER_GROUP_TABLE => 'ug'),
135					'ON'	=> 'ug.group_id = g.group_id AND ug.user_pending = 0 AND ug.user_id = ' . (int) $user->data['user_id'],
136				),
137			),
138		);
139
140		$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
141
142		$group_ids = $groups_ary = array();
143		while ($row = $db->sql_fetchrow($result))
144		{
145			if ($row['group_type'] == GROUP_HIDDEN && !$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel') && $row['ug_user_id'] != $user->data['user_id'])
146			{
147				$row['group_name'] = $user->lang['GROUP_UNDISCLOSED'];
148				$row['u_group'] = '';
149			}
150			else
151			{
152				$row['group_name'] = $group_helper->get_name($row['group_name']);
153				$row['u_group'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $row['group_id']);
154			}
155
156			if ($row['teampage_id'])
157			{
158				// Only put groups into the array we want to display.
159				// We are fetching all groups, to ensure we got all data for default groups.
160				$group_ids[] = (int) $row['group_id'];
161			}
162			$groups_ary[(int) $row['group_id']] = $row;
163		}
164		$db->sql_freeresult($result);
165
166		$sql_ary = array(
167			'SELECT'	=> 'u.user_id, u.group_id as default_group, u.username, u.username_clean, u.user_colour, u.user_type, u.user_rank, u.user_posts, u.user_allow_pm, g.group_id',
168
169			'FROM'		=> array(
170				USER_GROUP_TABLE => 'ug',
171			),
172
173			'LEFT_JOIN'	=> array(
174				array(
175					'FROM'	=> array(USERS_TABLE => 'u'),
176					'ON'	=> 'ug.user_id = u.user_id',
177				),
178				array(
179					'FROM'	=> array(GROUPS_TABLE => 'g'),
180					'ON'	=> 'ug.group_id = g.group_id',
181				),
182			),
183
184			'WHERE'		=> $db->sql_in_set('g.group_id', $group_ids, false, true) . ' AND ug.user_pending = 0',
185
186			'ORDER_BY'	=> 'u.username_clean ASC',
187		);
188
189		/**
190		 * Modify the query used to get the users for the team page
191		 *
192		 * @event core.memberlist_team_modify_query
193		 * @var array	sql_ary			Array containing the query
194		 * @var array	group_ids		Array of group ids
195		 * @var array	teampage_data	The teampage data
196		 * @since 3.1.3-RC1
197		 */
198		$vars = array(
199			'sql_ary',
200			'group_ids',
201			'teampage_data',
202		);
203		extract($phpbb_dispatcher->trigger_event('core.memberlist_team_modify_query', compact($vars)));
204
205		$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
206
207		$user_ary = $user_ids = $group_users = array();
208		while ($row = $db->sql_fetchrow($result))
209		{
210			$row['forums'] = '';
211			$row['forums_ary'] = array();
212			$user_ary[(int) $row['user_id']] = $row;
213			$user_ids[] = (int) $row['user_id'];
214			$group_users[(int) $row['group_id']][] = (int) $row['user_id'];
215		}
216		$db->sql_freeresult($result);
217
218		$user_ids = array_unique($user_ids);
219
220		if (!empty($user_ids) && $config['teampage_forums'])
221		{
222			$template->assign_var('S_DISPLAY_MODERATOR_FORUMS', true);
223			// Get all moderators
224			$perm_ary = $auth->acl_get_list($user_ids, array('m_'), false);
225
226			foreach ($perm_ary as $forum_id => $forum_ary)
227			{
228				foreach ($forum_ary as $auth_option => $id_ary)
229				{
230					foreach ($id_ary as $id)
231					{
232						if (!$forum_id)
233						{
234							$user_ary[$id]['forums'] = $user->lang['ALL_FORUMS'];
235						}
236						else
237						{
238							$user_ary[$id]['forums_ary'][] = $forum_id;
239						}
240					}
241				}
242			}
243
244			$sql = 'SELECT forum_id, forum_name
245				FROM ' . FORUMS_TABLE;
246			$result = $db->sql_query($sql);
247
248			$forums = array();
249			while ($row = $db->sql_fetchrow($result))
250			{
251				$forums[$row['forum_id']] = $row['forum_name'];
252			}
253			$db->sql_freeresult($result);
254
255			foreach ($user_ary as $user_id => $user_data)
256			{
257				if (!$user_data['forums'])
258				{
259					foreach ($user_data['forums_ary'] as $forum_id)
260					{
261						$user_ary[$user_id]['forums_options'] = true;
262						if (isset($forums[$forum_id]))
263						{
264							if ($auth->acl_get('f_list', $forum_id))
265							{
266								$user_ary[$user_id]['forums'] .= '<option value="">' . $forums[$forum_id] . '</option>';
267							}
268						}
269					}
270				}
271			}
272		}
273
274		$parent_team = 0;
275		foreach ($teampage_data as $team_data)
276		{
277			// If this team entry has no group, it's a category
278			if (!$team_data['group_id'])
279			{
280				$template->assign_block_vars('group', array(
281					'GROUP_NAME'  => $team_data['teampage_name'],
282				));
283
284				$parent_team = (int) $team_data['teampage_id'];
285				continue;
286			}
287
288			$group_data = $groups_ary[(int) $team_data['group_id']];
289			$group_id = (int) $team_data['group_id'];
290
291			if (!$team_data['teampage_parent'])
292			{
293				// If the group does not have a parent category, we display the groupname as category
294				$template->assign_block_vars('group', array(
295					'GROUP_NAME'	=> $group_data['group_name'],
296					'GROUP_COLOR'	=> $group_data['group_colour'],
297					'U_GROUP'		=> $group_data['u_group'],
298				));
299			}
300
301			// Display group members.
302			if (!empty($group_users[$group_id]))
303			{
304				foreach ($group_users[$group_id] as $user_id)
305				{
306					if (isset($user_ary[$user_id]))
307					{
308						$row = $user_ary[$user_id];
309						if ($config['teampage_memberships'] == 1 && ($group_id != $groups_ary[$row['default_group']]['group_id']) && $groups_ary[$row['default_group']]['teampage_id'])
310						{
311							// Display users in their primary group, instead of the first group, when it is displayed on the teampage.
312							continue;
313						}
314
315						$user_rank_data = phpbb_get_user_rank($row, (($row['user_id'] == ANONYMOUS) ? false : $row['user_posts']));
316
317						$template_vars = array(
318							'USER_ID'		=> $row['user_id'],
319							'FORUMS'		=> $row['forums'],
320							'FORUM_OPTIONS'	=> (isset($row['forums_options'])) ? true : false,
321							'RANK_TITLE'	=> $user_rank_data['title'],
322
323							'GROUP_NAME'	=> $groups_ary[$row['default_group']]['group_name'],
324							'GROUP_COLOR'	=> $groups_ary[$row['default_group']]['group_colour'],
325							'U_GROUP'		=> $groups_ary[$row['default_group']]['u_group'],
326
327							'RANK_IMG'		=> $user_rank_data['img'],
328							'RANK_IMG_SRC'	=> $user_rank_data['img_src'],
329
330							'S_INACTIVE'	=> $row['user_type'] == USER_INACTIVE,
331
332							'U_PM'			=> ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($row['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;mode=compose&amp;u=' . $row['user_id']) : '',
333
334							'USERNAME_FULL'		=> get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']),
335							'USERNAME'			=> get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']),
336							'USER_COLOR'		=> get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']),
337							'U_VIEW_PROFILE'	=> get_username_string('profile', $row['user_id'], $row['username'], $row['user_colour']),
338						);
339
340						/**
341						 * Modify the template vars for displaying the user in the groups on the teampage
342						 *
343						 * @event core.memberlist_team_modify_template_vars
344						 * @var array	template_vars		Array containing the query
345						 * @var array	row					Array containing the action user row
346						 * @var array	groups_ary			Array of groups with all users that should be displayed
347						 * @since 3.1.3-RC1
348						 */
349						$vars = array(
350							'template_vars',
351							'row',
352							'groups_ary',
353						);
354						extract($phpbb_dispatcher->trigger_event('core.memberlist_team_modify_template_vars', compact($vars)));
355
356						$template->assign_block_vars('group.user', $template_vars);
357
358						if ($config['teampage_memberships'] != 2)
359						{
360							unset($user_ary[$user_id]);
361						}
362					}
363				}
364			}
365		}
366
367		$template->assign_block_vars('navlinks', array(
368			'BREADCRUMB_NAME'	=> $page_title,
369			'U_BREADCRUMB'		=> append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=team"),
370		));
371
372		$template->assign_vars(array(
373			'PM_IMG'		=> $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE']))
374		);
375	break;
376
377	case 'contact':
378
379		$page_title = $user->lang['IM_USER'];
380		$template_html = 'memberlist_im.html';
381
382		if (!$auth->acl_get('u_sendim'))
383		{
384			send_status_line(403, 'Forbidden');
385			trigger_error('NOT_AUTHORISED');
386		}
387
388		$presence_img = '';
389		switch ($action)
390		{
391			case 'jabber':
392				$lang = 'JABBER';
393				$sql_field = 'user_jabber';
394				$s_select = (@extension_loaded('xml') && $config['jab_enable']) ? 'S_SEND_JABBER' : 'S_NO_SEND_JABBER';
395				$s_action = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&amp;action=$action&amp;u=$user_id");
396			break;
397
398			default:
399				trigger_error('NO_MODE', E_USER_ERROR);
400			break;
401		}
402
403		// Grab relevant data
404		$sql = "SELECT user_id, username, user_email, user_lang, $sql_field
405			FROM " . USERS_TABLE . "
406			WHERE user_id = $user_id
407				AND user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')';
408		$result = $db->sql_query($sql);
409		$row = $db->sql_fetchrow($result);
410		$db->sql_freeresult($result);
411
412		if (!$row)
413		{
414			trigger_error('NO_USER');
415		}
416		else if (empty($row[$sql_field]))
417		{
418			trigger_error('IM_NO_DATA');
419		}
420
421		// Post data grab actions
422		switch ($action)
423		{
424			case 'jabber':
425				add_form_key('memberlist_messaging');
426
427				if ($submit && @extension_loaded('xml') && $config['jab_enable'])
428				{
429					if (check_form_key('memberlist_messaging'))
430					{
431
432						include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
433
434						$subject = sprintf($user->lang['IM_JABBER_SUBJECT'], $user->data['username'], $config['server_name']);
435						$message = $request->variable('message', '', true);
436
437						if (empty($message))
438						{
439							trigger_error('EMPTY_MESSAGE_IM');
440						}
441
442						$messenger = new messenger(false);
443
444						$messenger->template('profile_send_im', $row['user_lang']);
445						$messenger->subject(htmlspecialchars_decode($subject, ENT_COMPAT));
446
447						$messenger->replyto($user->data['user_email']);
448						$messenger->set_addresses($row);
449
450						$messenger->assign_vars(array(
451							'BOARD_CONTACT'	=> phpbb_get_board_contact($config, $phpEx),
452							'FROM_USERNAME'	=> htmlspecialchars_decode($user->data['username'], ENT_COMPAT),
453							'TO_USERNAME'	=> htmlspecialchars_decode($row['username'], ENT_COMPAT),
454							'MESSAGE'		=> htmlspecialchars_decode($message, ENT_COMPAT))
455						);
456
457						$messenger->send(NOTIFY_IM);
458
459						$s_select = 'S_SENT_JABBER';
460					}
461					else
462					{
463						trigger_error('FORM_INVALID');
464					}
465				}
466			break;
467		}
468
469		$template->assign_block_vars('navlinks', array(
470			'BREADCRUMB_NAME'	=> $page_title,
471			'U_BREADCRUMB'		=> append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&amp;action=$action&amp;u=$user_id"),
472		));
473
474		// Send vars to the template
475		$template->assign_vars(array(
476			'IM_CONTACT'	=> $row[$sql_field],
477			'A_IM_CONTACT'	=> addslashes($row[$sql_field]),
478
479			'USERNAME'		=> $row['username'],
480			'CONTACT_NAME'	=> $row[$sql_field],
481			'SITENAME'		=> $config['sitename'],
482
483			'PRESENCE_IMG'		=> $presence_img,
484
485			'L_SEND_IM_EXPLAIN'	=> $user->lang['IM_' . $lang],
486			'L_IM_SENT_JABBER'	=> sprintf($user->lang['IM_SENT_JABBER'], $row['username']),
487
488			$s_select			=> true,
489			'S_IM_ACTION'		=> $s_action)
490		);
491
492	break;
493
494	case 'viewprofile':
495		// Display a profile
496		if ($user_id == ANONYMOUS && !$username)
497		{
498			trigger_error('NO_USER');
499		}
500
501		// Get user...
502		$sql_array = array(
503			'SELECT'	=> 'u.*',
504			'FROM'		=> array(
505				USERS_TABLE		=> 'u'
506			),
507			'WHERE'		=> (($username) ? "u.username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'" : "u.user_id = $user_id"),
508		);
509
510		/**
511		 * Modify user data SQL before member profile row is created
512		 *
513		 * @event core.memberlist_modify_viewprofile_sql
514		 * @var int		user_id				The user ID
515		 * @var string	username			The username
516		 * @var array	sql_array			Array containing the main query
517		 * @since 3.2.6-RC1
518		 */
519		$vars = array(
520			'user_id',
521			'username',
522			'sql_array',
523		);
524		extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_viewprofile_sql', compact($vars)));
525
526		$sql = $db->sql_build_query('SELECT', $sql_array);
527		$result = $db->sql_query($sql);
528		$member = $db->sql_fetchrow($result);
529		$db->sql_freeresult($result);
530
531		if (!$member)
532		{
533			trigger_error('NO_USER');
534		}
535
536		// a_user admins and founder are able to view inactive users and bots to be able to manage them more easily
537		// Normal users are able to see at least users having only changed their profile settings but not yet reactivated.
538		if (!$auth->acl_get('a_user') && $user->data['user_type'] != USER_FOUNDER)
539		{
540			if ($member['user_type'] == USER_IGNORE)
541			{
542				trigger_error('NO_USER');
543			}
544			else if ($member['user_type'] == USER_INACTIVE && $member['user_inactive_reason'] != INACTIVE_PROFILE)
545			{
546				trigger_error('NO_USER');
547			}
548		}
549
550		$user_id = (int) $member['user_id'];
551
552		// Get group memberships
553		// Also get visiting user's groups to determine hidden group memberships if necessary.
554		$auth_hidden_groups = ($user_id === (int) $user->data['user_id'] || $auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? true : false;
555		$sql_uid_ary = ($auth_hidden_groups) ? array($user_id) : array($user_id, (int) $user->data['user_id']);
556
557		// Do the SQL thang
558		$sql_ary = [
559			'SELECT'	=> 'g.group_id, g.group_name, g.group_type, ug.user_id',
560
561			'FROM'		=> [
562				GROUPS_TABLE => 'g',
563			],
564
565			'LEFT_JOIN' => [
566				[
567					'FROM' => [USER_GROUP_TABLE => 'ug'],
568					'ON'   => 'g.group_id = ug.group_id',
569				],
570			],
571
572			'WHERE'		=> $db->sql_in_set('ug.user_id', $sql_uid_ary) . '
573				AND ug.user_pending = 0',
574		];
575
576		/**
577		* Modify the query used to get the group data
578		*
579		* @event core.modify_memberlist_viewprofile_group_sql
580		* @var array	sql_ary			Array containing the query
581		* @since 3.2.6-RC1
582		*/
583		$vars = array(
584			'sql_ary',
585		);
586		extract($phpbb_dispatcher->trigger_event('core.modify_memberlist_viewprofile_group_sql', compact($vars)));
587
588		$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
589
590		// Divide data into profile data and current user data
591		$profile_groups = $user_groups = array();
592		while ($row = $db->sql_fetchrow($result))
593		{
594			$row['user_id'] = (int) $row['user_id'];
595			$row['group_id'] = (int) $row['group_id'];
596
597			if ($row['user_id'] == $user_id)
598			{
599				$profile_groups[] = $row;
600			}
601			else
602			{
603				$user_groups[$row['group_id']] = $row['group_id'];
604			}
605		}
606		$db->sql_freeresult($result);
607
608		// Filter out hidden groups and sort groups by name
609		$group_data = $group_sort = array();
610		foreach ($profile_groups as $row)
611		{
612			if (!$auth_hidden_groups && $row['group_type'] == GROUP_HIDDEN && !isset($user_groups[$row['group_id']]))
613			{
614				// Skip over hidden groups the user cannot see
615				continue;
616			}
617
618			$row['group_name'] = $group_helper->get_name($row['group_name']);
619
620			$group_sort[$row['group_id']] = utf8_clean_string($row['group_name']);
621			$group_data[$row['group_id']] = $row;
622		}
623		unset($profile_groups);
624		unset($user_groups);
625		asort($group_sort);
626
627		/**
628		* Modify group data before options is created and data is unset
629		*
630		* @event core.modify_memberlist_viewprofile_group_data
631		* @var array	group_data			Array containing the group data
632		* @var array	group_sort			Array containing the sorted group data
633		* @since 3.2.6-RC1
634		*/
635		$vars = array(
636			'group_data',
637			'group_sort',
638		);
639		extract($phpbb_dispatcher->trigger_event('core.modify_memberlist_viewprofile_group_data', compact($vars)));
640
641		$group_options = '';
642		foreach ($group_sort as $group_id => $null)
643		{
644			$row = $group_data[$group_id];
645
646			$group_options .= '<option value="' . $row['group_id'] . '"' . (($row['group_id'] == $member['group_id']) ? ' selected="selected"' : '') . '>' . $row['group_name'] . '</option>';
647		}
648		unset($group_data);
649		unset($group_sort);
650
651		// What colour is the zebra
652		$sql = 'SELECT friend, foe
653			FROM ' . ZEBRA_TABLE . "
654			WHERE zebra_id = $user_id
655				AND user_id = {$user->data['user_id']}";
656		$result = $db->sql_query($sql);
657		$row = $db->sql_fetchrow($result);
658
659		$foe = $row ? (bool) $row['foe'] : false;
660		$friend = $row ? (bool) $row['friend'] : false;
661
662		$db->sql_freeresult($result);
663
664		if ($config['load_onlinetrack'])
665		{
666			$sql = 'SELECT MAX(session_time) AS session_time, MIN(session_viewonline) AS session_viewonline
667				FROM ' . SESSIONS_TABLE . "
668				WHERE session_user_id = $user_id";
669			$result = $db->sql_query($sql);
670			$row = $db->sql_fetchrow($result);
671			$db->sql_freeresult($result);
672
673			$member['session_time'] = (isset($row['session_time'])) ? $row['session_time'] : 0;
674			$member['session_viewonline'] = (isset($row['session_viewonline'])) ? $row['session_viewonline'] : 0;
675			unset($row);
676		}
677
678		if ($config['load_user_activity'])
679		{
680			display_user_activity($member);
681		}
682
683		// Do the relevant calculations
684		$memberdays = max(1, round((time() - $member['user_regdate']) / 86400));
685		$posts_per_day = $member['user_posts'] / $memberdays;
686		$percentage = ($config['num_posts']) ? min(100, ($member['user_posts'] / $config['num_posts']) * 100) : 0;
687
688
689		if ($member['user_sig'])
690		{
691			$parse_flags = ($member['user_sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
692			$member['user_sig'] = generate_text_for_display($member['user_sig'], $member['user_sig_bbcode_uid'], $member['user_sig_bbcode_bitfield'], $parse_flags, true);
693		}
694
695		// We need to check if the modules 'zebra' ('friends' & 'foes' mode),  'notes' ('user_notes' mode) and  'warn' ('warn_user' mode) are accessible to decide if we can display appropriate links
696		$zebra_enabled = $friends_enabled = $foes_enabled = $user_notes_enabled = $warn_user_enabled = false;
697
698		// Only check if the user is logged in
699		if ($user->data['is_registered'])
700		{
701			if (!class_exists('p_master'))
702			{
703				include($phpbb_root_path . 'includes/functions_module.' . $phpEx);
704			}
705			$module = new p_master();
706
707			$module->list_modules('ucp');
708			$module->list_modules('mcp');
709
710			$user_notes_enabled = ($module->loaded('mcp_notes', 'user_notes')) ? true : false;
711			$warn_user_enabled = ($module->loaded('mcp_warn', 'warn_user')) ? true : false;
712			$zebra_enabled = ($module->loaded('ucp_zebra')) ? true : false;
713			$friends_enabled = ($module->loaded('ucp_zebra', 'friends')) ? true : false;
714			$foes_enabled = ($module->loaded('ucp_zebra', 'foes')) ? true : false;
715
716			unset($module);
717		}
718
719		// Custom Profile Fields
720		$profile_fields = array();
721		if ($config['load_cpf_viewprofile'])
722		{
723			/* @var $cp \phpbb\profilefields\manager */
724			$cp = $phpbb_container->get('profilefields.manager');
725			$profile_fields = $cp->grab_profile_fields_data($user_id);
726			$profile_fields = (isset($profile_fields[$user_id])) ? $cp->generate_profile_fields_template_data($profile_fields[$user_id]) : array();
727		}
728
729		/**
730		* Modify user data before we display the profile
731		*
732		* @event core.memberlist_view_profile
733		* @var	array	member					Array with user's data
734		* @var	bool	user_notes_enabled		Is the mcp user notes module enabled?
735		* @var	bool	warn_user_enabled		Is the mcp warnings module enabled?
736		* @var	bool	zebra_enabled			Is the ucp zebra module enabled?
737		* @var	bool	friends_enabled			Is the ucp friends module enabled?
738		* @var	bool	foes_enabled			Is the ucp foes module enabled?
739		* @var	bool    friend					Is the user friend?
740		* @var	bool	foe						Is the user foe?
741		* @var	array	profile_fields			Array with user's profile field data
742		* @since 3.1.0-a1
743		* @changed 3.1.0-b2 Added friend and foe status
744		* @changed 3.1.0-b3 Added profile fields data
745		*/
746		$vars = array(
747			'member',
748			'user_notes_enabled',
749			'warn_user_enabled',
750			'zebra_enabled',
751			'friends_enabled',
752			'foes_enabled',
753			'friend',
754			'foe',
755			'profile_fields',
756		);
757		extract($phpbb_dispatcher->trigger_event('core.memberlist_view_profile', compact($vars)));
758
759		$template->assign_vars(phpbb_show_profile($member, $user_notes_enabled, $warn_user_enabled));
760
761		// If the user has m_approve permission or a_user permission, then list then display unapproved posts
762		if ($auth->acl_getf_global('m_approve') || $auth->acl_get('a_user'))
763		{
764			$sql = 'SELECT COUNT(post_id) as posts_in_queue
765				FROM ' . POSTS_TABLE . '
766				WHERE poster_id = ' . $user_id . '
767					AND ' . $db->sql_in_set('post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE));
768			$result = $db->sql_query($sql);
769			$member['posts_in_queue'] = (int) $db->sql_fetchfield('posts_in_queue');
770			$db->sql_freeresult($result);
771		}
772		else
773		{
774			$member['posts_in_queue'] = 0;
775		}
776
777		// Define the main array of vars to assign to memberlist_view.html
778		$template_ary = array(
779			'L_POSTS_IN_QUEUE'			=> $user->lang('NUM_POSTS_IN_QUEUE', $member['posts_in_queue']),
780
781			'POSTS_DAY'					=> $user->lang('POST_DAY', $posts_per_day),
782			'POSTS_PCT'					=> $user->lang('POST_PCT', $percentage),
783
784			'SIGNATURE'					=> $member['user_sig'],
785			'POSTS_IN_QUEUE'			=> $member['posts_in_queue'],
786
787			'PM_IMG'					=> $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE']),
788			'L_SEND_EMAIL_USER'			=> $user->lang('SEND_EMAIL_USER', $member['username']),
789			'EMAIL_IMG'					=> $user->img('icon_contact_email', $user->lang['EMAIL']),
790			'JABBER_IMG'				=> $user->img('icon_contact_jabber', $user->lang['JABBER']),
791			'SEARCH_IMG'				=> $user->img('icon_user_search', $user->lang['SEARCH']),
792
793			'S_PROFILE_ACTION'			=> append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group'),
794			'S_GROUP_OPTIONS'			=> $group_options,
795			'S_CUSTOM_FIELDS'			=> (isset($profile_fields['row']) && count($profile_fields['row'])) ? true : false,
796
797			'U_USER_ADMIN'				=> ($auth->acl_get('a_user')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview&amp;u=' . $user_id, true, $user->session_id) : '',
798			'U_USER_BAN'				=> ($auth->acl_get('m_ban') && $user_id != $user->data['user_id']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=ban&amp;mode=user&amp;u=' . $user_id, true, $user->session_id) : '',
799			'U_MCP_QUEUE'				=> ($auth->acl_getf_global('m_approve')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue', true, $user->session_id) : '',
800
801			'U_SWITCH_PERMISSIONS'		=> ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_id) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&amp;u={$user_id}&amp;hash=" . generate_link_hash('switchperm')) : '',
802			'U_EDIT_SELF'				=> ($user_id == $user->data['user_id'] && $auth->acl_get('u_chgprofileinfo')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_profile&amp;mode=profile_info') : '',
803
804			'S_USER_NOTES'				=> ($user_notes_enabled) ? true : false,
805			'S_WARN_USER'				=> ($warn_user_enabled) ? true : false,
806			'S_ZEBRA'					=> ($user->data['user_id'] != $user_id && $user->data['is_registered'] && $zebra_enabled) ? true : false,
807			'U_ADD_FRIEND'				=> (!$friend && !$foe && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;add=' . urlencode(htmlspecialchars_decode($member['username'], ENT_COMPAT))) : '',
808			'U_ADD_FOE'					=> (!$friend && !$foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;mode=foes&amp;add=' . urlencode(htmlspecialchars_decode($member['username'], ENT_COMPAT))) : '',
809			'U_REMOVE_FRIEND'			=> ($friend && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;remove=1&amp;usernames[]=' . $user_id) : '',
810			'U_REMOVE_FOE'				=> ($foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;remove=1&amp;mode=foes&amp;usernames[]=' . $user_id) : '',
811
812			'U_CANONICAL'				=> generate_board_url() . '/' . append_sid("memberlist.$phpEx", 'mode=viewprofile&amp;u=' . $user_id, true, ''),
813		);
814
815		/**
816		* Modify user's template vars before we display the profile
817		*
818		* @event core.memberlist_modify_view_profile_template_vars
819		* @var	array	template_ary	Array with user's template vars
820		* @since 3.2.6-RC1
821		*/
822		$vars = array(
823			'template_ary',
824		);
825		extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_view_profile_template_vars', compact($vars)));
826
827		// Assign vars to memberlist_view.html
828		$template->assign_vars($template_ary);
829
830		if (!empty($profile_fields['row']))
831		{
832			$template->assign_vars($profile_fields['row']);
833		}
834
835		if (!empty($profile_fields['blockrow']))
836		{
837			foreach ($profile_fields['blockrow'] as $field_data)
838			{
839				$template->assign_block_vars('custom_fields', $field_data);
840			}
841		}
842
843		// Inactive reason/account?
844		if ($member['user_type'] == USER_INACTIVE)
845		{
846			$user->add_lang('acp/common');
847
848			$inactive_reason = $user->lang['INACTIVE_REASON_UNKNOWN'];
849
850			switch ($member['user_inactive_reason'])
851			{
852				case INACTIVE_REGISTER:
853					$inactive_reason = $user->lang['INACTIVE_REASON_REGISTER'];
854				break;
855
856				case INACTIVE_PROFILE:
857					$inactive_reason = $user->lang['INACTIVE_REASON_PROFILE'];
858				break;
859
860				case INACTIVE_MANUAL:
861					$inactive_reason = $user->lang['INACTIVE_REASON_MANUAL'];
862				break;
863
864				case INACTIVE_REMIND:
865					$inactive_reason = $user->lang['INACTIVE_REASON_REMIND'];
866				break;
867			}
868
869			$template->assign_vars(array(
870				'S_USER_INACTIVE'		=> true,
871				'USER_INACTIVE_REASON'	=> $inactive_reason)
872			);
873		}
874
875		// Now generate page title
876		$page_title = sprintf($user->lang['VIEWING_PROFILE'], $member['username']);
877		$template_html = 'memberlist_view.html';
878
879		$template->assign_block_vars('navlinks', array(
880			'BREADCRUMB_NAME'	=> $user->lang('MEMBERLIST'),
881			'U_BREADCRUMB'		=> append_sid("{$phpbb_root_path}memberlist.$phpEx"),
882		));
883		$template->assign_block_vars('navlinks', array(
884			'BREADCRUMB_NAME'	=> $member['username'],
885			'U_BREADCRUMB'		=> append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=viewprofile&u=$user_id"),
886		));
887
888	break;
889
890	case 'contactadmin':
891	case 'email':
892		if (!class_exists('messenger'))
893		{
894			include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
895		}
896
897		$user_id	= $request->variable('u', 0);
898		$topic_id	= $request->variable('t', 0);
899
900		if ($user_id)
901		{
902			$form_name = 'user';
903		}
904		else if ($topic_id)
905		{
906			$form_name = 'topic';
907		}
908		else if ($mode === 'contactadmin')
909		{
910			$form_name = 'admin';
911		}
912		else
913		{
914			trigger_error('NO_EMAIL');
915		}
916
917		/** @var $form \phpbb\message\form */
918		$form = $phpbb_container->get('message.form.' . $form_name);
919
920		$form->bind($request);
921		$error = $form->check_allow();
922		if ($error)
923		{
924			trigger_error($error);
925		}
926
927		if ($request->is_set_post('submit'))
928		{
929			$messenger = new messenger(false);
930			$form->submit($messenger);
931		}
932
933		$page_title = $form->get_page_title();
934		$template_html = $form->get_template_file();
935		$form->render($template);
936
937		if ($user_id)
938		{
939			$navlink_name = $user->lang('SEND_EMAIL');
940			$navlink_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&u=$user_id");
941		}
942		else if ($topic_id)
943		{
944			$sql = 'SELECT f.parent_id, f.forum_parents, f.left_id, f.right_id, f.forum_type, f.forum_name, f.forum_id, f.forum_desc, f.forum_desc_uid, f.forum_desc_bitfield, f.forum_desc_options, f.forum_options, t.topic_title
945					FROM ' . FORUMS_TABLE . ' as f,
946						' . TOPICS_TABLE . ' as t
947					WHERE t.forum_id = f.forum_id';
948			$result = $db->sql_query($sql);
949			$topic_data = $db->sql_fetchrow($result);
950			$db->sql_freeresult($result);
951
952			generate_forum_nav($topic_data);
953			$template->assign_block_vars('navlinks', array(
954				'BREADCRUMB_NAME'	=> $topic_data['topic_title'],
955				'U_BREADCRUMB'		=> append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id"),
956			));
957
958			$navlink_name = $user->lang('EMAIL_TOPIC');
959			$navlink_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&t=$topic_id");
960		}
961		else if ($mode === 'contactadmin')
962		{
963			$navlink_name = $user->lang('CONTACT_ADMIN');
964			$navlink_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contactadmin");
965		}
966
967		$template->assign_block_vars('navlinks', array(
968			'BREADCRUMB_NAME'	=> $navlink_name,
969			'U_BREADCRUMB'		=> $navlink_url,
970		));
971
972	break;
973
974	case 'livesearch':
975
976		$username_chars = $request->variable('username', '', true);
977
978		$sql = 'SELECT username, user_id, user_colour
979			FROM ' . USERS_TABLE . '
980			WHERE ' . $db->sql_in_set('user_type', $user_types) . '
981				AND username_clean ' . $db->sql_like_expression(utf8_clean_string($username_chars) . $db->get_any_char());
982		$result = $db->sql_query_limit($sql, 10);
983		$user_list = array();
984
985		while ($row = $db->sql_fetchrow($result))
986		{
987			$user_list[] = array(
988				'user_id'		=> (int) $row['user_id'],
989				'result'		=> $row['username'],
990				'username_full'	=> get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']),
991				'display'		=> get_username_string('no_profile', $row['user_id'], $row['username'], $row['user_colour']),
992			);
993		}
994		$db->sql_freeresult($result);
995		$json_response = new \phpbb\json_response();
996		$json_response->send(array(
997			'keyword' => $username_chars,
998			'results' => $user_list,
999		));
1000
1001	break;
1002
1003	case 'group':
1004	default:
1005		// The basic memberlist
1006		$page_title = $user->lang['MEMBERLIST'];
1007		$template_html = 'memberlist_body.html';
1008
1009		$template->assign_block_vars('navlinks', array(
1010			'BREADCRUMB_NAME'	=> $page_title,
1011			'U_BREADCRUMB'		=> append_sid("{$phpbb_root_path}memberlist.$phpEx"),
1012		));
1013
1014		/* @var $pagination \phpbb\pagination */
1015		$pagination = $phpbb_container->get('pagination');
1016
1017		// Sorting
1018		$sort_key_text = array('a' => $user->lang['SORT_USERNAME'], 'c' => $user->lang['SORT_JOINED'], 'd' => $user->lang['SORT_POST_COUNT']);
1019		$sort_key_sql = array('a' => 'u.username_clean', 'c' => 'u.user_regdate', 'd' => 'u.user_posts');
1020
1021		if ($config['jab_enable'] && $auth->acl_get('u_sendim'))
1022		{
1023			$sort_key_text['k'] = $user->lang['JABBER'];
1024			$sort_key_sql['k'] = 'u.user_jabber';
1025		}
1026
1027		if ($auth->acl_get('a_user'))
1028		{
1029			$sort_key_text['e'] = $user->lang['SORT_EMAIL'];
1030			$sort_key_sql['e'] = 'u.user_email';
1031		}
1032
1033		if ($auth->acl_get('u_viewonline'))
1034		{
1035			$sort_key_text['l'] = $user->lang['SORT_LAST_ACTIVE'];
1036			$sort_key_sql['l'] = 'u.user_lastvisit';
1037		}
1038
1039		$sort_key_text['m'] = $user->lang['SORT_RANK'];
1040		$sort_key_sql['m'] = 'u.user_rank';
1041
1042		$sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']);
1043
1044		$s_sort_key = '';
1045		foreach ($sort_key_text as $key => $value)
1046		{
1047			$selected = ($sort_key == $key) ? ' selected="selected"' : '';
1048			$s_sort_key .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
1049		}
1050
1051		$s_sort_dir = '';
1052		foreach ($sort_dir_text as $key => $value)
1053		{
1054			$selected = ($sort_dir == $key) ? ' selected="selected"' : '';
1055			$s_sort_dir .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
1056		}
1057
1058		// Additional sorting options for user search ... if search is enabled, if not
1059		// then only admins can make use of this (for ACP functionality)
1060		$sql_select = $sql_where_data = $sql_from = $sql_where = $order_by = '';
1061
1062
1063		$form			= $request->variable('form', '');
1064		$field			= $request->variable('field', '');
1065		$select_single 	= $request->variable('select_single', false);
1066
1067		// Search URL parameters, if any of these are in the URL we do a search
1068		$search_params = array('username', 'email', 'jabber', 'search_group_id', 'joined_select', 'active_select', 'count_select', 'joined', 'active', 'count', 'ip');
1069
1070		// We validate form and field here, only id/class allowed
1071		$form = (!preg_match('/^[a-z0-9_-]+$/i', $form)) ? '' : $form;
1072		$field = (!preg_match('/^[a-z0-9_-]+$/i', $field)) ? '' : $field;
1073		if ((($mode == '' || $mode == 'searchuser') || count(array_intersect($request->variable_names(\phpbb\request\request_interface::GET), $search_params)) > 0) && ($config['load_search'] || $auth->acl_get('a_')))
1074		{
1075			$username	= $request->variable('username', '', true);
1076			$email		= strtolower($request->variable('email', ''));
1077			$jabber		= $request->variable('jabber', '');
1078			$search_group_id	= $request->variable('search_group_id', 0);
1079
1080			// when using these, make sure that we actually have values defined in $find_key_match
1081			$joined_select	= $request->variable('joined_select', 'lt');
1082			$active_select	= $request->variable('active_select', 'lt');
1083			$count_select	= $request->variable('count_select', 'eq');
1084
1085			$joined			= explode('-', $request->variable('joined', ''));
1086			$active			= explode('-', $request->variable('active', ''));
1087			$count			= ($request->variable('count', '') !== '') ? $request->variable('count', 0) : '';
1088			$ipdomain		= $request->variable('ip', '');
1089
1090			$find_key_match = array('lt' => '<', 'gt' => '>', 'eq' => '=');
1091
1092			$find_count = array('lt' => $user->lang['LESS_THAN'], 'eq' => $user->lang['EQUAL_TO'], 'gt' => $user->lang['MORE_THAN']);
1093			$s_find_count = '';
1094			foreach ($find_count as $key => $value)
1095			{
1096				$selected = ($count_select == $key) ? ' selected="selected"' : '';
1097				$s_find_count .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
1098			}
1099
1100			$find_time = array('lt' => $user->lang['BEFORE'], 'gt' => $user->lang['AFTER']);
1101			$s_find_join_time = '';
1102			foreach ($find_time as $key => $value)
1103			{
1104				$selected = ($joined_select == $key) ? ' selected="selected"' : '';
1105				$s_find_join_time .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
1106			}
1107
1108			$s_find_active_time = '';
1109			foreach ($find_time as $key => $value)
1110			{
1111				$selected = ($active_select == $key) ? ' selected="selected"' : '';
1112				$s_find_active_time .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
1113			}
1114
1115			$sql_where .= ($username) ? ' AND u.username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($username))) : '';
1116			$sql_where .= ($auth->acl_get('a_user') && $email) ? ' AND u.user_email ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $email)) . ' ' : '';
1117			$sql_where .= ($jabber) ? ' AND u.user_jabber ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $jabber)) . ' ' : '';
1118			$sql_where .= (is_numeric($count) && isset($find_key_match[$count_select])) ? ' AND u.user_posts ' . $find_key_match[$count_select] . ' ' . (int) $count . ' ' : '';
1119
1120			if (isset($find_key_match[$joined_select]) && count($joined) == 3)
1121			{
1122				$joined_time = gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]);
1123
1124				if ($joined_time !== false)
1125				{
1126					$sql_where .= " AND u.user_regdate " . $find_key_match[$joined_select] . ' ' . $joined_time;
1127				}
1128			}
1129
1130			if (isset($find_key_match[$active_select]) && count($active) == 3 && $auth->acl_get('u_viewonline'))
1131			{
1132				$active_time = gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]);
1133
1134				if ($active_time !== false)
1135				{
1136					if ($active_select === 'lt' && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0)
1137					{
1138						$sql_where .= ' AND u.user_lastvisit = 0';
1139					}
1140					else if ($active_select === 'gt')
1141					{
1142						$sql_where .= ' AND u.user_lastvisit ' . $find_key_match[$active_select] . ' ' . $active_time;
1143					}
1144					else
1145					{
1146						$sql_where .= ' AND (u.user_lastvisit > 0 AND u.user_lastvisit < ' . $active_time . ')';
1147					}
1148				}
1149			}
1150
1151			$sql_where .= ($search_group_id) ? " AND u.user_id = ug.user_id AND ug.group_id = $search_group_id AND ug.user_pending = 0 " : '';
1152
1153			if ($search_group_id)
1154			{
1155				$sql_from = ', ' . USER_GROUP_TABLE . ' ug ';
1156			}
1157
1158			if ($ipdomain && $auth->acl_getf_global('m_info'))
1159			{
1160				if (strspn($ipdomain, 'abcdefghijklmnopqrstuvwxyz'))
1161				{
1162					$hostnames = gethostbynamel($ipdomain);
1163
1164					if ($hostnames !== false)
1165					{
1166						$ips = "'" . implode('\', \'', array_map(array($db, 'sql_escape'), preg_replace('#([0-9]{1,3}\.[0-9]{1,3}[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})#', "\\1", gethostbynamel($ipdomain)))) . "'";
1167					}
1168					else
1169					{
1170						$ips = false;
1171					}
1172				}
1173				else
1174				{
1175					$ips = "'" . str_replace('*', '%', $db->sql_escape($ipdomain)) . "'";
1176				}
1177
1178				if ($ips === false)
1179				{
1180					// A minor fudge but it does the job :D
1181					$sql_where .= " AND u.user_id = 0";
1182				}
1183				else
1184				{
1185					$ip_forums = array_keys($auth->acl_getf('m_info', true));
1186
1187					$sql = 'SELECT DISTINCT poster_id
1188						FROM ' . POSTS_TABLE . '
1189						WHERE poster_ip ' . ((strpos($ips, '%') !== false) ? 'LIKE' : 'IN') . " ($ips)
1190							AND " . $db->sql_in_set('forum_id', $ip_forums);
1191
1192					/**
1193					* Modify sql query for members search by ip address / hostname
1194					*
1195					* @event core.memberlist_modify_ip_search_sql_query
1196					* @var	string	ipdomain	The host name
1197					* @var	string	ips			IP address list for the given host name
1198					* @var	string	sql			The SQL query for searching members by IP address
1199					* @since 3.1.7-RC1
1200					*/
1201					$vars = array(
1202						'ipdomain',
1203						'ips',
1204						'sql',
1205					);
1206					extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_ip_search_sql_query', compact($vars)));
1207
1208					$result = $db->sql_query($sql);
1209
1210					if ($row = $db->sql_fetchrow($result))
1211					{
1212						$ip_sql = array();
1213						do
1214						{
1215							$ip_sql[] = $row['poster_id'];
1216						}
1217						while ($row = $db->sql_fetchrow($result));
1218
1219						$sql_where .= ' AND ' . $db->sql_in_set('u.user_id', $ip_sql);
1220					}
1221					else
1222					{
1223						// A minor fudge but it does the job :D
1224						$sql_where .= " AND u.user_id = 0";
1225					}
1226					unset($ip_forums);
1227
1228					$db->sql_freeresult($result);
1229				}
1230			}
1231		}
1232
1233		$first_char = $request->variable('first_char', '');
1234
1235		if ($first_char == 'other')
1236		{
1237			for ($i = 97; $i < 123; $i++)
1238			{
1239				$sql_where .= ' AND u.username_clean NOT ' . $db->sql_like_expression(chr($i) . $db->get_any_char());
1240			}
1241		}
1242		else if ($first_char)
1243		{
1244			$sql_where .= ' AND u.username_clean ' . $db->sql_like_expression(substr($first_char, 0, 1) . $db->get_any_char());
1245		}
1246
1247		// Are we looking at a usergroup? If so, fetch additional info
1248		// and further restrict the user info query
1249		if ($mode == 'group')
1250		{
1251			// We JOIN here to save a query for determining membership for hidden groups. ;)
1252			$sql = 'SELECT g.*, ug.user_id, ug.group_leader
1253				FROM ' . GROUPS_TABLE . ' g
1254				LEFT JOIN ' . USER_GROUP_TABLE . ' ug ON (ug.user_pending = 0 AND ug.user_id = ' . $user->data['user_id'] . " AND ug.group_id = $group_id)
1255				WHERE g.group_id = $group_id";
1256			$result = $db->sql_query($sql);
1257			$group_row = $db->sql_fetchrow($result);
1258			$db->sql_freeresult($result);
1259
1260			if (!$group_row)
1261			{
1262				trigger_error('NO_GROUP');
1263			}
1264
1265			switch ($group_row['group_type'])
1266			{
1267				case GROUP_OPEN:
1268					$group_row['l_group_type'] = 'OPEN';
1269				break;
1270
1271				case GROUP_CLOSED:
1272					$group_row['l_group_type'] = 'CLOSED';
1273				break;
1274
1275				case GROUP_HIDDEN:
1276					$group_row['l_group_type'] = 'HIDDEN';
1277
1278					// Check for membership or special permissions
1279					if (!$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel') && $group_row['user_id'] != $user->data['user_id'])
1280					{
1281						trigger_error('NO_GROUP');
1282					}
1283				break;
1284
1285				case GROUP_SPECIAL:
1286					$group_row['l_group_type'] = 'SPECIAL';
1287				break;
1288
1289				case GROUP_FREE:
1290					$group_row['l_group_type'] = 'FREE';
1291				break;
1292			}
1293
1294			$avatar_img = phpbb_get_group_avatar($group_row);
1295
1296			// ... same for group rank
1297			$group_rank_data = array(
1298				'title'		=> null,
1299				'img'		=> null,
1300				'img_src'	=> null,
1301			);
1302			if ($group_row['group_rank'])
1303			{
1304				$group_rank_data = $group_helper->get_rank($group_row);
1305
1306				if ($group_rank_data['img'])
1307				{
1308					$group_rank_data['img'] .= '<br />';
1309				}
1310			}
1311			// include modules for manage groups link display or not
1312			// need to ensure the module is active
1313			$can_manage_group = false;
1314			if ($user->data['is_registered'] && $group_row['group_leader'])
1315			{
1316				if (!class_exists('p_master'))
1317				{
1318					include($phpbb_root_path . 'includes/functions_module.' . $phpEx);
1319				}
1320				$module = new p_master;
1321				$module->list_modules('ucp');
1322
1323				if ($module->is_active('ucp_groups', 'manage'))
1324				{
1325					$can_manage_group = true;
1326				}
1327				unset($module);
1328			}
1329
1330			$template->assign_block_vars('navlinks', array(
1331				'BREADCRUMB_NAME'	=> $group_helper->get_name($group_row['group_name']),
1332				'U_BREADCRUMB'		=> append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=group&amp;g=$group_id"),
1333			));
1334
1335			$template->assign_vars(array(
1336				'GROUP_DESC'	=> generate_text_for_display($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_bitfield'], $group_row['group_desc_options']),
1337				'GROUP_NAME'	=> $group_helper->get_name($group_row['group_name']),
1338				'GROUP_COLOR'	=> $group_row['group_colour'],
1339				'GROUP_TYPE'	=> $user->lang['GROUP_IS_' . $group_row['l_group_type']],
1340				'GROUP_RANK'	=> $group_rank_data['title'],
1341
1342				'AVATAR_IMG'	=> $avatar_img,
1343				'RANK_IMG'		=> $group_rank_data['img'],
1344				'RANK_IMG_SRC'	=> $group_rank_data['img_src'],
1345
1346				'U_PM'			=> ($auth->acl_get('u_sendpm') && $auth->acl_get('u_masspm_group') && $group_row['group_receive_pm'] && $config['allow_privmsg'] && $config['allow_mass_pm']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;mode=compose&amp;g=' . $group_id) : '',
1347				'U_MANAGE'		=> ($can_manage_group) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_groups&amp;mode=manage') : false,)
1348			);
1349
1350			$sql_select = ', ug.group_leader';
1351			$sql_from = ', ' . USER_GROUP_TABLE . ' ug ';
1352			$order_by = 'ug.group_leader DESC, ';
1353
1354			$sql_where .= " AND ug.user_pending = 0 AND u.user_id = ug.user_id AND ug.group_id = $group_id";
1355			$sql_where_data = " AND u.user_id = ug.user_id AND ug.group_id = $group_id";
1356		}
1357
1358		// Sorting and order
1359		if (!isset($sort_key_sql[$sort_key]))
1360		{
1361			$sort_key = $default_key;
1362		}
1363
1364		$order_by .= $sort_key_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC');
1365
1366		// Unfortunately we must do this here for sorting by rank, else the sort order is applied wrongly
1367		if ($sort_key == 'm')
1368		{
1369			$order_by .= ', u.user_posts DESC';
1370		}
1371
1372		/**
1373		* Modify sql query data for members search
1374		*
1375		* @event core.memberlist_modify_sql_query_data
1376		* @var	string	order_by		SQL ORDER BY clause condition
1377		* @var	string	sort_dir		The sorting direction
1378		* @var	string	sort_key		The sorting key
1379		* @var	array	sort_key_sql	Arraty with the sorting conditions data
1380		* @var	string	sql_from		SQL FROM clause condition
1381		* @var	string	sql_select		SQL SELECT fields list
1382		* @var	string	sql_where		SQL WHERE clause condition
1383		* @var	string	sql_where_data	SQL WHERE clause additional conditions data
1384		* @since 3.1.7-RC1
1385		*/
1386		$vars = array(
1387			'order_by',
1388			'sort_dir',
1389			'sort_key',
1390			'sort_key_sql',
1391			'sql_from',
1392			'sql_select',
1393			'sql_where',
1394			'sql_where_data',
1395		);
1396		extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_sql_query_data', compact($vars)));
1397
1398		// Count the users ...
1399		$sql = 'SELECT COUNT(u.user_id) AS total_users
1400			FROM ' . USERS_TABLE . " u$sql_from
1401			WHERE " . $db->sql_in_set('u.user_type', $user_types) . "
1402			$sql_where";
1403		$result = $db->sql_query($sql);
1404		$total_users = (int) $db->sql_fetchfield('total_users');
1405		$db->sql_freeresult($result);
1406
1407		// Build a relevant pagination_url
1408		$params = $sort_params = array();
1409
1410		// We do not use $request->variable() here directly to save some calls (not all variables are set)
1411		$check_params = array(
1412			'g'				=> array('g', 0),
1413			'sk'			=> array('sk', $default_key),
1414			'sd'			=> array('sd', 'a'),
1415			'form'			=> array('form', ''),
1416			'field'			=> array('field', ''),
1417			'select_single'	=> array('select_single', $select_single),
1418			'username'		=> array('username', '', true),
1419			'email'			=> array('email', ''),
1420			'jabber'		=> array('jabber', ''),
1421			'search_group_id'	=> array('search_group_id', 0),
1422			'joined_select'	=> array('joined_select', 'lt'),
1423			'active_select'	=> array('active_select', 'lt'),
1424			'count_select'	=> array('count_select', 'eq'),
1425			'joined'		=> array('joined', ''),
1426			'active'		=> array('active', ''),
1427			'count'			=> ($request->variable('count', '') !== '') ? array('count', 0) : array('count', ''),
1428			'ip'			=> array('ip', ''),
1429			'first_char'	=> array('first_char', ''),
1430		);
1431
1432		$u_first_char_params = array();
1433		foreach ($check_params as $key => $call)
1434		{
1435			if (!isset($_REQUEST[$key]))
1436			{
1437				continue;
1438			}
1439
1440			$param = call_user_func_array(array($request, 'variable'), $call);
1441			// Encode strings, convert everything else to int in order to prevent empty parameters.
1442			$param = urlencode($key) . '=' . ((is_string($param)) ? urlencode($param) : (int) $param);
1443			$params[] = $param;
1444
1445			if ($key != 'first_char')
1446			{
1447				$u_first_char_params[] = $param;
1448			}
1449			if ($key != 'sk' && $key != 'sd')
1450			{
1451				$sort_params[] = $param;
1452			}
1453		}
1454
1455		$u_hide_find_member = append_sid("{$phpbb_root_path}memberlist.$phpEx", "start=$start" . (!empty($params) ? '&amp;' . implode('&amp;', $params) : ''));
1456
1457		if ($mode)
1458		{
1459			$params[] = "mode=$mode";
1460			$u_first_char_params[] = "mode=$mode";
1461		}
1462		$sort_params[] = "mode=$mode";
1463
1464		$u_first_char_params = implode('&amp;', $u_first_char_params);
1465		$u_first_char_params .= ($u_first_char_params) ? '&amp;' : '';
1466
1467		$first_characters = array();
1468		$first_characters[''] = $user->lang['ALL'];
1469		for ($i = 97; $i < 123; $i++)
1470		{
1471			$first_characters[chr($i)] = chr($i - 32);
1472		}
1473		$first_characters['other'] = $user->lang['OTHER'];
1474
1475		$first_char_block_vars = [];
1476
1477		foreach ($first_characters as $char => $desc)
1478		{
1479			$first_char_block_vars[] = [
1480				'DESC'			=> $desc,
1481				'VALUE'			=> $char,
1482				'S_SELECTED'	=> ($first_char == $char) ? true : false,
1483				'U_SORT'		=> append_sid("{$phpbb_root_path}memberlist.$phpEx", $u_first_char_params . 'first_char=' . $char) . '#memberlist',
1484			];
1485		}
1486
1487		/**
1488		 * Modify memberlist sort and pagination parameters
1489		 *
1490		 * @event core.memberlist_modify_sort_pagination_params
1491		 * @var array	sort_params				Array with URL parameters for sorting
1492		 * @var array	params					Array with URL parameters for pagination
1493		 * @var array	first_characters		Array that maps each letter in a-z, 'other' and the empty string to their display representation
1494		 * @var string	u_first_char_params		Concatenated URL parameters for first character search links
1495		 * @var array	first_char_block_vars	Template block variables for each first character
1496		 * @var int		total_users				Total number of users found in this search
1497		 * @since 3.2.6-RC1
1498		 */
1499		$vars = [
1500			'sort_params',
1501			'params',
1502			'first_characters',
1503			'u_first_char_params',
1504			'first_char_block_vars',
1505			'total_users',
1506		];
1507		extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_sort_pagination_params', compact($vars)));
1508
1509		$template->assign_block_vars_array('first_char', $first_char_block_vars);
1510
1511		$pagination_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", implode('&amp;', $params));
1512		$sort_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", implode('&amp;', $sort_params));
1513
1514		unset($search_params, $sort_params);
1515
1516		// Some search user specific data
1517		if (($mode == '' || $mode == 'searchuser') && ($config['load_search'] || $auth->acl_get('a_')))
1518		{
1519			$group_selected = $request->variable('search_group_id', 0);
1520			$s_group_select = '<option value="0"' . ((!$group_selected) ? ' selected="selected"' : '') . '>&nbsp;</option>';
1521			$group_ids = array();
1522
1523			/**
1524			* @todo add this to a separate function (function is responsible for returning the groups the user is able to see based on the users group membership)
1525			*/
1526
1527			if ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel'))
1528			{
1529				$sql = 'SELECT group_id, group_name, group_type
1530					FROM ' . GROUPS_TABLE;
1531
1532				if (!$config['coppa_enable'])
1533				{
1534					$sql .= " WHERE group_name <> 'REGISTERED_COPPA'";
1535				}
1536
1537				$sql .= ' ORDER BY group_name ASC';
1538			}
1539			else
1540			{
1541				$sql = 'SELECT g.group_id, g.group_name, g.group_type
1542					FROM ' . GROUPS_TABLE . ' g
1543					LEFT JOIN ' . USER_GROUP_TABLE . ' ug
1544						ON (
1545							g.group_id = ug.group_id
1546							AND ug.user_id = ' . $user->data['user_id'] . '
1547							AND ug.user_pending = 0
1548						)
1549					WHERE (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . $user->data['user_id'] . ')';
1550
1551				if (!$config['coppa_enable'])
1552				{
1553					$sql .= " AND g.group_name <> 'REGISTERED_COPPA'";
1554				}
1555
1556				$sql .= ' ORDER BY g.group_name ASC';
1557			}
1558			$result = $db->sql_query($sql);
1559
1560			while ($row = $db->sql_fetchrow($result))
1561			{
1562				$group_ids[] = $row['group_id'];
1563				$s_group_select .= '<option value="' . $row['group_id'] . '"' . (($group_selected == $row['group_id']) ? ' selected="selected"' : '') . '>' . $group_helper->get_name($row['group_name']) . '</option>';
1564			}
1565			$db->sql_freeresult($result);
1566
1567			if ($group_selected !== 0 && !in_array($group_selected, $group_ids))
1568			{
1569				trigger_error('NO_GROUP');
1570			}
1571
1572			$template->assign_vars(array(
1573				'USERNAME'	=> $username,
1574				'EMAIL'		=> $email,
1575				'JABBER'	=> $jabber,
1576				'JOINED'	=> implode('-', $joined),
1577				'ACTIVE'	=> implode('-', $active),
1578				'COUNT'		=> $count,
1579				'IP'		=> $ipdomain,
1580
1581				'S_IP_SEARCH_ALLOWED'	=> ($auth->acl_getf_global('m_info')) ? true : false,
1582				'S_EMAIL_SEARCH_ALLOWED'=> ($auth->acl_get('a_user')) ? true : false,
1583				'S_JABBER_ENABLED'		=> $config['jab_enable'],
1584				'S_IN_SEARCH_POPUP'		=> ($form && $field) ? true : false,
1585				'S_SEARCH_USER'			=> ($mode == 'searchuser' || ($mode == '' && $submit)),
1586				'S_FORM_NAME'			=> $form,
1587				'S_FIELD_NAME'			=> $field,
1588				'S_SELECT_SINGLE'		=> $select_single,
1589				'S_COUNT_OPTIONS'		=> $s_find_count,
1590				'S_SORT_OPTIONS'		=> $s_sort_key,
1591				'S_JOINED_TIME_OPTIONS'	=> $s_find_join_time,
1592				'S_ACTIVE_TIME_OPTIONS'	=> $s_find_active_time,
1593				'S_GROUP_SELECT'		=> $s_group_select,
1594				'S_USER_SEARCH_ACTION'	=> append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=searchuser&amp;form=$form&amp;field=$field"))
1595			);
1596		}
1597
1598		$start = $pagination->validate_start($start, $config['topics_per_page'], $total_users);
1599
1600		// Get us some users :D
1601		$sql = "SELECT u.user_id
1602			FROM " . USERS_TABLE . " u
1603				$sql_from
1604			WHERE " . $db->sql_in_set('u.user_type', $user_types) . "
1605				$sql_where
1606			ORDER BY $order_by";
1607		$result = $db->sql_query_limit($sql, $config['topics_per_page'], $start);
1608
1609		$user_list = array();
1610		while ($row = $db->sql_fetchrow($result))
1611		{
1612			$user_list[] = (int) $row['user_id'];
1613		}
1614		$db->sql_freeresult($result);
1615
1616		// Load custom profile fields
1617		if ($config['load_cpf_memberlist'])
1618		{
1619			/* @var $cp \phpbb\profilefields\manager */
1620			$cp = $phpbb_container->get('profilefields.manager');
1621
1622			$cp_row = $cp->generate_profile_fields_template_headlines('field_show_on_ml');
1623			foreach ($cp_row as $profile_field)
1624			{
1625				$template->assign_block_vars('custom_fields', $profile_field);
1626			}
1627		}
1628
1629		$leaders_set = false;
1630		// So, did we get any users?
1631		if (count($user_list))
1632		{
1633			// Session time?! Session time...
1634			$sql = 'SELECT session_user_id, MAX(session_time) AS session_time
1635				FROM ' . SESSIONS_TABLE . '
1636				WHERE session_time >= ' . (time() - $config['session_length']) . '
1637					AND ' . $db->sql_in_set('session_user_id', $user_list) . '
1638				GROUP BY session_user_id';
1639			$result = $db->sql_query($sql);
1640
1641			$session_times = array();
1642			while ($row = $db->sql_fetchrow($result))
1643			{
1644				$session_times[$row['session_user_id']] = $row['session_time'];
1645			}
1646			$db->sql_freeresult($result);
1647
1648			// Do the SQL thang
1649			if ($mode == 'group')
1650			{
1651				$sql_from_ary = explode(',', $sql_from);
1652				$extra_tables = [];
1653				foreach ($sql_from_ary as $entry)
1654				{
1655					$table_data = explode(' ', trim($entry));
1656
1657					if (empty($table_data[0]) || empty($table_data[1]))
1658					{
1659						continue;
1660					}
1661
1662					$extra_tables[$table_data[0]] = $table_data[1];
1663				}
1664
1665				$sql_array = array(
1666					'SELECT'	=> 'u.*' . $sql_select,
1667					'FROM'		=> array_merge([USERS_TABLE => 'u'], $extra_tables),
1668					'WHERE'		=> $db->sql_in_set('u.user_id', $user_list) . $sql_where_data . '',
1669				);
1670			}
1671			else
1672			{
1673				$sql_array = array(
1674					'SELECT'	=> 'u.*',
1675					'FROM'		=> array(
1676						USERS_TABLE		=> 'u'
1677					),
1678					'WHERE'		=> $db->sql_in_set('u.user_id', $user_list),
1679				);
1680			}
1681
1682			/**
1683			 * Modify user data SQL before member row is created
1684			 *
1685			 * @event core.memberlist_modify_memberrow_sql
1686			 * @var string	mode				Memberlist mode
1687			 * @var string	sql_select			Additional select statement
1688			 * @var string	sql_from			Additional from statement
1689			 * @var array	sql_array			Array containing the main query
1690			 * @var array	user_list			Array containing list of users
1691			 * @since 3.2.6-RC1
1692			 */
1693			$vars = array(
1694				'mode',
1695				'sql_select',
1696				'sql_from',
1697				'sql_array',
1698				'user_list',
1699			);
1700			extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_memberrow_sql', compact($vars)));
1701
1702			$sql = $db->sql_build_query('SELECT', $sql_array);
1703			$result = $db->sql_query($sql);
1704
1705			$id_cache = array();
1706			while ($row = $db->sql_fetchrow($result))
1707			{
1708				$row['session_time'] = (!empty($session_times[$row['user_id']])) ? $session_times[$row['user_id']] : 0;
1709				$row['last_visit'] = (!empty($row['session_time'])) ? $row['session_time'] : $row['user_lastvisit'];
1710
1711				$id_cache[$row['user_id']] = $row;
1712			}
1713
1714			$db->sql_freeresult($result);
1715
1716			// Load custom profile fields if required
1717			if ($config['load_cpf_memberlist'])
1718			{
1719				// Grab all profile fields from users in id cache for later use - similar to the poster cache
1720				$profile_fields_cache = $cp->grab_profile_fields_data($user_list);
1721
1722				// Filter the fields we don't want to show
1723				foreach ($profile_fields_cache as $user_id => $user_profile_fields)
1724				{
1725					foreach ($user_profile_fields as $field_ident => $profile_field)
1726					{
1727						if (!$profile_field['data']['field_show_on_ml'])
1728						{
1729							unset($profile_fields_cache[$user_id][$field_ident]);
1730						}
1731					}
1732				}
1733			}
1734
1735			// If we sort by last active date we need to adjust the id cache due to user_lastvisit not being the last active date...
1736			if ($sort_key == 'l')
1737			{
1738//				uasort($id_cache, create_function('$first, $second', "return (\$first['last_visit'] == \$second['last_visit']) ? 0 : ((\$first['last_visit'] < \$second['last_visit']) ? $lesser_than : ($lesser_than * -1));"));
1739				usort($user_list,  'phpbb_sort_last_active');
1740			}
1741
1742			// do we need to display contact fields as such
1743			$use_contact_fields = true;
1744
1745			/**
1746			 * Modify list of users before member row is created
1747			 *
1748			 * @event core.memberlist_memberrow_before
1749			 * @var array	user_list			Array containing list of users
1750			 * @var bool	use_contact_fields	Should we display contact fields as such?
1751			 * @since 3.1.7-RC1
1752			 */
1753			$vars = array('user_list', 'use_contact_fields');
1754			extract($phpbb_dispatcher->trigger_event('core.memberlist_memberrow_before', compact($vars)));
1755
1756			for ($i = 0, $end = count($user_list); $i < $end; ++$i)
1757			{
1758				$user_id = $user_list[$i];
1759				$row = $id_cache[$user_id];
1760				$is_leader = (isset($row['group_leader']) && $row['group_leader']) ? true : false;
1761				$leaders_set = ($leaders_set || $is_leader);
1762
1763				$cp_row = array();
1764				if ($config['load_cpf_memberlist'])
1765				{
1766					$cp_row = (isset($profile_fields_cache[$user_id])) ? $cp->generate_profile_fields_template_data($profile_fields_cache[$user_id], $use_contact_fields) : array();
1767				}
1768
1769				$memberrow = array_merge(phpbb_show_profile($row, false, false, false), array(
1770					'ROW_NUMBER'		=> $i + ($start + 1),
1771
1772					'S_CUSTOM_PROFILE'	=> (isset($cp_row['row']) && count($cp_row['row'])) ? true : false,
1773					'S_GROUP_LEADER'	=> $is_leader,
1774					'S_INACTIVE'		=> $row['user_type'] == USER_INACTIVE,
1775
1776					'U_VIEW_PROFILE'	=> get_username_string('profile', $user_id, $row['username']),
1777				));
1778
1779				if (isset($cp_row['row']) && count($cp_row['row']))
1780				{
1781					$memberrow = array_merge($memberrow, $cp_row['row']);
1782				}
1783
1784				$template->assign_block_vars('memberrow', $memberrow);
1785
1786				if (isset($cp_row['blockrow']) && count($cp_row['blockrow']))
1787				{
1788					foreach ($cp_row['blockrow'] as $field_data)
1789					{
1790						$template->assign_block_vars('memberrow.custom_fields', $field_data);
1791					}
1792				}
1793
1794				unset($id_cache[$user_id]);
1795			}
1796		}
1797
1798		$pagination->generate_template_pagination($pagination_url, 'pagination', 'start', $total_users, $config['topics_per_page'], $start);
1799
1800		// Generate page
1801		$template_vars = array(
1802			'TOTAL_USERS'	=> $user->lang('LIST_USERS', (int) $total_users),
1803
1804			'PROFILE_IMG'	=> $user->img('icon_user_profile', $user->lang['PROFILE']),
1805			'PM_IMG'		=> $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE']),
1806			'EMAIL_IMG'		=> $user->img('icon_contact_email', $user->lang['EMAIL']),
1807			'JABBER_IMG'	=> $user->img('icon_contact_jabber', $user->lang['JABBER']),
1808			'SEARCH_IMG'	=> $user->img('icon_user_search', $user->lang['SEARCH']),
1809
1810			'U_FIND_MEMBER'			=> ($config['load_search'] || $auth->acl_get('a_')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser' . (($start) ? "&amp;start=$start" : '') . (!empty($params) ? '&amp;' . implode('&amp;', $params) : '')) : '',
1811			'U_HIDE_FIND_MEMBER'	=> ($mode == 'searchuser' || ($mode == '' && $submit)) ? $u_hide_find_member : '',
1812			'U_LIVE_SEARCH'			=> ($config['allow_live_searches']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=livesearch') : false,
1813			'U_SORT_USERNAME'		=> $sort_url . '&amp;sk=a&amp;sd=' . (($sort_key == 'a' && $sort_dir == 'a') ? 'd' : 'a'),
1814			'U_SORT_JOINED'			=> $sort_url . '&amp;sk=c&amp;sd=' . (($sort_key == 'c' && $sort_dir == 'd') ? 'a' : 'd'),
1815			'U_SORT_POSTS'			=> $sort_url . '&amp;sk=d&amp;sd=' . (($sort_key == 'd' && $sort_dir == 'd') ? 'a' : 'd'),
1816			'U_SORT_EMAIL'			=> $sort_url . '&amp;sk=e&amp;sd=' . (($sort_key == 'e' && $sort_dir == 'd') ? 'a' : 'd'),
1817			'U_SORT_ACTIVE'			=> ($auth->acl_get('u_viewonline')) ? $sort_url . '&amp;sk=l&amp;sd=' . (($sort_key == 'l' && $sort_dir == 'd') ? 'a' : 'd') : '',
1818			'U_SORT_RANK'			=> $sort_url . '&amp;sk=m&amp;sd=' . (($sort_key == 'm' && $sort_dir == 'd') ? 'a' : 'd'),
1819			'U_LIST_CHAR'			=> $sort_url . '&amp;sk=a&amp;sd=' . (($sort_key == 'l' && $sort_dir == 'd') ? 'a' : 'd'),
1820
1821			'S_SHOW_GROUP'		=> ($mode == 'group') ? true : false,
1822			'S_VIEWONLINE'		=> $auth->acl_get('u_viewonline'),
1823			'S_LEADERS_SET'		=> $leaders_set,
1824			'S_MODE_SELECT'		=> $s_sort_key,
1825			'S_ORDER_SELECT'	=> $s_sort_dir,
1826			'S_MODE_ACTION'		=> $pagination_url,
1827		);
1828
1829		/**
1830		 * Modify memberlist page template vars
1831		 *
1832		 * @event core.memberlist_modify_template_vars
1833		 * @var array	params				Array containing URL parameters
1834		 * @var string	sort_url			Sorting URL base
1835		 * @var array	template_vars		Array containing template vars
1836		 * @since 3.2.2-RC1
1837		 */
1838		$vars = array('params', 'sort_url', 'template_vars');
1839		extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_template_vars', compact($vars)));
1840
1841		$template->assign_vars($template_vars);
1842}
1843
1844// Output the page
1845page_header($page_title);
1846
1847$template->set_filenames(array(
1848	'body' => $template_html)
1849);
1850make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
1851
1852page_footer();
1853