Issues (1686)

sources/subs/MembersOnline.subs.php (2 issues)

1
<?php
2
3
/**
4
 * Function to support online user functions
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * This file contains code covered by:
11
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
12
 *
13
 * @version 2.0 dev
14
 *
15
 */
16
17
use ElkArte\Cache\Cache;
18
use ElkArte\Helper\Util;
19
use ElkArte\User;
20
21
/**
22
 * Retrieve a list and several other statistics of the users currently online.
23
 *
24
 * - Used by the board index and SSI.
25
 * - Also returns the membergroups of the users that are currently online.
26
 * - (optionally) hides members that chose to hide their online presence.
27
 *
28
 * @param mixed[] $membersOnlineOptions
29
 * @return array
30
 * @package Members
31
 */
32
function getMembersOnlineStats($membersOnlineOptions)
33
{
34
	global $modSettings, $txt;
35 2
36
	$db = database();
37 2
38
	// The list can be sorted in several ways.
39
	$allowed_sort_options = array(
40
		'', // No sorting.
41 2
		'log_time',
42
		'real_name',
43
		'show_online',
44
		'online_color',
45
		'group_name',
46
	);
47
48
	// Default the sorting method to 'most recent online members first'.
49
	if (!isset($membersOnlineOptions['sort']))
50 2
	{
51
		$membersOnlineOptions['sort'] = 'log_time';
52
		$membersOnlineOptions['reverse_sort'] = true;
53
	}
54
55
	// Not allowed sort method? Bang! Error!
56
	elseif (!in_array($membersOnlineOptions['sort'], $allowed_sort_options))
57 2
	{
58
		trigger_error('Sort method for getMembersOnlineStats() function is not allowed', E_USER_NOTICE);
59
	}
60
61
	// Get it from the cache and send it back.
62
	$temp = array();
63 2
	$cache = Cache::instance();
64 2
	if ($cache->levelHigherThan(1) && $cache->getVar($temp, 'membersOnlineStats-' . $membersOnlineOptions['sort'], 240))
65 2
	{
66
		return filter_members_online($temp, empty($membersOnlineOptions['reverse_sort']) ? 'ksort' : 'krsort');
67
	}
68
69
	// Initialize the array that'll be returned later on.
70
	$membersOnlineStats = array(
71
		'users_online' => array(),
72 2
		'list_users_online' => array(),
73
		'online_groups' => array(),
74
		'num_guests' => 0,
75
		'num_spiders' => 0,
76
		'num_buddies' => 0,
77
		'num_users_hidden' => 0,
78
		'num_users_online' => 0,
79
	);
80
81
	// Get any spiders if enabled.
82
	$spiders = array();
83 2
	$spider_finds = array();
84 2
	if (!empty($modSettings['show_spider_online']) && ($modSettings['show_spider_online'] < 3 || allowedTo('admin_forum')) && !empty($modSettings['spider_name_cache']))
85 2
	{
86
		$spiders = Util::unserialize($modSettings['spider_name_cache']);
87
	}
88
89
	// Load the users online right now.
90
	$request = $db->query('', '
91 2
		SELECT
92
			lo.id_member, lo.log_time, lo.id_spider, mem.real_name, mem.member_name, mem.show_online,
93
			mg.online_color, mg.id_group, mg.group_name
94
		FROM {db_prefix}log_online AS lo
95
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lo.id_member)
96
			LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_mem_group} THEN mem.id_post_group ELSE mem.id_group END)',
97
		array(
98
			'reg_mem_group' => 0,
99 2
		)
100
	);
101
	while (($row = $request->fetch_assoc()))
