1 | <?php |
||||
2 | |||||
3 | /** |
||||
4 | * This file contains nosey functions so show where a user is active |
||||
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 | * @version 2.0 dev |
||||
11 | * |
||||
12 | */ |
||||
13 | |||||
14 | use ElkArte\Cache\Cache; |
||||
15 | use ElkArte\Helper\Util; |
||||
16 | use ElkArte\Languages\Txt; |
||||
17 | use ElkArte\User; |
||||
18 | |||||
19 | /** |
||||
20 | * Checks, who is viewing a topic or board |
||||
21 | * |
||||
22 | * @param int $id |
||||
23 | * @param string $session |
||||
24 | * @param string $type |
||||
25 | * @return array |
||||
26 | */ |
||||
27 | function viewers($id, $session, $type = 'topic') |
||||
28 | { |
||||
29 | 2 | $db = database(); |
|||
30 | |||||
31 | // Make sure we have a default value |
||||
32 | 2 | if (!in_array($type, array('topic', 'board'))) |
|||
33 | { |
||||
34 | $type = 'topic'; |
||||
35 | } |
||||
36 | |||||
37 | 2 | return $db->fetchQuery(' |
|||
38 | SELECT |
||||
39 | lo.id_member, lo.log_time, mem.real_name, mem.member_name, mem.show_online, |
||||
40 | mg.online_color, mg.id_group, mg.group_name |
||||
41 | FROM {db_prefix}log_online AS lo |
||||
42 | LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lo.id_member) |
||||
43 | LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_member_group} THEN mem.id_post_group ELSE mem.id_group END) |
||||
44 | WHERE INSTR(lo.url, {string:in_url_string}) > 0 OR lo.session = {string:session}', |
||||
45 | array( |
||||
46 | 2 | 'reg_member_group' => 0, |
|||
47 | 2 | 'in_url_string' => 's:5:"' . $type . '";i:' . $id . ';', |
|||
48 | 2 | 'session' => $session |
|||
49 | ) |
||||
50 | 2 | )->fetch_all(); |
|||
51 | } |
||||
52 | |||||
53 | /** |
||||
54 | * Format viewers list for display, for a topic or board. |
||||
55 | * |
||||
56 | * @param int $id id of the element (topic or board) we're watching |
||||
57 | * @param string $type = 'topic, 'topic' or 'board' |
||||
58 | */ |
||||
59 | function formatViewers($id, $type) |
||||
60 | { |
||||
61 | global $context; |
||||
62 | 2 | ||||
63 | // Lets say there's no one around. (what? could happen!) |
||||
64 | $context['view_members'] = array(); |
||||
65 | 2 | $context['view_members_list'] = array(); |
|||
66 | 2 | $context['view_num_hidden'] = 0; |
|||
67 | 2 | $context['view_num_guests'] = 0; |
|||
68 | 2 | ||||
69 | $viewers = viewers($id, User::$info->is_guest ? 'ip' . User::$info->ip : session_id(), $type); |
||||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() The property
is_guest does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||
70 | 2 | ||||
71 | foreach ($viewers as $viewer) |
||||
72 | 2 | { |
|||
73 | // is this a guest? |
||||
74 | if (empty($viewer['id_member'])) |
||||
75 | { |
||||
76 | $context['view_num_guests']++; |
||||
77 | continue; |
||||
78 | } |
||||
79 | |||||
80 | $href = getUrl('profile', ['action' => 'profile', 'u' => $viewer['id_member'], 'name' => $viewer['real_name']]); |
||||
81 | // it's a member. We format them with links 'n stuff. |
||||
82 | if (!empty($viewer['online_color'])) |
||||
83 | { |
||||
84 | $link = '<a href="' . $href . '" style="color: ' . $viewer['online_color'] . ';">' . $viewer['real_name'] . '</a>'; |
||||
85 | } |
||||
86 | else |
||||
87 | { |
||||
88 | $link = '<a href="' . $href . '">' . $viewer['real_name'] . '</a>'; |
||||
89 | } |
||||
90 | |||||
91 | $is_buddy = in_array($viewer['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
![]() The property
buddies does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||
92 | if ($is_buddy) |
||||
93 | { |
||||
94 | $link = '<strong>' . $link . '</strong>'; |
||||
95 | } |
||||
96 | |||||
97 | // fill the summary list |
||||
98 | if (!empty($viewer['show_online']) || allowedTo('moderate_forum')) |
||||
99 | { |
||||
100 | $context['view_members_list'][$viewer['log_time'] . $viewer['member_name']] = empty($viewer['show_online']) ? '<em>' . $link . '</em>' : $link; |
||||
101 | } |
||||
102 | |||||
103 | // fill the detailed list |
||||
104 | $context['view_members'][$viewer['log_time'] . $viewer['member_name']] = array( |
||||
105 | 'id' => $viewer['id_member'], |
||||
106 | 'username' => $viewer['member_name'], |
||||
107 | 'name' => $viewer['real_name'], |
||||
108 | 'group' => $viewer['id_group'], |
||||
109 | 'href' => $href, |
||||
110 | 'link' => $link, |
||||
111 | 'is_buddy' => $is_buddy, |
||||
112 | 'hidden' => empty($viewer['show_online']), |
||||
113 | ); |
||||
114 | |||||
115 | // add the hidden members to the count (and don't show them in the template) |
||||
116 | if (empty($viewer['show_online'])) |
||||
117 | { |
||||
118 | $context['view_num_hidden']++; |
||||
119 | } |
||||
120 | } |
||||
121 | |||||
122 | // Sort them out. |
||||
123 | krsort($context['view_members_list']); |
||||
124 | 2 | krsort($context['view_members']); |
|||
125 | 2 | } |
|||
126 | 2 | ||||
127 | |||||
128 | /** |
||||
129 | * This function determines the actions of the members passed in urls. |
||||
130 | * |
||||
131 | * Adding actions to the Who's Online list: |
||||
132 | * Adding actions to this list is actually relatively easy... |
||||
133 | * - for actions anyone should be able to see, just add a string named whoall_ACTION. |
||||
134 | * (where ACTION is the action used in index.php.) |
||||
135 | * - for actions that have a subaction which should be represented differently, use whoall_ACTION_SUBACTION. |
||||
136 | * - for actions that include a topic, and should be restricted, use whotopic_ACTION. |
||||
137 | * - for actions that use a message, by msg or quote, use whopost_ACTION. |
||||
138 | * - for administrator-only actions, use whoadmin_ACTION. |
||||
139 | * - for actions that should be viewable only with certain permissions, use whoallow_ACTION and |
||||
140 | * add a list of possible permissions to the $allowedActions array, using ACTION as the key. |
||||
141 | * |
||||
142 | * @param mixed[]|string $urls a single url (string) or an array of arrays, each inner array being (serialized request data, id_member) |
||||
143 | * @param string|bool $preferred_prefix = false |
||||
144 | * @return mixed[]|string an array of descriptions if you passed an array, otherwise the string describing their current location. |
||||
145 | */ |
||||
146 | function determineActions($urls, $preferred_prefix = false) |
||||
147 | { |
||||
148 | global $txt, $modSettings; |
||||
149 | |||||
150 | $db = database(); |
||||
151 | |||||
152 | if (!allowedTo('who_view')) |
||||
153 | { |
||||
154 | return array(); |
||||
155 | } |
||||
156 | |||||
157 | Txt::load('Who'); |
||||
158 | |||||
159 | // Actions that require a specific permission level. |
||||
160 | $allowedActions = array( |
||||
161 | 'admin' => array('moderate_forum', 'manage_membergroups', 'manage_bans', 'admin_forum', 'manage_permissions', 'send_mail', 'manage_attachments', 'manage_smileys', 'manage_boards', 'edit_news'), |
||||
162 | 'ban' => array('manage_bans'), |
||||
163 | 'boardrecount' => array('admin_forum'), |
||||
164 | 'calendar' => array('calendar_view'), |
||||
165 | 'editnews' => array('edit_news'), |
||||
166 | 'mailing' => array('send_mail'), |
||||
167 | 'maintain' => array('admin_forum'), |
||||
168 | 'manageattachments' => array('manage_attachments'), |
||||
169 | 'manageboards' => array('manage_boards'), |
||||
170 | 'memberlist' => array('view_mlist'), |
||||
171 | 'moderate' => array('access_mod_center', 'moderate_forum', 'manage_membergroups'), |
||||
172 | 'optimizetables' => array('admin_forum'), |
||||
173 | 'repairboards' => array('admin_forum'), |
||||
174 | 'search' => array('search_posts'), |
||||
175 | 'setcensor' => array('moderate_forum'), |
||||
176 | 'setreserve' => array('moderate_forum'), |
||||
177 | 'stats' => array('view_stats'), |
||||
178 | 'viewErrorLog' => array('admin_forum'), |
||||
179 | 'viewmembers' => array('moderate_forum'), |
||||
180 | ); |
||||
181 | |||||
182 | // Provide integration a way to add to the allowed action array |
||||
183 | call_integration_hook('integrate_whos_online_allowed', array(&$allowedActions)); |
||||
184 | |||||
185 | if (!is_array($urls)) |
||||
186 | { |
||||
187 | $url_list = array(array($urls, User::$info->id)); |
||||
0 ignored issues
–
show
The property
id does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||
188 | } |
||||
189 | else |
||||
190 | { |
||||
191 | $url_list = $urls; |
||||
192 | } |
||||
193 | |||||
194 | // These are done to query these in large chunks. (instead of one by one.) |
||||
195 | $topic_ids = array(); |
||||
196 | $profile_ids = array(); |
||||
197 | $board_ids = array(); |
||||
198 | |||||
199 | $data = array(); |
||||
200 | foreach ($url_list as $k => $url) |
||||
201 | { |
||||
202 | // Get the request parameters.. |
||||
203 | $actions = Util::unserialize($url[0]); |
||||
204 | if ($actions === false) |
||||
205 | { |
||||
206 | continue; |
||||
207 | } |
||||
208 | |||||
209 | // If it's the admin or moderation center, and there is an area set, use that instead. |
||||
210 | if (isset($actions['action']) && ($actions['action'] == 'admin' || $actions['action'] == 'moderate') && isset($actions['area'])) |
||||
211 | { |
||||
212 | $actions['action'] = $actions['area']; |
||||
213 | } |
||||
214 | |||||
215 | // Check if there was no action or the action is display. |
||||
216 | if (!isset($actions['action']) || $actions['action'] == 'display') |
||||
217 | { |
||||
218 | // It's a topic! Must be! |
||||
219 | if (isset($actions['topic'])) |
||||
220 | { |
||||
221 | // Assume they can't view it, and queue it up for later. |
||||
222 | $data[$k] = $txt['who_hidden']; |
||||
223 | $topic_ids[(int) $actions['topic']][$k] = $txt['who_topic']; |
||||
224 | } |
||||
225 | // It's a board! |
||||
226 | elseif (isset($actions['board'])) |
||||
227 | { |
||||
228 | // Hide first, show later. |
||||
229 | $data[$k] = $txt['who_hidden']; |
||||
230 | $board_ids[$actions['board']][$k] = $txt['who_board']; |
||||
231 | } |
||||
232 | // It's the board index!! It must be! |
||||
233 | else |
||||
234 | { |
||||
235 | $data[$k] = replaceBasicActionUrl($txt['who_index']); |
||||
236 | } |
||||
237 | } |
||||
238 | // Probably an error or some goon? |
||||
239 | elseif ($actions['action'] == '') |
||||
240 | { |
||||
241 | $data[$k] = replaceBasicActionUrl($txt['who_index']); |
||||
242 | } |
||||
243 | // Some other normal action...? |
||||
244 | else |
||||
245 | { |
||||
246 | // Viewing/editing a profile. |
||||
247 | if ($actions['action'] === 'profile') |
||||
248 | { |
||||
249 | // Whose? Their own? |
||||
250 | if (empty($actions['u'])) |
||||
251 | { |
||||
252 | require_once(SUBSDIR . '/Profile.subs.php'); |
||||
253 | $memID = currentMemberID(); |
||||
254 | |||||
255 | if ($memID == User::$info->id) |
||||
256 | { |
||||
257 | $actions['u'] = $url[1]; |
||||
258 | } |
||||
259 | else |
||||
260 | { |
||||
261 | $actions['u'] = $memID; |
||||
262 | } |
||||
263 | } |
||||
264 | |||||
265 | $data[$k] = $txt['who_hidden']; |
||||
266 | $profile_ids[(int) $actions['u']][$k] = $actions['action'] === 'profile' ? $txt['who_viewprofile'] : $txt['who_profile']; |
||||
267 | } |
||||
268 | // Trying to post |
||||
269 | elseif (($actions['action'] === 'post' || $actions['action'] === 'post2' || $actions['action'] === 'topicbyemail') && empty($actions['topic']) && isset($actions['board'])) |
||||
270 | { |
||||
271 | $data[$k] = $txt['who_hidden']; |
||||
272 | if ($actions['action'] === 'topicbyemail') |
||||
273 | { |
||||
274 | $board_ids[(int) $actions['board']][$k] = $txt['who_topicbyemail']; |
||||
275 | } |
||||
276 | else |
||||
277 | { |
||||
278 | $board_ids[(int) $actions['board']][$k] = isset($actions['poll']) ? $txt['who_poll'] : $txt['who_post']; |
||||
279 | } |
||||
280 | } |
||||
281 | // A subaction anyone can view... if the language string is there, show it. |
||||
282 | elseif (isset($actions['sa'], $txt['whoall_' . $actions['action'] . '_' . $actions['sa']])) |
||||
283 | { |
||||
284 | $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']]) ? $txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']] : $txt['whoall_' . $actions['action'] . '_' . $actions['sa']]; |
||||
0 ignored issues
–
show
Are you sure
$preferred_prefix of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
285 | } |
||||
286 | // An action any old fellow can look at. (if $txt['whoall_' . $action] exists, we know everyone can see it.) |
||||
287 | elseif (isset($txt['whoall_' . $actions['action']])) |
||||
288 | { |
||||
289 | $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action']]) ? $txt[$preferred_prefix . $actions['action']] : replaceBasicActionUrl($txt['whoall_' . $actions['action']]); |
||||
290 | } |
||||
291 | // Viewable if and only if they can see the board... |
||||
292 | elseif (isset($txt['whotopic_' . $actions['action']])) |
||||
293 | { |
||||
294 | // Find out what topic they are accessing. |
||||
295 | $topic = (int) ($actions['topic'] ?? ($actions['from'] ?? 0)); |
||||
296 | |||||
297 | $data[$k] = $txt['who_hidden']; |
||||
298 | $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action']]; |
||||
299 | } |
||||
300 | // Viewable if and only if they can see the board... |
||||
301 | elseif (isset($actions['sa']) && isset($txt['whotopic_' . $actions['action'] . '_' . $actions['sa']])) |
||||
302 | { |
||||
303 | // Find out what topic they are accessing. |
||||
304 | $topic = (int) ($actions['topic'] ?? ($actions['from'] ?? 0)); |
||||
305 | |||||
306 | $data[$k] = $txt['who_hidden']; |
||||
307 | $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action'] . '_' . $actions['sa']]; |
||||
308 | } |
||||
309 | elseif (isset($txt['whopost_' . $actions['action']])) |
||||
310 | { |
||||
311 | // Find out what message they are accessing. |
||||
312 | $msgid = (int) ($actions['msg'] ?? ($actions['quote'] ?? 0)); |
||||
313 | |||||
314 | $result = $db->query('', ' |
||||
315 | SELECT |
||||
316 | m.id_topic, m.subject |
||||
317 | FROM {db_prefix}messages AS m |
||||
318 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) |
||||
319 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ') |
||||
320 | WHERE m.id_msg = {int:id_msg} |
||||
321 | AND {query_see_board}' . ($modSettings['postmod_active'] ? ' |
||||
322 | AND m.approved = {int:is_approved}' : '') . ' |
||||
323 | LIMIT 1', |
||||
324 | array( |
||||
325 | 'is_approved' => 1, |
||||
326 | 'id_msg' => $msgid, |
||||
327 | ) |
||||
328 | ); |
||||
329 | list ($id_topic, $subject) = $result->fetch_row(); |
||||
330 | $data[$k] = sprintf($txt['whopost_' . $actions['action']], getUrl('topic', ['topic' => $id_topic, 'start' => '0', 'subject' => $subject]), $subject); |
||||
331 | $result->free_result(); |
||||
332 | |||||
333 | if (empty($id_topic)) |
||||
334 | { |
||||
335 | $data[$k] = $txt['who_hidden']; |
||||
336 | } |
||||
337 | } |
||||
338 | // Viewable only by administrators.. (if it starts with whoadmin, it's admin only!) |
||||
339 | elseif (allowedTo('moderate_forum') && isset($txt['whoadmin_' . $actions['action']])) |
||||
340 | { |
||||
341 | $data[$k] = $txt['whoadmin_' . $actions['action']]; |
||||
342 | } |
||||
343 | // Viewable by permission level. |
||||
344 | elseif (isset($allowedActions[$actions['action']])) |
||||
345 | { |
||||
346 | if (allowedTo($allowedActions[$actions['action']])) |
||||
347 | { |
||||
348 | if (isset($actions['sa']) && isset($txt['whoallow_' . $actions['action'] . '_' . $actions['sa']])) |
||||
349 | { |
||||
350 | $data[$k] = replaceBasicActionUrl($txt['whoallow_' . $actions['action'] . '_' . $actions['sa']]); |
||||
351 | } |
||||
352 | else |
||||
353 | { |
||||
354 | $data[$k] = replaceBasicActionUrl($txt['whoallow_' . $actions['action']]); |
||||
355 | } |
||||
356 | } |
||||
357 | elseif (in_array('moderate_forum', $allowedActions[$actions['action']])) |
||||
358 | { |
||||
359 | $data[$k] = $txt['who_moderate']; |
||||
360 | } |
||||
361 | elseif (in_array('admin_forum', $allowedActions[$actions['action']])) |
||||
362 | { |
||||
363 | $data[$k] = $txt['who_admin']; |
||||
364 | } |
||||
365 | else |
||||
366 | { |
||||
367 | $data[$k] = $txt['who_hidden']; |
||||
368 | } |
||||
369 | } |
||||
370 | // Something we don't have details about, but it is an action, maybe an addon |
||||
371 | elseif (!empty($actions['action'])) |
||||
372 | { |
||||
373 | $data[$k] = sprintf($txt['who_generic'], $actions['action']); |
||||
374 | } |
||||
375 | // We just don't know |
||||
376 | else |
||||
377 | { |
||||
378 | $data[$k] = $txt['who_unknown']; |
||||
379 | } |
||||
380 | } |
||||
381 | |||||
382 | // Maybe the action is integrated into another system? |
||||
383 | if (count($integrate_actions = call_integration_hook('integrate_whos_online', array($actions))) > 0) |
||||
384 | { |
||||
385 | // Try each integration hook with this url and see if they can fill in the details |
||||
386 | foreach ($integrate_actions as $integrate_action) |
||||
387 | { |
||||
388 | if (!empty($integrate_action)) |
||||
389 | { |
||||
390 | // Found it, all done then |
||||
391 | $data[$k] = $integrate_action; |
||||
392 | break; |
||||
393 | } |
||||
394 | } |
||||
395 | } |
||||
396 | } |
||||
397 | |||||
398 | // Load topic names. |
||||
399 | if (!empty($topic_ids)) |
||||
400 | { |
||||
401 | require_once(SUBSDIR . '/Topic.subs.php'); |
||||
402 | $topics_data = topicsList(array_keys($topic_ids)); |
||||
403 | |||||
404 | foreach ($topics_data as $topic) |
||||
405 | { |
||||
406 | // Show the topic's subject for each of the members looking at this... |
||||
407 | foreach ($topic_ids[$topic['id_topic']] as $k => $session_text) |
||||
408 | { |
||||
409 | $data[$k] = sprintf($session_text, getUrl('topic', ['topic' => $topic['id_topic'], 'start' => '0', 'subject' => $topic['subject']]), $topic['subject']); |
||||
410 | } |
||||
411 | } |
||||
412 | } |
||||
413 | |||||
414 | // Load board names. |
||||
415 | if (!empty($board_ids)) |
||||
416 | { |
||||
417 | require_once(SUBSDIR . '/Boards.subs.php'); |
||||
418 | |||||
419 | $boards_list = getBoardList(array('included_boards' => array_keys($board_ids)), true); |
||||
420 | foreach ($boards_list as $board) |
||||
421 | { |
||||
422 | // Put the board name into the string for each member... |
||||
423 | foreach ($board_ids[$board['id_board']] as $k => $session_text) |
||||
424 | { |
||||
425 | $data[$k] = sprintf($session_text, getUrl('board', ['board' => $board['id_board'], 'start' => '0', 'name' => $board['board_name']]), $board['board_name']); |
||||
426 | } |
||||
427 | } |
||||
428 | } |
||||
429 | |||||
430 | // Load member names for the profile. |
||||
431 | if (!empty($profile_ids) && (allowedTo('profile_view_any') || allowedTo('profile_view_own'))) |
||||
432 | { |
||||
433 | require_once(SUBSDIR . '/Members.subs.php'); |
||||
434 | $result = getBasicMemberData(array_keys($profile_ids)); |
||||
435 | foreach ($result as $row) |
||||
436 | { |
||||
437 | // If they aren't allowed to view this person's profile, skip it. |
||||
438 | if (!allowedTo('profile_view_any') && User::$info->id != $row['id_member']) |
||||
439 | { |
||||
440 | continue; |
||||
441 | } |
||||
442 | |||||
443 | // Set their action on each - session/text to sprintf. |
||||
444 | foreach ($profile_ids[$row['id_member']] as $k => $session_text) |
||||
445 | { |
||||
446 | $data[$k] = sprintf($session_text, getUrl('profile', ['action' => 'profile', 'u' => $row['id_member'], 'name' => $row['real_name']]), $row['real_name']); |
||||
447 | } |
||||
448 | } |
||||
449 | } |
||||
450 | |||||
451 | if (!is_array($urls)) |
||||
452 | { |
||||
453 | return $data[0] ?? false; |
||||
0 ignored issues
–
show
The expression
return $data[0] ?? false could also return false which is incompatible with the documented return type array<mixed,mixed>|string . Did you maybe forget to handle an error condition?
If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled. ![]() |
|||||
454 | } |
||||
455 | else |
||||
456 | { |
||||
457 | return $data; |
||||
458 | } |
||||
459 | } |
||||
460 |