diff forum/Sources/Subs-Membergroups.php @ 76:e3e11437ecea website

Add forum code
author Chris Cannam
date Sun, 07 Jul 2013 11:25:48 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/forum/Sources/Subs-Membergroups.php	Sun Jul 07 11:25:48 2013 +0200
@@ -0,0 +1,757 @@
+<?php
+
+/**
+ * Simple Machines Forum (SMF)
+ *
+ * @package SMF
+ * @author Simple Machines http://www.simplemachines.org
+ * @copyright 2011 Simple Machines
+ * @license http://www.simplemachines.org/about/smf/license.php BSD
+ *
+ * @version 2.0
+ */
+
+if (!defined('SMF'))
+	die('Hacking attempt...');
+
+/*	This file contains functions regarding manipulation of and information
+	about membergroups.
+
+	bool deleteMembergroups(array groups)
+		- delete one of more membergroups.
+		- requires the manage_membergroups permission.
+		- returns true on success or false on failure.
+		- has protection against deletion of protected membergroups.
+		- deletes the permissions linked to the membergroup.
+		- takes members out of the deleted membergroups.
+
+	bool removeMembersFromGroups(array members, array groups = null)
+		- remove one or more members from one or more membergroups.
+		- requires the manage_membergroups permission.
+		- returns true on success or false on failure.
+		- if groups is null, the specified members are stripped from all their
+		  membergroups.
+		- function includes a protection against removing from implicit groups.
+		- non-admins are not able to remove members from the admin group.
+
+	bool addMembersToGroup(array members, group, type = 'auto')
+		- add one or more members to a specified group.
+		- requires the manage_membergroups permission.
+		- returns true on success or false on failure.
+		- the type parameter specifies whether the group is added as primary or
+		  as additional group.
+		- function has protection against adding members to implicit groups.
+		- non-admins are not able to add members to the admin group.
+
+	bool listMembergroupMembers_Href(&array members, int membergroup, int limit = null)
+		- get a list of all members that are part of a membergroup.
+		- if limit is set to null, all members are returned.
+		- returns a list of href-links in $members.
+		- returns true if there are more than limit members.
+
+*/
+
+// Delete one or more membergroups.
+function deleteMembergroups($groups)
+{
+	global $sourcedir, $smcFunc, $modSettings;
+
+	// Make sure it's an array.
+	if (!is_array($groups))
+		$groups = array((int) $groups);
+	else
+	{
+		$groups = array_unique($groups);
+
+		// Make sure all groups are integer.
+		foreach ($groups as $key => $value)
+			$groups[$key] = (int) $value;
+	}
+
+	// Some groups are protected (guests, administrators, moderators, newbies).
+	$protected_groups = array(-1, 0, 1, 3, 4);
+
+	// There maybe some others as well.
+	if (!allowedTo('admin_forum'))
+	{
+		$request = $smcFunc['db_query']('', '
+			SELECT id_group
+			FROM {db_prefix}membergroups
+			WHERE group_type = {int:is_protected}',
+			array(
+				'is_protected' => 1,
+			)
+		);
+		while ($row = $smcFunc['db_fetch_assoc']($request))
+			$protected_groups[] = $row['id_group'];
+		$smcFunc['db_free_result']($request);
+	}
+
+	// Make sure they don't delete protected groups!
+	$groups = array_diff($groups, array_unique($protected_groups));
+	if (empty($groups))
+		return false;
+
+	// Log the deletion.
+	$request = $smcFunc['db_query']('', '
+		SELECT group_name
+		FROM {db_prefix}membergroups
+		WHERE id_group IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+		)
+	);
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		logAction('delete_group', array('group' => $row['group_name']), 'admin');
+	$smcFunc['db_free_result']($request);
+
+	// Remove the membergroups themselves.
+	$smcFunc['db_query']('', '
+		DELETE FROM {db_prefix}membergroups
+		WHERE id_group IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+		)
+	);
+
+	// Remove the permissions of the membergroups.
+	$smcFunc['db_query']('', '
+		DELETE FROM {db_prefix}permissions
+		WHERE id_group IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+		)
+	);
+	$smcFunc['db_query']('', '
+		DELETE FROM {db_prefix}board_permissions
+		WHERE id_group IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+		)
+	);
+	$smcFunc['db_query']('', '
+		DELETE FROM {db_prefix}group_moderators
+		WHERE id_group IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+		)
+	);
+
+	// Delete any outstanding requests.
+	$smcFunc['db_query']('', '
+		DELETE FROM {db_prefix}log_group_requests
+		WHERE id_group IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+		)
+	);
+
+	// Update the primary groups of members.
+	$smcFunc['db_query']('', '
+		UPDATE {db_prefix}members
+		SET id_group = {int:regular_group}
+		WHERE id_group IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+			'regular_group' => 0,
+		)
+	);
+
+	// Update any inherited groups (Lose inheritance).
+	$smcFunc['db_query']('', '
+		UPDATE {db_prefix}membergroups
+		SET id_parent = {int:uninherited}
+		WHERE id_parent IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+			'uninherited' => -2,
+		)
+	);
+
+	// Update the additional groups of members.
+	$request = $smcFunc['db_query']('', '
+		SELECT id_member, additional_groups
+		FROM {db_prefix}members
+		WHERE FIND_IN_SET({raw:additional_groups_explode}, additional_groups) != 0',
+		array(
+			'additional_groups_explode' => implode(', additional_groups) != 0 OR FIND_IN_SET(', $groups),
+		)
+	);
+	$updates = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		$updates[$row['additional_groups']][] = $row['id_member'];
+	$smcFunc['db_free_result']($request);
+
+	foreach ($updates as $additional_groups => $memberArray)
+		updateMemberData($memberArray, array('additional_groups' => implode(',', array_diff(explode(',', $additional_groups), $groups))));
+
+	// No boards can provide access to these membergroups anymore.
+	$request = $smcFunc['db_query']('', '
+		SELECT id_board, member_groups
+		FROM {db_prefix}boards
+		WHERE FIND_IN_SET({raw:member_groups_explode}, member_groups) != 0',
+		array(
+			'member_groups_explode' => implode(', member_groups) != 0 OR FIND_IN_SET(', $groups),
+		)
+	);
+	$updates = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		$updates[$row['member_groups']][] = $row['id_board'];
+	$smcFunc['db_free_result']($request);
+
+	foreach ($updates as $member_groups => $boardArray)
+		$smcFunc['db_query']('', '
+			UPDATE {db_prefix}boards
+			SET member_groups = {string:member_groups}
+			WHERE id_board IN ({array_int:board_lists})',
+			array(
+				'board_lists' => $boardArray,
+				'member_groups' => implode(',', array_diff(explode(',', $member_groups), $groups)),
+			)
+		);
+
+	// Recalculate the post groups, as they likely changed.
+	updateStats('postgroups');
+
+	// Make a note of the fact that the cache may be wrong.
+	$settings_update = array('settings_updated' => time());
+	// Have we deleted the spider group?
+	if (isset($modSettings['spider_group']) && in_array($modSettings['spider_group'], $groups))
+		$settings_update['spider_group'] = 0;
+
+	updateSettings($settings_update);
+
+	// It was a success.
+	return true;
+}
+
+// Remove one or more members from one or more membergroups.
+function removeMembersFromGroups($members, $groups = null, $permissionCheckDone = false)
+{
+	global $smcFunc, $user_info, $modSettings;
+
+	// You're getting nowhere without this permission, unless of course you are the group's moderator.
+	if (!$permissionCheckDone)
+		isAllowedTo('manage_membergroups');
+
+	// Assume something will happen.
+	updateSettings(array('settings_updated' => time()));
+
+	// Cleaning the input.
+	if (!is_array($members))
+		$members = array((int) $members);
+	else
+	{
+		$members = array_unique($members);
+
+		// Cast the members to integer.
+		foreach ($members as $key => $value)
+			$members[$key] = (int) $value;
+	}
+
+	// Before we get started, let's check we won't leave the admin group empty!
+	if ($groups === null || $groups == 1 || (is_array($groups) && in_array(1, $groups)))
+	{
+		$admins = array();
+		listMembergroupMembers_Href($admins, 1);
+
+		// Remove any admins if there are too many.
+		$non_changing_admins = array_diff(array_keys($admins), $members);
+
+		if (empty($non_changing_admins))
+			$members = array_diff($members, array_keys($admins));
+	}
+
+	// Just in case.
+	if (empty($members))
+		return false;
+	elseif ($groups === null)
+	{
+		// Wanna remove all groups from these members? That's easy.
+		$smcFunc['db_query']('', '
+			UPDATE {db_prefix}members
+			SET
+				id_group = {int:regular_member},
+				additional_groups = {string:blank_string}
+			WHERE id_member IN ({array_int:member_list})' . (allowedTo('admin_forum') ? '' : '
+				AND id_group != {int:admin_group}
+				AND FIND_IN_SET({int:admin_group}, additional_groups) = 0'),
+			array(
+				'member_list' => $members,
+				'regular_member' => 0,
+				'admin_group' => 1,
+				'blank_string' => '',
+			)
+		);
+
+		updateStats('postgroups', $members);
+
+		// Log what just happened.
+		foreach ($members as $member)
+			logAction('removed_all_groups', array('member' => $member), 'admin');
+
+		return true;
+	}
+	elseif (!is_array($groups))
+		$groups = array((int) $groups);
+	else
+	{
+		$groups = array_unique($groups);
+
+		// Make sure all groups are integer.
+		foreach ($groups as $key => $value)
+			$groups[$key] = (int) $value;
+	}
+
+	// Fetch a list of groups members cannot be assigned to explicitely, and the group names of the ones we want.
+	$implicitGroups = array(-1, 0, 3);
+	$request = $smcFunc['db_query']('', '
+		SELECT id_group, group_name, min_posts
+		FROM {db_prefix}membergroups
+		WHERE id_group IN ({array_int:group_list})',
+		array(
+			'group_list' => $groups,
+		)
+	);
+	$group_names = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+	{
+		if ($row['min_posts'] != -1)
+			$implicitGroups[] = $row['id_group'];
+		else
+			$group_names[$row['id_group']] = $row['group_name'];
+	}
+	$smcFunc['db_free_result']($request);
+
+	// Now get rid of those groups.
+	$groups = array_diff($groups, $implicitGroups);
+
+	// Don't forget the protected groups.
+	if (!allowedTo('admin_forum'))
+	{
+		$request = $smcFunc['db_query']('', '
+			SELECT id_group
+			FROM {db_prefix}membergroups
+			WHERE group_type = {int:is_protected}',
+			array(
+				'is_protected' => 1,
+			)
+		);
+		$protected_groups = array(1);
+		while ($row = $smcFunc['db_fetch_assoc']($request))
+			$protected_groups[] = $row['id_group'];
+		$smcFunc['db_free_result']($request);
+
+		// If you're not an admin yourself, you can't touch protected groups!
+		$groups = array_diff($groups, array_unique($protected_groups));
+	}
+
+	// Only continue if there are still groups and members left.
+	if (empty($groups) || empty($members))
+		return false;
+
+	// First, reset those who have this as their primary group - this is the easy one.
+	$log_inserts = array();
+	$request = $smcFunc['db_query']('', '
+		SELECT id_member, id_group
+		FROM {db_prefix}members AS members
+		WHERE id_group IN ({array_int:group_list})
+			AND id_member IN ({array_int:member_list})',
+		array(
+			'group_list' => $groups,
+			'member_list' => $members,
+		)
+	);
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		$log_inserts[] = array(
+			time(), 3, $user_info['id'], $user_info['ip'], 'removed_from_group',
+			0, 0, 0, serialize(array('group' => $group_names[$row['id_group']], 'member' => $row['id_member'])),
+		);
+	$smcFunc['db_free_result']($request);
+
+	$smcFunc['db_query']('', '
+		UPDATE {db_prefix}members
+		SET id_group = {int:regular_member}
+		WHERE id_group IN ({array_int:group_list})
+			AND id_member IN ({array_int:member_list})',
+		array(
+			'group_list' => $groups,
+			'member_list' => $members,
+			'regular_member' => 0,
+		)
+	);
+
+	// Those who have it as part of their additional group must be updated the long way... sadly.
+	$request = $smcFunc['db_query']('', '
+		SELECT id_member, additional_groups
+		FROM {db_prefix}members
+		WHERE (FIND_IN_SET({raw:additional_groups_implode}, additional_groups) != 0)
+			AND id_member IN ({array_int:member_list})
+		LIMIT ' . count($members),
+		array(
+			'member_list' => $members,
+			'additional_groups_implode' => implode(', additional_groups) != 0 OR FIND_IN_SET(', $groups),
+		)
+	);
+	$updates = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+	{
+		// What log entries must we make for this one, eh?
+		foreach (explode(',', $row['additional_groups']) as $group)
+			if (in_array($group, $groups))
+				$log_inserts[] = array(
+					time(), 3, $user_info['id'], $user_info['ip'], 'removed_from_group',
+					0, 0, 0, serialize(array('group' => $group_names[$group], 'member' => $row['id_member'])),
+				);
+
+		$updates[$row['additional_groups']][] = $row['id_member'];
+	}
+	$smcFunc['db_free_result']($request);
+
+	foreach ($updates as $additional_groups => $memberArray)
+		$smcFunc['db_query']('', '
+			UPDATE {db_prefix}members
+			SET additional_groups = {string:additional_groups}
+			WHERE id_member IN ({array_int:member_list})',
+			array(
+				'member_list' => $memberArray,
+				'additional_groups' => implode(',', array_diff(explode(',', $additional_groups), $groups)),
+			)
+		);
+
+	// Their post groups may have changed now...
+	updateStats('postgroups', $members);
+
+	// Do the log.
+	if (!empty($log_inserts) && !empty($modSettings['modlog_enabled']))
+		$smcFunc['db_insert']('',
+			'{db_prefix}log_actions',
+			array(
+				'log_time' => 'int', 'id_log' => 'int', 'id_member' => 'int', 'ip' => 'string-16', 'action' => 'string',
+				'id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'extra' => 'string-65534',
+			),
+			$log_inserts,
+			array('id_action')
+		);
+
+	// Mission successful.
+	return true;
+}
+
+// Add one or more members to a membergroup.
+/* Supported types:
+	- only_primary      - Assigns a membergroup as primary membergroup, but only
+						  if a member has not yet a primary membergroup assigned,
+						  unless the member is already part of the membergroup.
+	- only_additional   - Assigns a membergroup to the additional membergroups,
+						  unless the member is already part of the membergroup.
+	- force_primary     - Assigns a membergroup as primary membergroup no matter
+						  what the previous primary membergroup was.
+	- auto              - Assigns a membergroup to the primary group if it's still
+						  available. If not, assign it to the additional group. */
+function addMembersToGroup($members, $group, $type = 'auto', $permissionCheckDone = false)
+{
+	global $smcFunc, $user_info, $modSettings;
+
+	// Show your licence, but only if it hasn't been done yet.
+	if (!$permissionCheckDone)
+		isAllowedTo('manage_membergroups');
+
+	// Make sure we don't keep old stuff cached.
+	updateSettings(array('settings_updated' => time()));
+
+	if (!is_array($members))
+		$members = array((int) $members);
+	else
+	{
+		$members = array_unique($members);
+
+		// Make sure all members are integer.
+		foreach ($members as $key => $value)
+			$members[$key] = (int) $value;
+	}
+	$group = (int) $group;
+
+	// Some groups just don't like explicitly having members.
+	$implicitGroups = array(-1, 0, 3);
+	$request = $smcFunc['db_query']('', '
+		SELECT id_group, group_name, min_posts
+		FROM {db_prefix}membergroups
+		WHERE id_group = {int:current_group}',
+		array(
+			'current_group' => $group,
+		)
+	);
+	$group_names = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+	{
+		if ($row['min_posts'] != -1)
+			$implicitGroups[] = $row['id_group'];
+		else
+			$group_names[$row['id_group']] = $row['group_name'];
+	}
+	$smcFunc['db_free_result']($request);
+
+	// Sorry, you can't join an implicit group.
+	if (in_array($group, $implicitGroups) || empty($members))
+		return false;
+
+	// Only admins can add admins...
+	if (!allowedTo('admin_forum') && $group == 1)
+		return false;
+	// ... and assign protected groups!
+	elseif (!allowedTo('admin_forum'))
+	{
+		$request = $smcFunc['db_query']('', '
+			SELECT group_type
+			FROM {db_prefix}membergroups
+			WHERE id_group = {int:current_group}
+			LIMIT {int:limit}',
+			array(
+				'current_group' => $group,
+				'limit' => 1,
+			)
+		);
+		list ($is_protected) = $smcFunc['db_fetch_row']($request);
+		$smcFunc['db_free_result']($request);
+
+		// Is it protected?
+		if ($is_protected == 1)
+			return false;
+	}
+
+	// Do the actual updates.
+	if ($type == 'only_additional')
+		$smcFunc['db_query']('', '
+			UPDATE {db_prefix}members
+			SET additional_groups = CASE WHEN additional_groups = {string:blank_string} THEN {string:id_group_string} ELSE CONCAT(additional_groups, {string:id_group_string_extend}) END
+			WHERE id_member IN ({array_int:member_list})
+				AND id_group != {int:id_group}
+				AND FIND_IN_SET({int:id_group}, additional_groups) = 0',
+			array(
+				'member_list' => $members,
+				'id_group' => $group,
+				'id_group_string' => (string) $group,
+				'id_group_string_extend' => ',' . $group,
+				'blank_string' => '',
+			)
+		);
+	elseif ($type == 'only_primary' || $type == 'force_primary')
+		$smcFunc['db_query']('', '
+			UPDATE {db_prefix}members
+			SET id_group = {int:id_group}
+			WHERE id_member IN ({array_int:member_list})' . ($type == 'force_primary' ? '' : '
+				AND id_group = {int:regular_group}
+				AND FIND_IN_SET({int:id_group}, additional_groups) = 0'),
+			array(
+				'member_list' => $members,
+				'id_group' => $group,
+				'regular_group' => 0,
+			)
+		);
+	elseif ($type == 'auto')
+		$smcFunc['db_query']('', '
+			UPDATE {db_prefix}members
+			SET
+				id_group = CASE WHEN id_group = {int:regular_group} THEN {int:id_group} ELSE id_group END,
+				additional_groups = CASE WHEN id_group = {int:id_group} THEN additional_groups
+					WHEN additional_groups = {string:blank_string} THEN {string:id_group_string}
+					ELSE CONCAT(additional_groups, {string:id_group_string_extend}) END
+			WHERE id_member IN ({array_int:member_list})
+				AND id_group != {int:id_group}
+				AND FIND_IN_SET({int:id_group}, additional_groups) = 0',
+			array(
+				'member_list' => $members,
+				'regular_group' => 0,
+				'id_group' => $group,
+				'blank_string' => '',
+				'id_group_string' => (string) $group,
+				'id_group_string_extend' => ',' . $group,
+			)
+		);
+	// Ack!!?  What happened?
+	else
+		trigger_error('addMembersToGroup(): Unknown type \'' . $type . '\'', E_USER_WARNING);
+
+	// Update their postgroup statistics.
+	updateStats('postgroups', $members);
+
+	// Log the data.
+	$log_inserts = array();
+	foreach ($members as $member)
+		$log_inserts[] = array(
+			time(), 3, $user_info['id'], $user_info['ip'], 'added_to_group',
+			0, 0, 0, serialize(array('group' => $group_names[$group], 'member' => $member)),
+		);
+
+	if (!empty($log_inserts) && !empty($modSettings['modlog_enabled']))
+		$smcFunc['db_insert']('',
+			'{db_prefix}log_actions',
+			array(
+				'log_time' => 'int', 'id_log' => 'int', 'id_member' => 'int', 'ip' => 'string-16', 'action' => 'string',
+				'id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'extra' => 'string-65534',
+			),
+			$log_inserts,
+			array('id_action')
+		);
+
+	return true;
+}
+
+function listMembergroupMembers_Href(&$members, $membergroup, $limit = null)
+{
+	global $scripturl, $txt, $smcFunc;
+
+	$request = $smcFunc['db_query']('', '
+		SELECT id_member, real_name
+		FROM {db_prefix}members
+		WHERE id_group = {int:id_group} OR FIND_IN_SET({int:id_group}, additional_groups) != 0' . ($limit === null ? '' : '
+		LIMIT ' . ($limit + 1)),
+		array(
+			'id_group' => $membergroup,
+		)
+	);
+	$members = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		$members[$row['id_member']] = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>';
+	$smcFunc['db_free_result']($request);
+
+	// If there are more than $limit members, add a 'more' link.
+	if ($limit !== null && count($members) > $limit)
+	{
+		array_pop($members);
+		return true;
+	}
+	else
+		return false;
+}
+
+// Retrieve a list of (visible) membergroups used by the cache.
+function cache_getMembergroupList()
+{
+	global $scripturl, $smcFunc;
+
+	$request = $smcFunc['db_query']('', '
+		SELECT id_group, group_name, online_color
+		FROM {db_prefix}membergroups
+		WHERE min_posts = {int:min_posts}
+			AND hidden = {int:not_hidden}
+			AND id_group != {int:mod_group}
+			AND online_color != {string:blank_string}
+		ORDER BY group_name',
+		array(
+			'min_posts' => -1,
+			'not_hidden' => 0,
+			'mod_group' => 3,
+			'blank_string' => '',
+		)
+	);
+	$groupCache = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		$groupCache[] = '<a href="' . $scripturl . '?action=groups;sa=members;group=' . $row['id_group'] . '" ' . ($row['online_color'] ? 'style="color: ' . $row['online_color'] . '"' : '') . '>' . $row['group_name'] . '</a>';
+	$smcFunc['db_free_result']($request);
+
+	return array(
+		'data' => $groupCache,
+		'expires' => time() + 3600,
+		'refresh_eval' => 'return $GLOBALS[\'modSettings\'][\'settings_updated\'] > ' . time() . ';',
+	);
+}
+
+function list_getMembergroups($start, $items_per_page, $sort, $membergroup_type)
+{
+	global $txt, $scripturl, $context, $settings, $smcFunc;
+
+	$groups = array();
+
+	// Get the basic group data.
+	$request = $smcFunc['db_query']('substring_membergroups', '
+		SELECT id_group, group_name, min_posts, online_color, stars, 0 AS num_members
+		FROM {db_prefix}membergroups
+		WHERE min_posts ' . ($membergroup_type === 'post_count' ? '!=' : '=') . ' -1' . (allowedTo('admin_forum') ? '' : '
+			AND group_type != {int:is_protected}') . '
+		ORDER BY {raw:sort}',
+		array(
+			'is_protected' => 1,
+			'sort' => $sort,
+		)
+	);
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+		$groups[$row['id_group']] = array(
+			'id_group' => $row['id_group'],
+			'group_name' => $row['group_name'],
+			'min_posts' => $row['min_posts'],
+			'online_color' => $row['online_color'],
+			'stars' => $row['stars'],
+			'num_members' => $row['num_members'],
+		);
+	$smcFunc['db_free_result']($request);
+
+	// If we found any membergroups, get the amount of members in them.
+	if (!empty($groups))
+	{
+		if ($membergroup_type === 'post_count')
+		{
+			$query = $smcFunc['db_query']('', '
+				SELECT id_post_group AS id_group, COUNT(*) AS num_members
+				FROM {db_prefix}members
+				WHERE id_post_group IN ({array_int:group_list})
+				GROUP BY id_post_group',
+				array(
+					'group_list' => array_keys($groups),
+				)
+			);
+			while ($row = $smcFunc['db_fetch_assoc']($query))
+				$groups[$row['id_group']]['num_members'] += $row['num_members'];
+			$smcFunc['db_free_result']($query);
+		}
+
+		else
+		{
+			$query = $smcFunc['db_query']('', '
+				SELECT id_group, COUNT(*) AS num_members
+				FROM {db_prefix}members
+				WHERE id_group IN ({array_int:group_list})
+				GROUP BY id_group',
+				array(
+					'group_list' => array_keys($groups),
+				)
+			);
+			while ($row = $smcFunc['db_fetch_assoc']($query))
+				$groups[$row['id_group']]['num_members'] += $row['num_members'];
+			$smcFunc['db_free_result']($query);
+
+			$query = $smcFunc['db_query']('', '
+				SELECT mg.id_group, COUNT(*) AS num_members
+				FROM {db_prefix}membergroups AS mg
+					INNER JOIN {db_prefix}members AS mem ON (mem.additional_groups != {string:blank_string}
+						AND mem.id_group != mg.id_group
+						AND FIND_IN_SET(mg.id_group, mem.additional_groups) != 0)
+				WHERE mg.id_group IN ({array_int:group_list})
+				GROUP BY mg.id_group',
+				array(
+					'group_list' => array_keys($groups),
+					'blank_string' => '',
+				)
+			);
+			while ($row = $smcFunc['db_fetch_assoc']($query))
+				$groups[$row['id_group']]['num_members'] += $row['num_members'];
+			$smcFunc['db_free_result']($query);
+		}
+	}
+
+	// Apply manual sorting if the 'number of members' column is selected.
+	if (substr($sort, 0, 1) == '1' || strpos($sort, ', 1') !== false)
+	{
+		$sort_ascending = strpos($sort, 'DESC') === false;
+
+		foreach ($groups as $group)
+			$sort_array[] = $group['id_group'] != 3 ? (int) $group['num_members'] : -1;
+
+		array_multisort($sort_array, $sort_ascending ? SORT_ASC : SORT_DESC, SORT_REGULAR, $groups);
+	}
+
+	return $groups;
+}
+
+?>
\ No newline at end of file