102 2
	{
103
		if (empty($row['real_name']))
104
		{
105
			// Do we think it's a spider?
106
			if ($row['id_spider'] && isset($spiders[$row['id_spider']]))
107
			{
108
				$spider_finds[$row['id_spider']] = isset($spider_finds[$row['id_spider']]) ? $spider_finds[$row['id_spider']] + 1 : 1;
109
				$membersOnlineStats['num_spiders']++;
110
			}
111
			// Guests are only nice for statistics.
112
			$membersOnlineStats['num_guests']++;
113
114
			continue;
115
		}
116
		elseif (empty($row['show_online']) && empty($membersOnlineOptions['show_hidden']))
117
		{
118
			// Just increase the stats and don't add this hidden user to any list.
119
			$membersOnlineStats['num_users_hidden']++;
120
			continue;
121
		}
122
123
		$href = getUrl('profile', ['action' => 'profile', 'u' => $row['id_member'], 'name' => $row['real_name']]);
124
125
		// Some basic color coding...
126
		if (!empty($row['online_color']))
127
		{
128
			$link = '<a href="' . $href . '" style="color: ' . $row['online_color'] . ';">' . $row['real_name'] . '</a>';
129
		}
130
		else
131
		{
132
			$link = '<a href="' . $href . '">' . $row['real_name'] . '</a>';
133
		}
134
135
		// Buddies get counted and highlighted.
136
		$is_buddy = in_array($row['id_member'], User::$info->buddies);
0 ignored issues
show
It seems like ElkArte\User::info->buddies can also be of type null; however, parameter $haystack of in_array() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

136
		$is_buddy = in_array($row['id_member'], /** @scrutinizer ignore-type */ User::$info->buddies);
Loading history...
Bug Best Practice introduced by
The property buddies does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
137
		if ($is_buddy)
138
		{
139
			$membersOnlineStats['num_buddies']++;
140
			$link = '<strong>' . $link . '</strong>';
141
		}
142
143
		// A lot of useful information for each member.
144
		$membersOnlineStats['users_online'][$row[$membersOnlineOptions['sort']] . '_' . $row['member_name']] = array(
145
			'id' => $row['id_member'],
146
			'username' => $row['member_name'],
147
			'name' => $row['real_name'],
148
			'group' => $row['id_group'],
149
			'href' => $href,
150
			'link' => $link,
151
			'is_buddy' => $is_buddy,
152
			'hidden' => empty($row['show_online']),
153
			'is_last' => false,
154
		);
155
156
		// Store all distinct (primary) membergroups that are shown.
157
		if (!isset($membersOnlineStats['online_groups'][$row['id_group']]))
158
		{
159
			$membersOnlineStats['online_groups'][$row['id_group']] = array(
160
				'id' => $row['id_group'],
161
				'name' => $row['group_name'],
162
				'color' => $row['online_color']
163
			);
164
		}
165
	}
166
	$request->free_result();
167 2
168
	// If there are spiders only and we're showing the detail, add them to the online list - at the bottom.
169
	if (!empty($spider_finds) && $modSettings['show_spider_online'] > 1)
170 2
	{
171
		$sort = $membersOnlineOptions['sort'] === 'log_time' && $membersOnlineOptions['reverse_sort'] ? 0 : 'zzz_';
172
		foreach ($spider_finds as $id => $count)
173
		{
174
			$link = $spiders[$id] . ($count > 1 ? ' (' . $count . ')' : '');
175
			$membersOnlineStats['users_online'][$sort . '_' . $spiders[$id]] = array(
176
				'id' => 0,
177
				'username' => $spiders[$id],
178
				'name' => $link,
179
				'group' => $txt['spiders'],
180
				'href' => '',
181
				'link' => $link,
182
				'is_buddy' => false,
183
				'hidden' => false,
184
				'is_last' => false,
185
			);
186
			$membersOnlineStats['list_users_online'][$sort . '_' . $spiders[$id]] = $link;
187
		}
188
	}
189
190
	// Hidden and non-hidden members make up all online members.
191
	$membersOnlineStats['num_users_online'] = count($membersOnlineStats['users_online']) + $membersOnlineStats['num_users_hidden'] - (isset($modSettings['show_spider_online']) && $modSettings['show_spider_online'] > 1 ? count($spider_finds) : 0);
192 2
193
	Cache::instance()->put('membersOnlineStats-' . $membersOnlineOptions['sort'], $membersOnlineStats, 240);
194 2
195
	return filter_members_online($membersOnlineStats, empty($membersOnlineOptions['reverse_sort']) ? 'ksort' : 'krsort');
196 2
}
197
198
/**
199
 * Post-retrieval processing.
200
 * Needed mainly for when the cache is enabled and online users have to be
201
 * filtered out based on permissions.
202
 *
203
 * @param mixed[] $membersOnlineStats
204
 * @param string $sortFunction
205
 * @return mixed[]
206
 * @package Members
207
 */
208
function filter_members_online($membersOnlineStats, $sortFunction)
209
{
210
	foreach ($membersOnlineStats['users_online'] as $key => $row)
211
	{
212 2
		if (allowedTo('moderate_forum') === false && $row['hidden'])
213
		{
214
			continue;
215
		}
216
		// This is the compact version, simply implode it to show.
217
		$membersOnlineStats['list_users_online'][$key] = $row['hidden'] ? '<em>' . $row['link'] . '</em>' : $row['link'];
218
	}
219
220
	// Time to sort the list a bit.
221
	if (!empty($membersOnlineStats['users_online']))
222
	{
223 2
		// Sort the two lists.
224
		$sortFunction($membersOnlineStats['users_online']);
225
		$sortFunction($membersOnlineStats['list_users_online']);
226
227
		// Mark the last list item as 'is_last'.
228
		$userKeys = array_keys($membersOnlineStats['users_online']);
229
		$membersOnlineStats['users_online'][end($userKeys)]['is_last'] = true;
230
	}
231
232
	// Also sort the membergroups.
233
	ksort($membersOnlineStats['online_groups']);
234
235 2
	return $membersOnlineStats;
236
}
237 2
238
/**
239
 * Check if the number of users online is a record and store it.
240
 *
241
 * @param int $total_users_online
242
 * @package Members
243
 */
244
function trackStatsUsersOnline($total_users_online)
245
{
246
	global $modSettings;
247
248
	$db = database();
249 2
250
	$settingsToUpdate = array();
251 2
252
	// More members on now than ever were?  Update it!
253 2
	if (!isset($modSettings['mostOnline']) || $total_users_online >= $modSettings['mostOnline'])
254
	{
255
		$settingsToUpdate = array(
256 2
			'mostOnline' => $total_users_online,
257
			'mostDate' => time()
258
		);
259
	}
260
261
	$date = Util::strftime('%Y-%m-%d', forum_time(false));
262
263
	// No entry exists for today yet?
264 2
	if (!isset($modSettings['mostOnlineUpdated']) || $modSettings['mostOnlineUpdated'] != $date)
265
	{
266
		$request = $db->query('', '
267 2
			SELECT 
268
				most_on
269 2
			FROM {db_prefix}log_activity
270
			WHERE date = {date:date}
271
			LIMIT 1',
272
			array(
273
				'date' => $date,
274
			)
275
		);
276 2
277
		// The log_activity hasn't got an entry for today?
278
		if ($request->num_rows() === 0)
279
		{
280
			$db->insert('ignore',
281 2
				'{db_prefix}log_activity',
282
				array('date' => 'date', 'most_on' => 'int'),
283 2
				array($date, $total_users_online),
284 2
				array('date')
285 2
			);
286 2
		}
287 2
		// There's an entry in log_activity on today...
288
		else
289
		{
290
			list ($modSettings['mostOnlineToday']) = $request->fetch_row();
291
292
			if ($total_users_online > $modSettings['mostOnlineToday'])
293
			{
294
				trackStats(array('most_on' => $total_users_online));
295
			}
296
297
			$total_users_online = max($total_users_online, $modSettings['mostOnlineToday']);
298
		}
299
		$request->free_result();
300
301
		$settingsToUpdate['mostOnlineUpdated'] = $date;
302 2
		$settingsToUpdate['mostOnlineToday'] = $total_users_online;
303
	}
304 2
	// Highest number of users online today?
305 2
	elseif ($total_users_online > $modSettings['mostOnlineToday'])
306
	{
307
		trackStats(array('most_on' => $total_users_online));
308
		$settingsToUpdate['mostOnlineToday'] = $total_users_online;
309
	}
310
311
	if (!empty($settingsToUpdate))
312
	{
313
		updateSettings($settingsToUpdate);
314 2
	}
315
}
316