1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Provides ways to add information to your website by linking to and capturing output |
5
|
|
|
* from ElkArte |
6
|
|
|
* |
7
|
|
|
* @package ElkArte Forum |
8
|
|
|
* @copyright ElkArte Forum contributors |
9
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
10
|
|
|
* |
11
|
|
|
* This file contains code covered by: |
12
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
13
|
|
|
* |
14
|
|
|
* @version 2.0 dev |
15
|
|
|
* |
16
|
|
|
*/ |
17
|
|
|
|
18
|
|
|
use BBC\ParserWrapper; |
19
|
|
|
use ElkArte\Cache\Cache; |
20
|
|
|
use ElkArte\Controller\Poll; |
21
|
|
|
use ElkArte\EventManager; |
22
|
|
|
use ElkArte\Helper\Util; |
23
|
|
|
use ElkArte\MembersList; |
24
|
|
|
use ElkArte\MessageTopicIcons; |
25
|
|
|
use ElkArte\User; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Set this to one of three values depending on what you want to happen in the case of a fatal error. |
29
|
|
|
* - false: Default, will just load the error sub template and die - not putting any theme layers around it. |
30
|
|
|
* - true: Will load the error sub template AND put the template layers around it (Not useful if on total custom pages). |
31
|
|
|
* - string: Name of a callback function to call in the event of an error to allow you to define your own methods. Will die after function returns. |
32
|
|
|
*/ |
33
|
|
|
$ssi_on_error_method = false; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Don't do john didley if the forum's been shut down completely. |
37
|
|
|
*/ |
38
|
|
|
// $ssi_maintenance_off = false; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Define a theme for SSI (integer) |
42
|
|
|
*/ |
43
|
|
|
// $ssi_theme = 0; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* An array of layers to use. |
47
|
|
|
*/ |
48
|
|
|
// $ssi_layers = array(); |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Gzip output? (because it must be boolean and true, this can't be hacked.) |
52
|
|
|
*/ |
53
|
|
|
// $ssi_gzip = false; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Should we ban from SSI as well? |
57
|
|
|
*/ |
58
|
|
|
// $ssi_ban = false; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Do we allow guests in here? |
62
|
|
|
*/ |
63
|
|
|
// $ssi_guest_access = false; |
64
|
|
|
|
65
|
|
|
// We are in Elk, but from the side-entrance. |
66
|
|
|
if (!defined('ELKBOOT')) |
67
|
|
|
{ |
68
|
|
|
define('ELK', 'SSI'); |
69
|
|
|
|
70
|
|
|
require_once(__DIR__ . '/bootstrap.php'); |
71
|
|
|
$bootstrap = new Bootstrap(true); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
// The globals that were created during the bootstrap process |
75
|
|
|
global $time_start, $maintenance, $msubject, $mmessage, $mbname, $language; |
76
|
|
|
global $boardurl, $webmaster_email, $cookiename; |
77
|
|
|
global $db_type, $db_server, $db_name, $db_user, $db_prefix, $db_persist, $db_error_send; |
78
|
|
|
global $modSettings, $context, $user_info, $topic, $board, $txt; |
79
|
|
|
global $ssi_db_user, $scripturl, $ssi_db_passwd, $db_passwd; |
80
|
|
|
global $boarddir, $sourcedir, $db_show_debug, $ssi_error_reporting; |
81
|
|
|
|
82
|
|
|
// Have the ability to easily add functions to SSI. |
83
|
|
|
call_integration_hook('integrate_SSI'); |
84
|
|
|
|
85
|
|
|
// Call a function passed by GET. |
86
|
|
|
if (isset($_GET['ssi_function']) && function_exists('ssi_' . $_GET['ssi_function']) && (!empty($modSettings['allow_guestAccess']) || User::$info->is_guest === false)) |
|
|
|
|
87
|
|
|
{ |
88
|
|
|
call_user_func('ssi_' . $_GET['ssi_function']); |
89
|
|
|
exit; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
if (isset($_GET['ssi_function'])) |
93
|
|
|
{ |
94
|
|
|
exit; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
// You shouldn't just access SSI.php directly by URL!! |
98
|
|
|
if (basename($_SERVER['PHP_SELF']) === 'SSI.php') |
99
|
|
|
{ |
100
|
|
|
die(sprintf($txt['ssi_not_direct'], User::$info->is_admin ? "'" . addslashes(__FILE__) . "'" : "'SSI.php'")); |
|
|
|
|
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
error_reporting($ssi_error_reporting); |
104
|
|
|
|
105
|
|
|
return true; |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* This shuts down the SSI and shows the footer. |
109
|
|
|
*/ |
110
|
|
|
function ssi_shutdown() |
111
|
|
|
{ |
112
|
|
|
if (!isset($_GET['ssi_function']) || $_GET['ssi_function'] !== 'shutdown') |
113
|
|
|
{ |
114
|
|
|
template_footer(); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Display a welcome message, like: |
120
|
|
|
* "Hey, User, you have 0 messages, 0 are new." |
121
|
|
|
* |
122
|
|
|
* @param string $output_method The output method. If 'echo', will display |
123
|
|
|
* everything. Otherwise returns an array of user info. |
124
|
|
|
*/ |
125
|
|
|
function ssi_welcome($output_method = 'echo') |
126
|
|
|
{ |
127
|
|
|
global $context, $txt, $scripturl; |
128
|
|
|
|
129
|
|
|
if ($output_method === 'echo') |
130
|
|
|
{ |
131
|
|
|
if ($context['user']['is_guest']) |
132
|
|
|
{ |
133
|
|
|
echo replaceBasicActionUrl($txt[$context['can_register'] ? 'welcome_guest_register' : 'welcome_guest']); |
134
|
|
|
} |
135
|
|
|
else |
136
|
|
|
{ |
137
|
|
|
echo $txt['hello_member'], ' <strong>', $context['user']['name'], '</strong>', allowedTo('pm_read') ? ', ' . (empty($context['user']['messages']) ? $txt['msg_alert_no_messages'] : (($context['user']['messages'] == 1 ? sprintf($txt['msg_alert_one_message'], $scripturl . '?action=pm') : sprintf($txt['msg_alert_many_message'], $scripturl . '?action=pm', $context['user']['messages'])) . ', ' . ($context['user']['unread_messages'] == 1 ? $txt['msg_alert_one_new'] : sprintf($txt['msg_alert_many_new'], $context['user']['unread_messages'])))) : ''; |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
// Don't echo... then do what?! |
141
|
|
|
else |
142
|
|
|
{ |
143
|
|
|
return $context['user']; |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Display a menu bar, like is displayed at the top of the forum. |
149
|
|
|
* |
150
|
|
|
* @param string $output_method The output method. If 'echo', will display |
151
|
|
|
* everything. Otherwise returns an array of menu data. |
152
|
|
|
*/ |
153
|
|
|
function ssi_menubar($output_method = 'echo') |
154
|
|
|
{ |
155
|
|
|
global $context; |
156
|
|
|
|
157
|
|
|
if ($output_method === 'echo') |
158
|
|
|
{ |
159
|
|
|
template_menu(); |
160
|
|
|
} |
161
|
|
|
// What else could this do? |
162
|
|
|
else |
163
|
|
|
{ |
164
|
|
|
return $context['menu_buttons']; |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Show a logout link. |
170
|
|
|
* |
171
|
|
|
* @param string $redirect_to A URL to redirect the user to after they log out. |
172
|
|
|
* @param string $output_method = 'echo; The output method. If 'echo', shows a logout link, |
173
|
|
|
* otherwise returns HTML. |
174
|
|
|
*/ |
175
|
|
|
function ssi_logout($redirect_to = '', $output_method = 'echo') |
176
|
|
|
{ |
177
|
|
|
global $context, $txt, $scripturl; |
178
|
|
|
|
179
|
|
|
if ($redirect_to !== '') |
180
|
|
|
{ |
181
|
|
|
$_SESSION['logout_url'] = $redirect_to; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
// Guests can't log out. |
185
|
|
|
if ($context['user']['is_guest']) |
186
|
|
|
{ |
187
|
|
|
return false; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
$link = '<a class="linkbutton" href="' . $scripturl . '?action=logout;' . $context['session_var'] . '=' . $context['session_id'] . '">' . $txt['logout'] . '</a>'; |
191
|
|
|
|
192
|
|
|
if ($output_method === 'echo') |
193
|
|
|
{ |
194
|
|
|
echo $link; |
195
|
|
|
} |
196
|
|
|
else |
197
|
|
|
{ |
198
|
|
|
return $link; |
199
|
|
|
} |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Recent post list: |
204
|
|
|
* [board] Subject by Poster Date |
205
|
|
|
* |
206
|
|
|
* @param int $num_recent How many recent posts to display |
207
|
|
|
* @param int[]|null $exclude_boards If set, doesn't show posts from the specified boards |
208
|
|
|
* @param int[]|null $include_boards If set, only includes posts from the specified boards |
209
|
|
|
* @param string $output_method The output method. If 'echo', displays the posts, otherwise |
210
|
|
|
* returns an array of information about them. |
211
|
|
|
* @param bool $limit_body Whether or not to only show the first 384 characters of each post |
212
|
|
|
* @todo this may use getLastPosts with some modification |
213
|
|
|
* |
214
|
|
|
*/ |
215
|
|
|
function ssi_recentPosts($num_recent = 8, $exclude_boards = null, $include_boards = null, $output_method = 'echo', $limit_body = true) |
216
|
|
|
{ |
217
|
|
|
global $modSettings; |
218
|
|
|
|
219
|
|
|
// Excluding certain boards... |
220
|
|
|
if ($exclude_boards === null && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0) |
221
|
|
|
{ |
222
|
|
|
$exclude_boards = array($modSettings['recycle_board']); |
223
|
|
|
} |
224
|
|
|
elseif (empty($exclude_boards)) |
225
|
|
|
{ |
226
|
|
|
$exclude_boards = array(); |
227
|
|
|
} |
228
|
|
|
elseif (is_array($exclude_boards)) |
|
|
|
|
229
|
|
|
{ |
230
|
|
|
$exclude_boards = $exclude_boards; |
231
|
|
|
} |
232
|
|
|
else |
233
|
|
|
{ |
234
|
|
|
$exclude_boards = array($exclude_boards); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
// What about including certain boards - note we do some protection here as pre-2.0 didn't have this parameter. |
238
|
|
|
if (is_array($include_boards) || (int) $include_boards === $include_boards) |
239
|
|
|
{ |
240
|
|
|
$include_boards = is_array($include_boards) ? $include_boards : array($include_boards); |
|
|
|
|
241
|
|
|
} |
242
|
|
|
elseif ($include_boards !== null) |
|
|
|
|
243
|
|
|
{ |
244
|
|
|
$include_boards = array(); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
// Let's restrict the query boys (and girls) |
248
|
|
|
$query_where = ' |
249
|
|
|
m.id_msg >= {int:min_message_id} |
250
|
|
|
' . (empty($exclude_boards) ? '' : ' |
251
|
|
|
AND b.id_board NOT IN ({array_int:exclude_boards})') . ' |
252
|
|
|
' . ($include_boards === null ? '' : ' |
253
|
|
|
AND b.id_board IN ({array_int:include_boards})') . ' |
254
|
|
|
AND {query_wanna_see_board}' . ($modSettings['postmod_active'] ? ' |
255
|
|
|
AND m.approved = {int:is_approved}' : ''); |
256
|
|
|
|
257
|
|
|
$query_where_params = array( |
258
|
|
|
'is_approved' => 1, |
259
|
|
|
'include_boards' => $include_boards ?? '', |
260
|
|
|
'exclude_boards' => empty($exclude_boards) ? '' : $exclude_boards, |
261
|
|
|
'min_message_id' => $modSettings['maxMsgID'] - 25 * min($num_recent, 5), |
262
|
|
|
); |
263
|
|
|
|
264
|
|
|
// Past to this simpleton of a function... |
265
|
|
|
return ssi_queryPosts($query_where, $query_where_params, $num_recent, 'm.id_msg DESC', $output_method, $limit_body); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* Fetch a post with a particular ID. |
270
|
|
|
* |
271
|
|
|
* - By default will only show if you have permission to the see the board |
272
|
|
|
* in question - this can be overridden. |
273
|
|
|
* |
274
|
|
|
* @param int[] $post_ids An array containing the IDs of the posts to show |
275
|
|
|
* @param bool $override_permissions Whether to ignore permissions. If true, will show posts even |
276
|
|
|
* if the user doesn't have permission to see them. |
277
|
|
|
* @param string $output_method = 'echo; The output method. If 'echo', displays the posts, |
278
|
|
|
* otherwise returns an array of info about them |
279
|
|
|
* @todo this may use getRecentPosts with some modification |
280
|
|
|
* |
281
|
|
|
*/ |
282
|
|
|
function ssi_fetchPosts($post_ids = array(), $override_permissions = false, $output_method = 'echo') |
283
|
|
|
{ |
284
|
|
|
global $modSettings; |
285
|
|
|
|
286
|
|
|
if (empty($post_ids)) |
287
|
|
|
{ |
288
|
|
|
return ''; |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
// Allow the user to request more than one - why not? |
292
|
|
|
$post_ids = is_array($post_ids) ? $post_ids : array($post_ids); |
|
|
|
|
293
|
|
|
|
294
|
|
|
// Restrict the posts required... |
295
|
|
|
$query_where = ' |
296
|
|
|
m.id_msg IN ({array_int:message_list})' . ($override_permissions ? '' : ' |
297
|
|
|
AND {query_wanna_see_board}') . ($modSettings['postmod_active'] ? ' |
298
|
|
|
AND m.approved = {int:is_approved}' : ''); |
299
|
|
|
$query_where_params = array( |
300
|
|
|
'message_list' => $post_ids, |
301
|
|
|
'is_approved' => 1, |
302
|
|
|
); |
303
|
|
|
|
304
|
|
|
// Then make the query and dump the data. |
305
|
|
|
return ssi_queryPosts($query_where, $query_where_params, '', 'm.id_msg DESC', $output_method, false, $override_permissions); |
|
|
|
|
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* This handles actually pulling post info |
310
|
|
|
* |
311
|
|
|
* - removes code duplication in other queries |
312
|
|
|
* - don't call it direct unless you really know what you're up to. |
313
|
|
|
* |
314
|
|
|
* @param string $query_where The WHERE clause for the query |
315
|
|
|
* @param mixed[] $query_where_params An array of parameters for the WHERE clause |
316
|
|
|
* @param int $query_limit The maximum number of rows to return |
317
|
|
|
* @param string $query_order The ORDER BY clause for the query |
318
|
|
|
* @param string $output_method = 'echo; The output method. If 'echo', displays the posts, |
319
|
|
|
* otherwise returns an array of info about them. |
320
|
|
|
* @param bool $limit_body If true, will only show the first 384 characters of the post |
321
|
|
|
* rather than all of it |
322
|
|
|
* @param bool $override_permissions Whether or not to ignore permissions. If true, will |
323
|
|
|
* show all posts regardless of whether the user can actually see them |
324
|
|
|
* @todo if ssi_recentPosts and ssi_fetchPosts will use Recent.subs.php this can be removed |
325
|
|
|
* |
326
|
|
|
*/ |
327
|
|
|
function ssi_queryPosts($query_where = '', $query_where_params = array(), $query_limit = 10, $query_order = 'm.id_msg DESC', $output_method = 'echo', $limit_body = false, $override_permissions = false) |
328
|
|
|
{ |
329
|
|
|
global $scripturl, $txt, $modSettings; |
330
|
|
|
|
331
|
|
|
$db = database(); |
332
|
|
|
|
333
|
|
|
// Find all the posts. Newer ones will have higher IDs. |
334
|
|
|
$request = $db->fetchQuery(' |
335
|
|
|
SELECT |
336
|
|
|
m.poster_time, m.subject, m.id_topic, m.id_member, m.id_msg, m.id_board, b.name AS board_name, |
337
|
|
|
COALESCE(mem.real_name, m.poster_name) AS poster_name, ' . (User::$info->is_guest ? '1 AS is_read, 0 AS new_from' : ' |
|
|
|
|
338
|
|
|
COALESCE(lt.id_msg, lmr.id_msg, 0) >= m.id_msg_modified AS is_read, |
339
|
|
|
COALESCE(lt.id_msg, lmr.id_msg, -1) + 1 AS new_from') . ', ' . ($limit_body ? 'SUBSTRING(m.body, 1, 384) AS body' : 'm.body') . ', m.smileys_enabled |
340
|
|
|
FROM {db_prefix}messages AS m |
341
|
|
|
JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) |
342
|
|
|
JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) |
343
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)' . (User::$info->is_guest ? '' : ' |
344
|
|
|
LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = m.id_topic AND lt.id_member = {int:current_member}) |
345
|
|
|
LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = m.id_board AND lmr.id_member = {int:current_member})') . ' |
346
|
|
|
WHERE 1=1 ' . ($override_permissions ? '' : ' |
347
|
|
|
AND {query_wanna_see_board}') . ($modSettings['postmod_active'] ? ' |
348
|
|
|
AND m.approved = {int:is_approved} |
349
|
|
|
AND t.approved = {int:is_approved}' : '') . ' |
350
|
|
|
' . (empty($query_where) ? '' : 'AND ' . $query_where) . ' |
351
|
|
|
ORDER BY ' . $query_order . ' |
352
|
|
|
' . (empty($query_limit) ? '' : 'LIMIT {int:query_limit}'), |
353
|
|
|
array_merge($query_where_params, array( |
354
|
|
|
'current_member' => User::$info->id, |
|
|
|
|
355
|
|
|
'is_approved' => 1, |
356
|
|
|
'query_limit' => $query_limit, |
357
|
|
|
)) |
358
|
|
|
); |
359
|
|
|
|
360
|
|
|
$bbc_parser = ParserWrapper::instance(); |
361
|
|
|
|
362
|
|
|
$posts = array(); |
363
|
|
|
while ($row = $request->fetch_assoc()) |
364
|
|
|
{ |
365
|
|
|
$row['body'] = $bbc_parser->parseMessage($row['body'], $row['smileys_enabled']); |
366
|
|
|
|
367
|
|
|
// Censor it! |
368
|
|
|
$row['subject'] = censor($row['subject']); |
369
|
|
|
$row['body'] = censor($row['body']); |
370
|
|
|
|
371
|
|
|
$preview = strip_tags(strtr($row['body'], array('<br />' => ' '))); |
372
|
|
|
|
373
|
|
|
// Build the array. |
374
|
|
|
$posts[] = array( |
375
|
|
|
'id' => $row['id_msg'], |
376
|
|
|
'board' => array( |
377
|
|
|
'id' => $row['id_board'], |
378
|
|
|
'name' => $row['board_name'], |
379
|
|
|
'href' => $scripturl . '?board=' . $row['id_board'] . '.0', |
380
|
|
|
'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['board_name'] . '</a>' |
381
|
|
|
), |
382
|
|
|
'topic' => $row['id_topic'], |
383
|
|
|
'poster' => array( |
384
|
|
|
'id' => $row['id_member'], |
385
|
|
|
'name' => $row['poster_name'], |
386
|
|
|
'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], |
387
|
|
|
'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>' |
388
|
|
|
), |
389
|
|
|
'subject' => $row['subject'], |
390
|
|
|
'short_subject' => Util::shorten_text($row['subject'], empty($modSettings['ssi_subject_length']) ? 24 : $modSettings['ssi_subject_length']), |
391
|
|
|
'preview' => Util::shorten_text($preview, empty($modSettings['ssi_preview_length']) ? 128 : $modSettings['ssi_preview_length']), |
392
|
|
|
'body' => $row['body'], |
393
|
|
|
'time' => standardTime($row['poster_time']), |
394
|
|
|
'html_time' => htmlTime($row['poster_time']), |
395
|
|
|
'timestamp' => forum_time(true, $row['poster_time']), |
396
|
|
|
'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';topicseen#new', |
397
|
|
|
'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '" rel="nofollow">' . $row['subject'] . '</a>', |
398
|
|
|
'new' => !empty($row['is_read']), |
399
|
|
|
'is_new' => empty($row['is_read']), |
400
|
|
|
'new_from' => $row['new_from'], |
401
|
|
|
); |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
$request->free_result(); |
405
|
|
|
|
406
|
|
|
// Just return it. |
407
|
|
|
if ($output_method !== 'echo' || empty($posts)) |
408
|
|
|
{ |
409
|
|
|
return $posts; |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
echo ' |
413
|
|
|
<table class="ssi_table">'; |
414
|
|
|
|
415
|
|
|
foreach ($posts as $post) |
416
|
|
|
{ |
417
|
|
|
echo ' |
418
|
|
|
<tr> |
419
|
|
|
<td class="righttext"> |
420
|
|
|
[', $post['board']['link'], '] |
421
|
|
|
</td> |
422
|
|
|
<td class="top"> |
423
|
|
|
<a href="', $post['href'], '">', $post['subject'], '</a> |
424
|
|
|
', $txt['by'], ' ', $post['poster']['link'], ' |
425
|
|
|
', $post['is_new'] ? '<a href="' . $scripturl . '?topic=' . $post['topic'] . '.msg' . $post['new_from'] . ';topicseen#new" rel="nofollow" class="new_posts">' . $txt['new'] . '</a>' : '', ' |
426
|
|
|
</td> |
427
|
|
|
<td class="righttext"> |
428
|
|
|
', $post['time'], ' |
429
|
|
|
</td> |
430
|
|
|
</tr>'; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
echo ' |
434
|
|
|
</table>'; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Generates a recent topic list |
439
|
|
|
* |
440
|
|
|
* - [board] Subject by Poster Date |
441
|
|
|
* |
442
|
|
|
* @param int $num_recent How many recent topics to show |
443
|
|
|
* @param int[]|null $exclude_boards If set, exclude topics from the specified board(s) |
444
|
|
|
* @param bool|null $include_boards If set, only include topics from the specified board(s) |
445
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a list of topics, |
446
|
|
|
* otherwise returns an array of info about them |
447
|
|
|
*/ |
448
|
|
|
function ssi_recentTopics($num_recent = 8, $exclude_boards = null, $include_boards = null, $output_method = 'echo') |
449
|
|
|
{ |
450
|
|
|
global $settings, $scripturl, $txt, $modSettings; |
451
|
|
|
|
452
|
|
|
$db = database(); |
453
|
|
|
|
454
|
|
|
if ($exclude_boards === null && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0) |
455
|
|
|
{ |
456
|
|
|
$exclude_boards = array($modSettings['recycle_board']); |
457
|
|
|
} |
458
|
|
|
else |
459
|
|
|
{ |
460
|
|
|
$exclude_boards = empty($exclude_boards) ? array() : (is_array($exclude_boards) ? $exclude_boards : array($exclude_boards)); |
|
|
|
|
461
|
|
|
} |
462
|
|
|
|
463
|
|
|
// Only some boards?. |
464
|
|
|
if (is_array($include_boards) || (int) $include_boards === $include_boards) |
|
|
|
|
465
|
|
|
{ |
466
|
|
|
$include_boards = is_array($include_boards) ? $include_boards : array($include_boards); |
467
|
|
|
} |
468
|
|
|
elseif ($include_boards !== null) |
469
|
|
|
{ |
470
|
|
|
$output_method = $include_boards; |
471
|
|
|
$include_boards = array(); |
472
|
|
|
} |
473
|
|
|
|
474
|
|
|
$icon_sources = new MessageTopicIcons(!empty($modSettings['messageIconChecks_enable']), $settings['theme_dir']); |
475
|
|
|
|
476
|
|
|
// Find all the posts in distinct topics. Newer ones will have higher IDs. |
477
|
|
|
$topics = array(); |
478
|
|
|
$db->fetchQuery(' |
479
|
|
|
SELECT |
480
|
|
|
t.id_topic, b.id_board, b.name AS board_name |
481
|
|
|
FROM {db_prefix}topics AS t |
482
|
|
|
INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) |
483
|
|
|
LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
484
|
|
|
WHERE t.id_last_msg >= {int:min_message_id}' . (empty($exclude_boards) ? '' : ' |
485
|
|
|
AND b.id_board NOT IN ({array_int:exclude_boards})') . (empty($include_boards) ? '' : ' |
486
|
|
|
AND b.id_board IN ({array_int:include_boards})') . ' |
487
|
|
|
AND {query_wanna_see_board}' . ($modSettings['postmod_active'] ? ' |
488
|
|
|
AND t.approved = {int:is_approved} |
489
|
|
|
AND ml.approved = {int:is_approved}' : '') . ' |
490
|
|
|
ORDER BY t.id_last_msg DESC |
491
|
|
|
LIMIT {int:num_recent}', |
492
|
|
|
array( |
493
|
|
|
'include_boards' => empty($include_boards) ? '' : $include_boards, |
494
|
|
|
'exclude_boards' => empty($exclude_boards) ? '' : $exclude_boards, |
495
|
|
|
'min_message_id' => $modSettings['maxMsgID'] - 35 * min($num_recent, 5), |
496
|
|
|
'is_approved' => 1, |
497
|
|
|
'num_recent' => $num_recent, |
498
|
|
|
) |
499
|
|
|
)->fetch_callback( |
500
|
|
|
static function ($row) use (&$topics) { |
501
|
|
|
$topics[$row['id_topic']] = $row; |
502
|
|
|
} |
503
|
|
|
); |
504
|
|
|
|
505
|
|
|
// Did we find anything? If not, bail. |
506
|
|
|
if (empty($topics)) |
507
|
|
|
{ |
508
|
|
|
return array(); |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
$topic_list = array_keys($topics); |
512
|
|
|
|
513
|
|
|
// Count number of new posts per topic. |
514
|
|
|
if (User::$info->is_guest === false) |
|
|
|
|
515
|
|
|
{ |
516
|
|
|
$db->fetchQuery(' |
517
|
|
|
SELECT |
518
|
|
|
m.id_topic, COALESCE(lt.id_msg, lmr.id_msg, -2) + 1 AS new_from |
519
|
|
|
FROM {db_prefix}messages AS m |
520
|
|
|
LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = m.id_topic AND lt.id_member = {int:current_member}) |
521
|
|
|
LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = m.id_board AND lmr.id_member = {int:current_member}) |
522
|
|
|
WHERE |
523
|
|
|
m.id_topic IN ({array_int:topic_list}) |
524
|
|
|
AND (m.id_msg > COALESCE(lt.id_msg, lmr.id_msg, 0)) |
525
|
|
|
GROUP BY m.id_topic, lt.id_msg, lmr.id_msg', |
526
|
|
|
array( |
527
|
|
|
'current_member' => User::$info->id, |
|
|
|
|
528
|
|
|
'topic_list' => $topic_list |
529
|
|
|
) |
530
|
|
|
)->fetch_callback( |
531
|
|
|
static function ($row) use (&$topics) { |
532
|
|
|
$topics[$row['id_topic']] += $row; |
533
|
|
|
} |
534
|
|
|
); |
535
|
|
|
} |
536
|
|
|
|
537
|
|
|
// Find all the posts in distinct topics. Newer ones will have higher IDs. |
538
|
|
|
$request = $db->fetchQuery(' |
539
|
|
|
SELECT |
540
|
|
|
ml.poster_time, ml.id_member, ml.id_msg, ml.smileys_enabled, ml.icon, |
541
|
|
|
mf.subject, mf.id_member AS id_op_member, |
542
|
|
|
t.id_topic, t.num_replies, t.num_views, t.id_last_msg, t.id_first_msg, |
543
|
|
|
mg.online_color, |
544
|
|
|
COALESCE(mem.real_name, ml.poster_name) AS poster_name, |
545
|
|
|
COALESCE(memop.real_name, mf.poster_name) AS op_name, |
546
|
|
|
SUBSTRING(ml.body, 1, 384) AS body |
547
|
|
|
FROM {db_prefix}topics AS t |
548
|
|
|
INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) |
549
|
|
|
INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg) |
550
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ml.id_member) |
551
|
|
|
LEFT JOIN {db_prefix}members AS memop ON (memop.id_member = mf.id_member) |
552
|
|
|
LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = mem.id_group) |
553
|
|
|
WHERE t.id_topic IN ({array_int:topic_list})', |
554
|
|
|
array( |
555
|
|
|
'topic_list' => $topic_list |
556
|
|
|
) |
557
|
|
|
); |
558
|
|
|
$bbc_parser = ParserWrapper::instance(); |
559
|
|
|
$posts = array(); |
560
|
|
|
while (($row = $request->fetch_assoc())) |
561
|
|
|
{ |
562
|
|
|
$row['body'] = strip_tags(strtr($bbc_parser->parseMessage($row['body'], $row['smileys_enabled']), array('<br />' => ' '))); |
563
|
|
|
|
564
|
|
|
// Censor the subject and body. |
565
|
|
|
$row['subject'] = censor($row['subject']); |
566
|
|
|
$row['body'] = censor($row['body']); |
567
|
|
|
|
568
|
|
|
$row['body'] = Util::shorten_text($row['body'], 128); |
569
|
|
|
|
570
|
|
|
// Build the array. |
571
|
|
|
$posts[$row['id_last_msg']] = array( |
572
|
|
|
'board' => array( |
573
|
|
|
'id' => $topics[$row['id_topic']]['id_board'], |
574
|
|
|
'name' => $topics[$row['id_topic']]['board_name'], |
575
|
|
|
'href' => $scripturl . '?board=' . $topics[$row['id_topic']]['id_board'] . '.0', |
576
|
|
|
'link' => '<a href="' . $scripturl . '?board=' . $topics[$row['id_topic']]['id_board'] . '.0">' . $topics[$row['id_topic']]['board_name'] . '</a>', |
577
|
|
|
), |
578
|
|
|
'topic' => $row['id_topic'], |
579
|
|
|
'poster' => array( |
580
|
|
|
'id' => $row['id_member'], |
581
|
|
|
'name' => $row['poster_name'], |
582
|
|
|
'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], |
583
|
|
|
'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>' |
584
|
|
|
), |
585
|
|
|
'original_poster' => array( |
586
|
|
|
'id' => $row['id_op_member'], |
587
|
|
|
'name' => $row['op_name'], |
588
|
|
|
'href' => empty($row['id_op_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_op_member'], |
589
|
|
|
'link' => empty($row['id_op_member']) ? $row['op_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_op_member'] . '">' . $row['op_name'] . '</a>' |
590
|
|
|
), |
591
|
|
|
'subject' => $row['subject'], |
592
|
|
|
'replies' => $row['num_replies'], |
593
|
|
|
'views' => $row['num_views'], |
594
|
|
|
'short_subject' => Util::shorten_text($row['subject'], 25), |
595
|
|
|
'preview' => $row['body'], |
596
|
|
|
'time' => standardTime($row['poster_time']), |
597
|
|
|
'html_time' => htmlTime($row['poster_time']), |
598
|
|
|
'timestamp' => forum_time(true, $row['poster_time']), |
599
|
|
|
'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';topicseen#new', |
600
|
|
|
'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#new" rel="nofollow">' . $row['subject'] . '</a>', |
601
|
|
|
'is_new' => !empty($topics[$row['id_topic']]['new_from']), |
602
|
|
|
'new_from' => empty($topics[$row['id_topic']]['new_from']) ? 0 : $topics[$row['id_topic']]['new_from'], |
603
|
|
|
'icon' => '<img src="' . $icon_sources->getIconURL($row['icon']) . '" class="icon-middle" alt="' . $row['icon'] . '" />', |
604
|
|
|
); |
605
|
|
|
} |
606
|
|
|
|
607
|
|
|
$request->free_result(); |
608
|
|
|
krsort($posts); |
609
|
|
|
|
610
|
|
|
// Just return it. |
611
|
|
|
if ($output_method !== 'echo' || empty($posts)) |
612
|
|
|
{ |
613
|
|
|
return $posts; |
614
|
|
|
} |
615
|
|
|
|
616
|
|
|
echo ' |
617
|
|
|
<table class="ssi_table">'; |
618
|
|
|
|
619
|
|
|
foreach ($posts as $post) |
620
|
|
|
{ |
621
|
|
|
echo ' |
622
|
|
|
<tr> |
623
|
|
|
<td class="righttext top"> |
624
|
|
|
[', $post['board']['link'], '] |
625
|
|
|
</td> |
626
|
|
|
<td class="top"> |
627
|
|
|
<a href="', $post['href'], '">', $post['subject'], '</a> |
628
|
|
|
', $txt['by'], ' ', $post['poster']['link'], ' |
629
|
|
|
', $post['is_new'] ? '<a href="' . $scripturl . '?topic=' . $post['topic'] . '.msg' . $post['new_from'] . ';topicseen#new" rel="nofollow" class="new_posts">' . $txt['new'] . '</a>' : '', ' |
630
|
|
|
</td> |
631
|
|
|
<td class="righttext"> |
632
|
|
|
', $post['time'], ' |
633
|
|
|
</td> |
634
|
|
|
</tr>'; |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
echo ' |
638
|
|
|
</table>'; |
639
|
|
|
} |
640
|
|
|
|
641
|
|
|
/** |
642
|
|
|
* Show the top poster's name and profile link. |
643
|
|
|
* |
644
|
|
|
* @param int $topNumber How many top posters to list |
645
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', will display a list of |
646
|
|
|
* users, otherwise returns an array of info about them. |
647
|
|
|
*/ |
648
|
|
|
function ssi_topPoster($topNumber = 1, $output_method = 'echo') |
649
|
|
|
{ |
650
|
|
|
require_once(SUBSDIR . '/Stats.subs.php'); |
651
|
|
|
$top_posters = topPosters($topNumber); |
652
|
|
|
|
653
|
|
|
// Just return all the top posters. |
654
|
|
|
if ($output_method !== 'echo') |
655
|
|
|
{ |
656
|
|
|
return $top_posters; |
657
|
|
|
} |
658
|
|
|
|
659
|
|
|
// Make a quick array to list the links in. |
660
|
|
|
$temp_array = array(); |
661
|
|
|
foreach ($top_posters as $member) |
662
|
|
|
{ |
663
|
|
|
$temp_array[] = $member['link']; |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
echo implode(', ', $temp_array); |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
/** |
670
|
|
|
* Show boards by activity. |
671
|
|
|
* |
672
|
|
|
* @param int $num_top How many boards to display |
673
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a list of |
674
|
|
|
* boards, otherwise returns an array of info about them. |
675
|
|
|
*/ |
676
|
|
|
function ssi_topBoards($num_top = 10, $output_method = 'echo') |
677
|
|
|
{ |
678
|
|
|
global $txt; |
679
|
|
|
|
680
|
|
|
require_once(SUBSDIR . '/Stats.subs.php'); |
681
|
|
|
|
682
|
|
|
// Find boards with lots of posts. |
683
|
|
|
$boards = topBoards($num_top, true); |
684
|
|
|
|
685
|
|
|
foreach ($boards as $id => $board) |
686
|
|
|
{ |
687
|
|
|
$boards[$id]['new'] = empty($board['is_read']); |
688
|
|
|
} |
689
|
|
|
|
690
|
|
|
// If we shouldn't output or have nothing to output, just jump out. |
691
|
|
|
if ($output_method !== 'echo' || empty($boards)) |
692
|
|
|
{ |
693
|
|
|
return $boards; |
694
|
|
|
} |
695
|
|
|
|
696
|
|
|
echo ' |
697
|
|
|
<table class="ssi_table"> |
698
|
|
|
<tr> |
699
|
|
|
<th>', $txt['board'], '</th> |
700
|
|
|
<th class="centertext">', $txt['board_topics'], '</th> |
701
|
|
|
<th class="centertext">', $txt['posts'], '</th> |
702
|
|
|
</tr>'; |
703
|
|
|
|
704
|
|
|
foreach ($boards as $board) |
705
|
|
|
{ |
706
|
|
|
echo ' |
707
|
|
|
<tr> |
708
|
|
|
<td>', $board['new'] ? ' <a href="' . $board['href'] . '" class="new_posts">' . $txt['new'] . '</a> ' : '', $board['link'], '</td> |
709
|
|
|
<td class="centertext">', $board['num_topics'], '</td> |
710
|
|
|
<td class="centertext">', $board['num_posts'], '</td> |
711
|
|
|
</tr>'; |
712
|
|
|
} |
713
|
|
|
|
714
|
|
|
echo ' |
715
|
|
|
</table>'; |
716
|
|
|
} |
717
|
|
|
|
718
|
|
|
/** |
719
|
|
|
* Shows the top topics. |
720
|
|
|
* |
721
|
|
|
* @param string $type Can be one of type or replies |
722
|
|
|
* @param int $num_topics = 10, How many topics to display |
723
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a |
724
|
|
|
* list of topics, otherwise returns an array of info about them. |
725
|
|
|
*/ |
726
|
|
|
function ssi_topTopics($type = 'replies', $num_topics = 10, $output_method = 'echo') |
727
|
|
|
{ |
728
|
|
|
global $txt, $scripturl; |
729
|
|
|
|
730
|
|
|
require_once(SUBSDIR . '/Stats.subs.php'); |
731
|
|
|
|
732
|
|
|
$function = function_exists('topTopic' . ucfirst($type)) ? 'topTopic' . ucfirst($type) : 'topTopicReplies'; |
733
|
|
|
|
734
|
|
|
$topics = $function($num_topics); |
735
|
|
|
|
736
|
|
|
foreach ($topics as $topic_id => $row) |
737
|
|
|
{ |
738
|
|
|
$row['subject'] = censor($row['subject']); |
739
|
|
|
|
740
|
|
|
$topics[$topic_id]['href'] = $scripturl . '?topic=' . $row['id'] . '.0'; |
741
|
|
|
$topics[$topic_id]['link'] = '<a href="' . $scripturl . '?topic=' . $row['id'] . '.0">' . $row['subject'] . '</a>'; |
742
|
|
|
} |
743
|
|
|
|
744
|
|
|
if ($output_method !== 'echo' || empty($topics)) |
745
|
|
|
{ |
746
|
|
|
return $topics; |
747
|
|
|
} |
748
|
|
|
|
749
|
|
|
echo ' |
750
|
|
|
<table class="top_topic ssi_table"> |
751
|
|
|
<tr> |
752
|
|
|
<th class="link"></th> |
753
|
|
|
<th class="centertext views">', $txt['views'], '</th> |
754
|
|
|
<th class="centertext num_replies">', $txt['replies'], '</th> |
755
|
|
|
</tr>'; |
756
|
|
|
|
757
|
|
|
foreach ($topics as $topic) |
758
|
|
|
{ |
759
|
|
|
echo ' |
760
|
|
|
<tr> |
761
|
|
|
<td class="link"> |
762
|
|
|
', $topic['link'], ' |
763
|
|
|
</td> |
764
|
|
|
<td class="centertext views">', $topic['num_views'], '</td> |
765
|
|
|
<td class="centertext num_replies">', $topic['num_replies'], '</td> |
766
|
|
|
</tr>'; |
767
|
|
|
} |
768
|
|
|
|
769
|
|
|
echo ' |
770
|
|
|
</table>'; |
771
|
|
|
} |
772
|
|
|
|
773
|
|
|
/** |
774
|
|
|
* Shows the top topics, by replies. |
775
|
|
|
* |
776
|
|
|
* @param int $num_topics = 10, How many topics to show |
777
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a list of topics, |
778
|
|
|
* otherwise returns an array of info about them |
779
|
|
|
*/ |
780
|
|
|
function ssi_topTopicsReplies($num_topics = 10, $output_method = 'echo') |
781
|
|
|
{ |
782
|
|
|
return ssi_topTopics('replies', $num_topics, $output_method); |
783
|
|
|
} |
784
|
|
|
|
785
|
|
|
/** |
786
|
|
|
* Shows the top topics, by views. |
787
|
|
|
* |
788
|
|
|
* @param int $num_topics = 10, How many topics to show |
789
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a list of topics, |
790
|
|
|
* otherwise returns an array of info about them |
791
|
|
|
*/ |
792
|
|
|
function ssi_topTopicsViews($num_topics = 10, $output_method = 'echo') |
793
|
|
|
{ |
794
|
|
|
return ssi_topTopics('views', $num_topics, $output_method); |
795
|
|
|
} |
796
|
|
|
|
797
|
|
|
/** |
798
|
|
|
* Show a link to the latest member: |
799
|
|
|
* |
800
|
|
|
* - Please welcome, Someone, our latest member. |
801
|
|
|
* |
802
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', returns a string |
803
|
|
|
* with a link to the latest member's profile, otherwise returns an array of info about them. |
804
|
|
|
*/ |
805
|
|
|
function ssi_latestMember($output_method = 'echo') |
806
|
|
|
{ |
807
|
|
|
global $txt, $context; |
808
|
|
|
|
809
|
|
|
if ($output_method === 'echo') |
810
|
|
|
{ |
811
|
|
|
echo ' |
812
|
|
|
', sprintf($txt['welcome_newest_member'], $context['common_stats']['latest_member']['link']), '<br />'; |
813
|
|
|
} |
814
|
|
|
else |
815
|
|
|
{ |
816
|
|
|
return $context['common_stats']['latest_member']; |
817
|
|
|
} |
818
|
|
|
} |
819
|
|
|
|
820
|
|
|
/** |
821
|
|
|
* Fetch a random member |
822
|
|
|
* |
823
|
|
|
* @param string $random_type = '', if type set to 'day' will only change once a day! |
824
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a link to the member's |
825
|
|
|
* profile, otherwise returns an array of info about them. |
826
|
|
|
*/ |
827
|
|
|
function ssi_randomMember($random_type = '', $output_method = 'echo') |
828
|
|
|
{ |
829
|
|
|
global $modSettings; |
830
|
|
|
|
831
|
|
|
// If we're looking for something to stay the same each day then seed the generator. |
832
|
|
|
if ($random_type === 'day') |
833
|
|
|
{ |
834
|
|
|
// Set the seed to change only once per day. |
835
|
|
|
mt_srand(floor(time() / 86400)); |
|
|
|
|
836
|
|
|
} |
837
|
|
|
|
838
|
|
|
// Get the lowest ID we're interested in. |
839
|
|
|
$member_id = mt_rand(1, $modSettings['latestMember']); |
840
|
|
|
|
841
|
|
|
$result = ssi_queryMembers('member_greater_equal', $member_id, 1, 'id_member ASC', $output_method); |
842
|
|
|
|
843
|
|
|
// If we got nothing do the reverse - in case of unactivated members. |
844
|
|
|
if (empty($result)) |
845
|
|
|
{ |
846
|
|
|
$result = ssi_queryMembers('member_lesser_equal', $member_id, 1, 'id_member DESC', $output_method); |
847
|
|
|
} |
848
|
|
|
|
849
|
|
|
// Just to be sure put the random generator back to something... random. |
850
|
|
|
if ($random_type !== '') |
851
|
|
|
{ |
852
|
|
|
mt_srand(time()); |
853
|
|
|
} |
854
|
|
|
|
855
|
|
|
return $result; |
856
|
|
|
} |
857
|
|
|
|
858
|
|
|
/** |
859
|
|
|
* Fetch a specific member. |
860
|
|
|
* |
861
|
|
|
* @param int[] $member_ids = array() The IDs of the members to fetch |
862
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a |
863
|
|
|
* list of links to the members' profiles, otherwise returns an array of info about them. |
864
|
|
|
*/ |
865
|
|
|
function ssi_fetchMember($member_ids = array(), $output_method = 'echo') |
866
|
|
|
{ |
867
|
|
|
if (empty($member_ids)) |
868
|
|
|
{ |
869
|
|
|
return ''; |
870
|
|
|
} |
871
|
|
|
|
872
|
|
|
// Can have more than one member if you really want... |
873
|
|
|
$member_ids = is_array($member_ids) ? $member_ids : array($member_ids); |
|
|
|
|
874
|
|
|
|
875
|
|
|
// Then make the query and dump the data. |
876
|
|
|
return ssi_queryMembers('members', $member_ids, '', 'id_member', $output_method); |
877
|
|
|
} |
878
|
|
|
|
879
|
|
|
/** |
880
|
|
|
* Fetch all members in the specified group |
881
|
|
|
* |
882
|
|
|
* @param int|null $group_id The ID of the group to get members from |
883
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', returns a list of |
884
|
|
|
* group members, otherwise returns an array of info about them. |
885
|
|
|
*/ |
886
|
|
|
function ssi_fetchGroupMembers($group_id = null, $output_method = 'echo') |
887
|
|
|
{ |
888
|
|
|
if ($group_id === null) |
889
|
|
|
{ |
890
|
|
|
return false; |
891
|
|
|
} |
892
|
|
|
|
893
|
|
|
return ssi_queryMembers('group_list', is_array($group_id) ? $group_id : array($group_id), '', 'real_name', $output_method); |
|
|
|
|
894
|
|
|
} |
895
|
|
|
|
896
|
|
|
/** |
897
|
|
|
* Fetch some member data! |
898
|
|
|
* |
899
|
|
|
* - Gathers info about members based on the specified parameters. |
900
|
|
|
* - Used by other functions to eliminate duplication. |
901
|
|
|
* |
902
|
|
|
* @param string|null $query_where The info for the WHERE clause of the query |
903
|
|
|
* @param string|string[] $query_where_params The parameters for the WHERE clause |
904
|
|
|
* @param string|int $query_limit The number of rows to return or an empty string to return all |
905
|
|
|
* @param string $query_order The info for the ORDER BY clause of the query |
906
|
|
|
* @param string $output_method The output method. If 'echo', displays a list of members, |
907
|
|
|
* otherwise returns an array of info about them |
908
|
|
|
*/ |
909
|
|
|
function ssi_queryMembers($query_where = null, $query_where_params = array(), $query_limit = '', $query_order = 'id_member DESC', $output_method = 'echo') |
910
|
|
|
{ |
911
|
|
|
if ($query_where === null) |
912
|
|
|
{ |
913
|
|
|
return false; |
914
|
|
|
} |
915
|
|
|
|
916
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
917
|
|
|
$members_data = retrieveMemberData(array( |
918
|
|
|
$query_where => $query_where_params, |
919
|
|
|
'limit' => empty($query_limit) ? 10 : (int) $query_limit, |
920
|
|
|
'order_by' => $query_order, |
921
|
|
|
'activated_status' => 1, |
922
|
|
|
)); |
923
|
|
|
|
924
|
|
|
$members = array(); |
925
|
|
|
foreach ($members_data['member_info'] as $row) |
926
|
|
|
{ |
927
|
|
|
$members[] = $row['id']; |
928
|
|
|
} |
929
|
|
|
|
930
|
|
|
if (empty($members)) |
931
|
|
|
{ |
932
|
|
|
return array(); |
933
|
|
|
} |
934
|
|
|
|
935
|
|
|
// Load the members. |
936
|
|
|
MembersList::load($members); |
937
|
|
|
|
938
|
|
|
// Draw the table! |
939
|
|
|
if ($output_method === 'echo') |
940
|
|
|
{ |
941
|
|
|
echo ' |
942
|
|
|
<table class="ssi_table">'; |
943
|
|
|
} |
944
|
|
|
|
945
|
|
|
$query_members = array(); |
946
|
|
|
foreach ($members as $id) |
947
|
|
|
{ |
948
|
|
|
$member = MembersList::get($id); |
949
|
|
|
// Load their context data. |
950
|
|
|
if ($member->isEmpty()) |
951
|
|
|
{ |
952
|
|
|
continue; |
953
|
|
|
} |
954
|
|
|
|
955
|
|
|
$member->loadContext(); |
956
|
|
|
|
957
|
|
|
// Store this member's information. |
958
|
|
|
$query_members[$id] = $member; |
959
|
|
|
|
960
|
|
|
// Only do something if we're echo'ing. |
961
|
|
|
if ($output_method === 'echo') |
962
|
|
|
{ |
963
|
|
|
echo ' |
964
|
|
|
<tr> |
965
|
|
|
<td class="centertext"> |
966
|
|
|
', $query_members[$id]['link'], ' |
967
|
|
|
<br />', $query_members[$id]['avatar']['image'], ' |
968
|
|
|
</td> |
969
|
|
|
</tr>'; |
970
|
|
|
} |
971
|
|
|
} |
972
|
|
|
|
973
|
|
|
// End the table if appropriate. |
974
|
|
|
if ($output_method === 'echo') |
975
|
|
|
{ |
976
|
|
|
echo ' |
977
|
|
|
</table>'; |
978
|
|
|
} |
979
|
|
|
|
980
|
|
|
// Send back the data. |
981
|
|
|
return $query_members; |
982
|
|
|
} |
983
|
|
|
|
984
|
|
|
/** |
985
|
|
|
* Show some basic stats: |
986
|
|
|
* |
987
|
|
|
* - Total This: XXXX, etc. |
988
|
|
|
* |
989
|
|
|
* @param string $output_method The output method. If 'echo', displays the stats, |
990
|
|
|
* otherwise returns an array of info about them |
991
|
|
|
*/ |
992
|
|
|
function ssi_boardStats($output_method = 'echo') |
993
|
|
|
{ |
994
|
|
|
global $txt, $scripturl, $modSettings; |
995
|
|
|
|
996
|
|
|
if (!allowedTo('view_stats')) |
997
|
|
|
{ |
998
|
|
|
return false; |
999
|
|
|
} |
1000
|
|
|
|
1001
|
|
|
require_once(SUBSDIR . '/Boards.subs.php'); |
1002
|
|
|
require_once(SUBSDIR . '/Stats.subs.php'); |
1003
|
|
|
|
1004
|
|
|
$totals = array( |
1005
|
|
|
'members' => $modSettings['totalMembers'], |
1006
|
|
|
'posts' => $modSettings['totalMessages'], |
1007
|
|
|
'topics' => $modSettings['totalTopics'], |
1008
|
|
|
'boards' => countBoards(), |
1009
|
|
|
'categories' => numCategories(), |
1010
|
|
|
); |
1011
|
|
|
|
1012
|
|
|
if ($output_method !== 'echo') |
1013
|
|
|
{ |
1014
|
|
|
return $totals; |
1015
|
|
|
} |
1016
|
|
|
|
1017
|
|
|
echo ' |
1018
|
|
|
', $txt['total_members'], ': <a href="', $scripturl . '?action=memberlist">', comma_format($totals['members']), '</a><br /> |
1019
|
|
|
', $txt['total_posts'], ': ', comma_format($totals['posts']), '<br /> |
1020
|
|
|
', $txt['total_topics'], ': ', comma_format($totals['topics']), ' <br /> |
1021
|
|
|
', $txt['total_cats'], ': ', comma_format($totals['categories']), '<br /> |
1022
|
|
|
', $txt['total_boards'], ': ', comma_format($totals['boards']); |
1023
|
|
|
} |
1024
|
|
|
|
1025
|
|
|
/** |
1026
|
|
|
* Shows a list of online users: |
1027
|
|
|
* |
1028
|
|
|
* - YY Guests, ZZ Users and then a list... |
1029
|
|
|
* |
1030
|
|
|
* @param string $output_method The output method. If 'echo', displays the stats, |
1031
|
|
|
* otherwise returns an array of info about them |
1032
|
|
|
*/ |
1033
|
|
|
function ssi_whosOnline($output_method = 'echo') |
1034
|
|
|
{ |
1035
|
|
|
global $txt, $settings; |
1036
|
|
|
|
1037
|
|
|
require_once(SUBSDIR . '/MembersOnline.subs.php'); |
1038
|
|
|
$membersOnlineOptions = array( |
1039
|
|
|
'show_hidden' => allowedTo('moderate_forum'), |
1040
|
|
|
); |
1041
|
|
|
$return = getMembersOnlineStats($membersOnlineOptions); |
1042
|
|
|
|
1043
|
|
|
// Add some redundancy for backwards compatibility reasons. |
1044
|
|
|
if ($output_method !== 'echo') |
1045
|
|
|
{ |
1046
|
|
|
return $return + array( |
1047
|
|
|
'users' => $return['users_online'], |
1048
|
|
|
'guests' => $return['num_guests'], |
1049
|
|
|
'hidden' => $return['num_users_hidden'], |
1050
|
|
|
'buddies' => $return['num_buddies'], |
1051
|
|
|
'num_users' => $return['num_users_online'], |
1052
|
|
|
'total_users' => $return['num_users_online'] + $return['num_guests'], |
1053
|
|
|
); |
1054
|
|
|
} |
1055
|
|
|
|
1056
|
|
|
echo ' |
1057
|
|
|
', comma_format($return['num_guests']), ' ', $return['num_guests'] == 1 ? $txt['guest'] : $txt['guests'], ', ', comma_format($return['num_users_online']), ' ', $return['num_users_online'] == 1 ? $txt['user'] : $txt['users']; |
1058
|
|
|
|
1059
|
|
|
$bracketList = array(); |
1060
|
|
|
if (!empty(User::$info->buddies)) |
|
|
|
|
1061
|
|
|
{ |
1062
|
|
|
$bracketList[] = comma_format($return['num_buddies']) . ' ' . ($return['num_buddies'] == 1 ? $txt['buddy'] : $txt['buddies']); |
1063
|
|
|
} |
1064
|
|
|
|
1065
|
|
|
if (!empty($return['num_spiders'])) |
1066
|
|
|
{ |
1067
|
|
|
$bracketList[] = comma_format($return['num_spiders']) . ' ' . ($return['num_spiders'] == 1 ? $txt['spider'] : $txt['spiders']); |
1068
|
|
|
} |
1069
|
|
|
|
1070
|
|
|
if (!empty($return['num_users_hidden'])) |
1071
|
|
|
{ |
1072
|
|
|
$bracketList[] = comma_format($return['num_users_hidden']) . ' ' . $txt['hidden']; |
1073
|
|
|
} |
1074
|
|
|
|
1075
|
|
|
if (!empty($bracketList)) |
1076
|
|
|
{ |
1077
|
|
|
echo ' (' . implode(', ', $bracketList) . ')'; |
1078
|
|
|
} |
1079
|
|
|
|
1080
|
|
|
echo '<br /> |
1081
|
|
|
', implode(', ', $return['list_users_online']); |
1082
|
|
|
|
1083
|
|
|
// Showing membergroups? |
1084
|
|
|
if (empty($settings['show_group_key'])) |
1085
|
|
|
{ |
1086
|
|
|
return; |
1087
|
|
|
} |
1088
|
|
|
|
1089
|
|
|
if (empty($return['membergroups'])) |
1090
|
|
|
{ |
1091
|
|
|
return; |
1092
|
|
|
} |
1093
|
|
|
|
1094
|
|
|
echo '<br /> |
1095
|
|
|
[' . implode('] [', $return['membergroups']) . ']'; |
1096
|
|
|
} |
1097
|
|
|
|
1098
|
|
|
/** |
1099
|
|
|
* Just like whosOnline except it also logs the online presence. |
1100
|
|
|
* |
1101
|
|
|
* @param string $output_method The output method. If 'echo', displays the stats, |
1102
|
|
|
* otherwise returns an array of info about them |
1103
|
|
|
*/ |
1104
|
|
|
function ssi_logOnline($output_method = 'echo') |
1105
|
|
|
{ |
1106
|
|
|
writeLog(); |
1107
|
|
|
|
1108
|
|
|
if ($output_method !== 'echo') |
1109
|
|
|
{ |
1110
|
|
|
return ssi_whosOnline($output_method); |
1111
|
|
|
} |
1112
|
|
|
|
1113
|
|
|
ssi_whosOnline($output_method); |
1114
|
|
|
} |
1115
|
|
|
|
1116
|
|
|
/** |
1117
|
|
|
* Shows a login box. |
1118
|
|
|
* |
1119
|
|
|
* @param string $redirect_to = '' The URL to redirect the user to after they login |
1120
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo' and the user is a guest, displays a |
1121
|
|
|
* login box, otherwise returns whether the user is a guest |
1122
|
|
|
*/ |
1123
|
|
|
function ssi_login($redirect_to = '', $output_method = 'echo') |
1124
|
|
|
{ |
1125
|
|
|
global $scripturl, $txt, $modSettings, $context, $settings; |
1126
|
|
|
|
1127
|
|
|
if ($redirect_to !== '') |
1128
|
|
|
{ |
1129
|
|
|
$_SESSION['login_url'] = $redirect_to; |
1130
|
|
|
} |
1131
|
|
|
|
1132
|
|
|
if ($output_method !== 'echo' || User::$info->is_guest === false) |
|
|
|
|
1133
|
|
|
{ |
1134
|
|
|
return User::$info->is_guest; |
1135
|
|
|
} |
1136
|
|
|
|
1137
|
|
|
$context['default_username'] = isset($_POST['user']) ? preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_POST['user'], ENT_COMPAT, 'UTF-8')) : ''; |
1138
|
|
|
|
1139
|
|
|
echo ' |
1140
|
|
|
<form action="', $scripturl, '?action=login2" name="frmLogin" id="frmLogin" method="post" accept-charset="UTF-8"> |
1141
|
|
|
<div class="login centertext"> |
1142
|
|
|
<div class="well">'; |
1143
|
|
|
|
1144
|
|
|
// Did they make a mistake last time? |
1145
|
|
|
if (!empty($context['login_errors'])) |
1146
|
|
|
{ |
1147
|
|
|
echo ' |
1148
|
|
|
<p class="errorbox">', implode('<br />', $context['login_errors']), '</p><br />'; |
1149
|
|
|
} |
1150
|
|
|
|
1151
|
|
|
// Or perhaps there's some special description for this time? |
1152
|
|
|
if (isset($context['description'])) |
1153
|
|
|
{ |
1154
|
|
|
echo ' |
1155
|
|
|
<p class="description">', $context['description'], '</p>'; |
1156
|
|
|
} |
1157
|
|
|
|
1158
|
|
|
// Now just get the basic information - username, password, etc. |
1159
|
|
|
echo ' |
1160
|
|
|
<dl> |
1161
|
|
|
<dt>', $txt['username'], ':</dt> |
1162
|
|
|
<dd> |
1163
|
|
|
<input type="text" name="user" size="20" value="', $context['default_username'], '" class="input_text" autofocus="autofocus" autocomplete="username" placeholder="', $txt['username'], '" /> |
1164
|
|
|
</dd> |
1165
|
|
|
<dt>', $txt['password'], ':</dt> |
1166
|
|
|
<dd> |
1167
|
|
|
<input type="password" name="passwrd" value="" size="20" class="input_password" autocomplete="current-password" placeholder="', $txt['password'], '" /> |
1168
|
|
|
</dd> |
1169
|
|
|
</dl> |
1170
|
|
|
<input type="submit" value="', $txt['login'], '" /> |
1171
|
|
|
<p class="smalltext"> |
1172
|
|
|
<a href="', $scripturl, '?action=reminder">', $txt['forgot_your_password'], '</a> |
1173
|
|
|
</p> |
1174
|
|
|
<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" /> |
1175
|
|
|
<input type="hidden" name="', $context['login_token_var'], '" value="', $context['login_token'], '" /> |
1176
|
|
|
</div> |
1177
|
|
|
</div> |
1178
|
|
|
</form>'; |
1179
|
|
|
|
1180
|
|
|
// Focus on the correct input - username or password. |
1181
|
|
|
echo ' |
1182
|
|
|
<script> |
1183
|
|
|
document.forms.frmLogin.', isset($context['default_username']) && $context['default_username'] !== '' ? 'passwrd' : 'user', '.focus(); |
1184
|
|
|
</script>'; |
1185
|
|
|
} |
1186
|
|
|
|
1187
|
|
|
/** |
1188
|
|
|
* Show the most-voted-in poll. |
1189
|
|
|
* |
1190
|
|
|
* @param string $output_method = 'echo; The output method. If 'echo', displays the poll, |
1191
|
|
|
* otherwise returns an array of info about it |
1192
|
|
|
*/ |
1193
|
|
|
function ssi_topPoll($output_method = 'echo') |
1194
|
|
|
{ |
1195
|
|
|
// Just use recentPoll, no need to duplicate code... |
1196
|
|
|
return ssi_recentPoll(true, $output_method); |
1197
|
|
|
} |
1198
|
|
|
|
1199
|
|
|
/** |
1200
|
|
|
* Show the most recently posted poll. |
1201
|
|
|
* |
1202
|
|
|
* @param bool $topPollInstead = false Show the top poll (based on votes) instead of the most recent one |
1203
|
|
|
* @param string $output_method = string The output method. If 'echo', displays the poll, |
1204
|
|
|
* otherwise returns an array of info about it. |
1205
|
|
|
*/ |
1206
|
|
|
function ssi_recentPoll($topPollInstead = false, $output_method = 'echo') |
1207
|
|
|
{ |
1208
|
|
|
global $txt, $boardurl, $context, $modSettings; |
1209
|
|
|
|
1210
|
|
|
$boardsAllowed = array_intersect(boardsAllowedTo('poll_view'), boardsAllowedTo('poll_vote')); |
1211
|
|
|
|
1212
|
|
|
if (empty($boardsAllowed)) |
1213
|
|
|
{ |
1214
|
|
|
return array(); |
1215
|
|
|
} |
1216
|
|
|
|
1217
|
|
|
$db = database(); |
1218
|
|
|
|
1219
|
|
|
$row = $db->fetchQuery(' |
1220
|
|
|
SELECT |
1221
|
|
|
p.id_poll, p.question, t.id_topic, p.max_votes, p.guest_vote, p.hide_results, p.expire_time |
1222
|
|
|
FROM {db_prefix}polls AS p |
1223
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_poll = p.id_poll' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ') |
1224
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)' . ($topPollInstead ? ' |
1225
|
|
|
INNER JOIN {db_prefix}poll_choices AS pc ON (pc.id_poll = p.id_poll)' : '') . ' |
1226
|
|
|
LEFT JOIN {db_prefix}log_polls AS lp ON (lp.id_poll = p.id_poll |
1227
|
|
|
AND lp.id_member > {int:no_member} |
1228
|
|
|
AND lp.id_member = {int:current_member}) |
1229
|
|
|
WHERE p.voting_locked = {int:voting_opened} |
1230
|
|
|
AND (p.expire_time = {int:no_expiration} OR {int:current_time} < p.expire_time) |
1231
|
|
|
AND ' . (User::$info->is_guest ? 'p.guest_vote = {int:guest_vote_allowed}' : 'lp.id_choice IS NULL') . ' |
|
|
|
|
1232
|
|
|
AND {query_wanna_see_board}' . (in_array(0, $boardsAllowed) ? '' : ' |
1233
|
|
|
AND b.id_board IN ({array_int:boards_allowed_list})') . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' |
1234
|
|
|
AND b.id_board != {int:recycle_enable}' : '') . ' |
1235
|
|
|
ORDER BY ' . ($topPollInstead ? 'pc.votes' : 'p.id_poll') . ' DESC |
1236
|
|
|
LIMIT 1', |
1237
|
|
|
array( |
1238
|
|
|
'current_member' => User::$info->id, |
|
|
|
|
1239
|
|
|
'boards_allowed_list' => $boardsAllowed, |
1240
|
|
|
'is_approved' => 1, |
1241
|
|
|
'guest_vote_allowed' => 1, |
1242
|
|
|
'no_member' => 0, |
1243
|
|
|
'voting_opened' => 0, |
1244
|
|
|
'no_expiration' => 0, |
1245
|
|
|
'current_time' => time(), |
1246
|
|
|
'recycle_enable' => $modSettings['recycle_board'], |
1247
|
|
|
) |
1248
|
|
|
)->fetch_assoc(); |
1249
|
|
|
|
1250
|
|
|
// This user has voted on all the polls. |
1251
|
|
|
if (empty($row)) |
1252
|
|
|
{ |
1253
|
|
|
return array(); |
1254
|
|
|
} |
1255
|
|
|
|
1256
|
|
|
// If this is a guest who's voted we'll through ourselves to show poll to show the results. |
1257
|
|
|
if (User::$info->is_guest && (!$row['guest_vote'] || (isset($_COOKIE['guest_poll_vote']) && in_array($row['id_poll'], explode(',', $_COOKIE['guest_poll_vote']))))) |
1258
|
|
|
{ |
1259
|
|
|
return ssi_showPoll($row['id_topic'], $output_method); |
1260
|
|
|
} |
1261
|
|
|
|
1262
|
|
|
$request = $db->fetchQuery(' |
1263
|
|
|
SELECT |
1264
|
|
|
COUNT(DISTINCT id_member) |
1265
|
|
|
FROM {db_prefix}log_polls |
1266
|
|
|
WHERE id_poll = {int:current_poll}', |
1267
|
|
|
array( |
1268
|
|
|
'current_poll' => $row['id_poll'], |
1269
|
|
|
) |
1270
|
|
|
); |
1271
|
|
|
[$total] = $request->fetch_row(); |
1272
|
|
|
$request->free_result(); |
1273
|
|
|
|
1274
|
|
|
$options = array(); |
1275
|
|
|
$db->fetchQuery(' |
1276
|
|
|
SELECT |
1277
|
|
|
id_choice, label, votes |
1278
|
|
|
FROM {db_prefix}poll_choices |
1279
|
|
|
WHERE id_poll = {int:current_poll}', |
1280
|
|
|
array( |
1281
|
|
|
'current_poll' => $row['id_poll'], |
1282
|
|
|
) |
1283
|
|
|
)->fetch_callback( |
1284
|
|
|
static function ($rowChoice) use (&$options) { |
1285
|
|
|
$rowChoice['label'] = censor($rowChoice['label']); |
1286
|
|
|
$options[$rowChoice['id_choice']] = array($rowChoice['label'], $rowChoice['votes']); |
1287
|
|
|
} |
1288
|
|
|
); |
1289
|
|
|
|
1290
|
|
|
// Can they view it? |
1291
|
|
|
$is_expired = !empty($row['expire_time']) && $row['expire_time'] < time(); |
1292
|
|
|
$allow_view_results = allowedTo('moderate_board') || $row['hide_results'] == 0 || $is_expired; |
1293
|
|
|
|
1294
|
|
|
$return = array( |
1295
|
|
|
'id' => $row['id_poll'], |
1296
|
|
|
'image' => 'poll', |
1297
|
|
|
'question' => $row['question'], |
1298
|
|
|
'total_votes' => $total, |
1299
|
|
|
'is_locked' => false, |
1300
|
|
|
'topic' => $row['id_topic'], |
1301
|
|
|
'allow_view_results' => $allow_view_results, |
1302
|
|
|
'options' => array() |
1303
|
|
|
); |
1304
|
|
|
|
1305
|
|
|
$bbc_parser = ParserWrapper::instance(); |
1306
|
|
|
|
1307
|
|
|
// Calculate the percentages and bar lengths... |
1308
|
|
|
$divisor = $return['total_votes'] == 0 ? 1 : $return['total_votes']; |
1309
|
|
|
foreach ($options as $i => $option) |
1310
|
|
|
{ |
1311
|
|
|
$bar = floor(($option[1] * 100) / $divisor); |
1312
|
|
|
$barWide = $bar == 0 ? 1 : floor(($bar * 5) / 3); |
1313
|
|
|
$return['options'][$i] = array( |
1314
|
|
|
'id' => 'options-' . ($topPollInstead ? 'top-' : 'recent-') . $i, |
1315
|
|
|
'percent' => $bar, |
1316
|
|
|
'votes' => $option[1], /* Todo: gradient div will need some visual tweaking. Or replace with the current bar_ndt code from Poll.subs */ |
1317
|
|
|
'bar' => '<div class="poll_gradient" style="width: ' . $barWide . 'px;"></div>', |
1318
|
|
|
'option' => $bbc_parser->parsePoll($option[0]), |
1319
|
|
|
'vote_button' => '<input type="' . ($row['max_votes'] > 1 ? 'checkbox' : 'radio') . '" name="options[]" id="options-' . ($topPollInstead ? 'top-' : 'recent-') . $i . '" value="' . $i . '" class="input_' . ($row['max_votes'] > 1 ? 'check' : 'radio') . '" />' |
1320
|
|
|
); |
1321
|
|
|
} |
1322
|
|
|
|
1323
|
|
|
$return['allowed_warning'] = $row['max_votes'] > 1 ? sprintf($txt['poll_options6'], min(count($options), $row['max_votes'])) : ''; |
1324
|
|
|
|
1325
|
|
|
if ($output_method !== 'echo') |
1326
|
|
|
{ |
1327
|
|
|
return $return; |
1328
|
|
|
} |
1329
|
|
|
|
1330
|
|
|
if ($allow_view_results) |
1331
|
|
|
{ |
1332
|
|
|
echo ' |
1333
|
|
|
<form class="ssi_poll" action="', $boardurl, '/SSI.php?ssi_function=pollVote" method="post" accept-charset="UTF-8"> |
1334
|
|
|
<strong>', $return['question'], '</strong><br /> |
1335
|
|
|
', empty($return['allowed_warning']) ? '' : $return['allowed_warning'] . '<br />'; |
1336
|
|
|
|
1337
|
|
|
foreach ($return['options'] as $option) |
1338
|
|
|
{ |
1339
|
|
|
echo ' |
1340
|
|
|
<label for="', $option['id'], '">', $option['vote_button'], ' ', $option['option'], '</label><br />'; |
1341
|
|
|
} |
1342
|
|
|
|
1343
|
|
|
echo ' |
1344
|
|
|
<input type="submit" value="', $txt['poll_vote'], '" /> |
1345
|
|
|
<input type="hidden" name="poll" value="', $return['id'], '" /> |
1346
|
|
|
<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" /> |
1347
|
|
|
</form>'; |
1348
|
|
|
} |
1349
|
|
|
else |
1350
|
|
|
{ |
1351
|
|
|
echo $txt['poll_cannot_see']; |
1352
|
|
|
} |
1353
|
|
|
} |
1354
|
|
|
|
1355
|
|
|
/** |
1356
|
|
|
* Show a poll. |
1357
|
|
|
* |
1358
|
|
|
* - It is possible to use this function in combination with the template |
1359
|
|
|
* template_display_poll_above from Display.template.php, the only part missing |
1360
|
|
|
* is the definition of the poll moderation button array (see Display.controller.php |
1361
|
|
|
* for details). |
1362
|
|
|
* |
1363
|
|
|
* @param int|null $topicID = null The topic to show the poll from. If null, $_REQUEST['ssi_topic'] will |
1364
|
|
|
* be used instead. |
1365
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays the poll, otherwise |
1366
|
|
|
* returns an array of info about it. |
1367
|
|
|
*/ |
1368
|
|
|
function ssi_showPoll($topicID = null, $output_method = 'echo') |
1369
|
|
|
{ |
1370
|
|
|
global $txt, $context, $scripturl; |
1371
|
|
|
static $last_board = null; |
1372
|
|
|
|
1373
|
|
|
require_once(SUBSDIR . '/Poll.subs.php'); |
1374
|
|
|
require_once(SUBSDIR . '/Topic.subs.php'); |
1375
|
|
|
|
1376
|
|
|
$topicID = $topicID === null && isset($_REQUEST['ssi_topic']) ? (int) $_REQUEST['ssi_topic'] : (int) $topicID; |
1377
|
|
|
|
1378
|
|
|
if (empty($topicID)) |
1379
|
|
|
{ |
1380
|
|
|
return array(); |
1381
|
|
|
} |
1382
|
|
|
|
1383
|
|
|
// Get the topic starter information. |
1384
|
|
|
$topicinfo = getTopicInfo($topicID, 'starter'); |
1385
|
|
|
|
1386
|
|
|
$boards_can_poll = boardsAllowedTo('poll_view'); |
1387
|
|
|
|
1388
|
|
|
// If: |
1389
|
|
|
// - is not allowed to see poll in any board, |
1390
|
|
|
// - or: |
1391
|
|
|
// - is not allowed in the specific board, and |
1392
|
|
|
// - is not an admin |
1393
|
|
|
// fail |
1394
|
|
|
if (empty($boards_can_poll) || (!in_array($topicinfo['id_board'], $boards_can_poll) && !in_array(0, $boards_can_poll))) |
1395
|
|
|
{ |
1396
|
|
|
return array(); |
1397
|
|
|
} |
1398
|
|
|
|
1399
|
|
|
$context['user']['started'] = User::$info->id == $topicinfo['id_member'] && User::$info->is_guest === false; |
|
|
|
|
1400
|
|
|
|
1401
|
|
|
$poll_id = associatedPoll($topicID); |
1402
|
|
|
loadPollContext($poll_id); |
1403
|
|
|
|
1404
|
|
|
if (empty($context['poll'])) |
1405
|
|
|
{ |
1406
|
|
|
return array(); |
1407
|
|
|
} |
1408
|
|
|
|
1409
|
|
|
if ($output_method !== 'echo') |
1410
|
|
|
{ |
1411
|
|
|
return $context['poll']; |
1412
|
|
|
} |
1413
|
|
|
|
1414
|
|
|
echo ' |
1415
|
|
|
<div class="content" id="poll_options"> |
1416
|
|
|
<h4 id="pollquestion"> |
1417
|
|
|
', $context['poll']['question'], ' |
1418
|
|
|
</h4>'; |
1419
|
|
|
|
1420
|
|
|
if ($context['poll']['allow_vote']) |
1421
|
|
|
{ |
1422
|
|
|
echo ' |
1423
|
|
|
<form action="', $scripturl, '?action=poll;sa=vote;topic=', $context['current_topic'], '.', $context['start'], ';poll=', $context['poll']['id'], '" method="post" accept-charset="UTF-8">'; |
1424
|
|
|
|
1425
|
|
|
// Show a warning if they are allowed more than one option. |
1426
|
|
|
if ($context['poll']['allowed_warning']) |
1427
|
|
|
{ |
1428
|
|
|
echo ' |
1429
|
|
|
<p>', $context['poll']['allowed_warning'], '</p>'; |
1430
|
|
|
} |
1431
|
|
|
|
1432
|
|
|
echo ' |
1433
|
|
|
<ul class="options">'; |
1434
|
|
|
|
1435
|
|
|
// Show each option with its button - a radio likely. |
1436
|
|
|
foreach ($context['poll']['options'] as $option) |
1437
|
|
|
{ |
1438
|
|
|
echo ' |
1439
|
|
|
<li>', $option['vote_button'], ' <label for="', $option['id'], '">', $option['option'], '</label></li>'; |
1440
|
|
|
} |
1441
|
|
|
|
1442
|
|
|
echo ' |
1443
|
|
|
</ul> |
1444
|
|
|
<div class="submitbutton"> |
1445
|
|
|
<input type="submit" value="', $txt['poll_vote'], '" /> |
1446
|
|
|
<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" /> |
1447
|
|
|
</div> |
1448
|
|
|
</form>'; |
1449
|
|
|
|
1450
|
|
|
// Is the clock ticking? |
1451
|
|
|
if (!empty($context['poll']['expire_time'])) |
1452
|
|
|
{ |
1453
|
|
|
echo ' |
1454
|
|
|
<p><strong>', ($context['poll']['is_expired'] ? $txt['poll_expired_on'] : $txt['poll_expires_on']), ':</strong> ', $context['poll']['expire_time'], '</p>'; |
1455
|
|
|
} |
1456
|
|
|
|
1457
|
|
|
} |
1458
|
|
|
elseif ($context['poll']['allow_view_results']) |
1459
|
|
|
{ |
1460
|
|
|
echo ' |
1461
|
|
|
<ul class="options">'; |
1462
|
|
|
|
1463
|
|
|
// Show each option with its corresponding percentage bar. |
1464
|
|
|
foreach ($context['poll']['options'] as $option) |
1465
|
|
|
{ |
1466
|
|
|
echo ' |
1467
|
|
|
<li', $option['voted_this'] ? ' class="voted"' : '', '>', $option['option'], ' |
1468
|
|
|
<div class="results">'; |
1469
|
|
|
|
1470
|
|
|
if ($context['allow_poll_view']) |
1471
|
|
|
{ |
1472
|
|
|
echo ' |
1473
|
|
|
<div class="statsbar"> ', $option['bar_ndt'], '</div> |
1474
|
|
|
<span class="percentage">', $option['votes'], ' (', $option['percent'], '%)</span>'; |
1475
|
|
|
} |
1476
|
|
|
|
1477
|
|
|
echo ' |
1478
|
|
|
</div> |
1479
|
|
|
</li>'; |
1480
|
|
|
} |
1481
|
|
|
|
1482
|
|
|
echo ' |
1483
|
|
|
</ul>'; |
1484
|
|
|
|
1485
|
|
|
if ($context['allow_poll_view']) |
1486
|
|
|
{ |
1487
|
|
|
echo ' |
1488
|
|
|
<p><strong>', $txt['poll_total_voters'], ':</strong> ', $context['poll']['total_votes'], '</p>'; |
1489
|
|
|
} |
1490
|
|
|
|
1491
|
|
|
// Is the clock ticking? |
1492
|
|
|
if (!empty($context['poll']['expire_time'])) |
1493
|
|
|
{ |
1494
|
|
|
echo ' |
1495
|
|
|
<p><strong>', ($context['poll']['is_expired'] ? $txt['poll_expired_on'] : $txt['poll_expires_on']), ':</strong> ', $context['poll']['expire_time'], '</p>'; |
1496
|
|
|
} |
1497
|
|
|
} |
1498
|
|
|
// Cannot see it I'm afraid! |
1499
|
|
|
else |
1500
|
|
|
{ |
1501
|
|
|
echo $txt['poll_cannot_see']; |
1502
|
|
|
} |
1503
|
|
|
|
1504
|
|
|
echo ' |
1505
|
|
|
</div>'; |
1506
|
|
|
} |
1507
|
|
|
|
1508
|
|
|
/** |
1509
|
|
|
* Takes care of voting - don't worry, this is done automatically. |
1510
|
|
|
*/ |
1511
|
|
|
function ssi_pollVote() |
1512
|
|
|
{ |
1513
|
|
|
global $context, $topic, $board; |
1514
|
|
|
|
1515
|
|
|
$pollID = isset($_POST['poll']) ? (int) $_POST['poll'] : 0; |
1516
|
|
|
|
1517
|
|
|
if (empty($pollID) || !isset($_POST[$context['session_var']]) || $_POST[$context['session_var']] != $_SESSION['session_value'] || empty($_POST['options'])) |
1518
|
|
|
{ |
1519
|
|
|
echo '<!DOCTYPE html> |
1520
|
|
|
<html> |
1521
|
|
|
<head> |
1522
|
|
|
<script> |
1523
|
|
|
history.go(-1); |
1524
|
|
|
</script> |
1525
|
|
|
</head> |
1526
|
|
|
<body>«</body> |
1527
|
|
|
</html>'; |
1528
|
|
|
|
1529
|
|
|
return; |
1530
|
|
|
} |
1531
|
|
|
|
1532
|
|
|
require_once(SUBSDIR . '/Poll.subs.php'); |
1533
|
|
|
|
1534
|
|
|
// We have to fake we are in a topic so that we can use the proper controller |
1535
|
|
|
[$topic, $board] = topicFromPoll($pollID); |
1536
|
|
|
loadBoard(); |
1537
|
|
|
|
1538
|
|
|
$poll_action = new Poll(new EventManager()); |
1539
|
|
|
$poll_action->setUser(User::$info); |
1540
|
|
|
$poll_action->pre_dispatch(); |
1541
|
|
|
|
1542
|
|
|
// The controller takes already care of redirecting properly or fail |
1543
|
|
|
$poll_action->action_vote(); |
1544
|
|
|
} |
1545
|
|
|
|
1546
|
|
|
/** |
1547
|
|
|
* Show a search box. |
1548
|
|
|
* |
1549
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a search box, |
1550
|
|
|
* otherwise returns the URL of the search page. |
1551
|
|
|
*/ |
1552
|
|
|
function ssi_quickSearch($output_method = 'echo') |
1553
|
|
|
{ |
1554
|
|
|
global $scripturl, $txt; |
1555
|
|
|
|
1556
|
|
|
if (!allowedTo('search_posts')) |
1557
|
|
|
{ |
1558
|
|
|
return ''; |
1559
|
|
|
} |
1560
|
|
|
|
1561
|
|
|
if ($output_method !== 'echo') |
1562
|
|
|
{ |
1563
|
|
|
return $scripturl . '?action=search'; |
1564
|
|
|
} |
1565
|
|
|
|
1566
|
|
|
echo ' |
1567
|
|
|
<form action="', $scripturl, '?action=search;sa=results" method="post" accept-charset="UTF-8"> |
1568
|
|
|
<input type="hidden" name="advanced" value="0" /> |
1569
|
|
|
<input type="text" name="search" size="30" class="input_text" /> |
1570
|
|
|
<input type="submit" value="', $txt['search'], '" /> |
1571
|
|
|
</form>'; |
1572
|
|
|
} |
1573
|
|
|
|
1574
|
|
|
/** |
1575
|
|
|
* Show what would be the forum news. |
1576
|
|
|
* |
1577
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', shows the news item, otherwise returns it. |
1578
|
|
|
*/ |
1579
|
|
|
function ssi_news($output_method = 'echo') |
1580
|
|
|
{ |
1581
|
|
|
global $context; |
1582
|
|
|
|
1583
|
|
|
if ($output_method !== 'echo') |
1584
|
|
|
{ |
1585
|
|
|
return $context['random_news_line']; |
1586
|
|
|
} |
1587
|
|
|
|
1588
|
|
|
echo $context['random_news_line']; |
1589
|
|
|
} |
1590
|
|
|
|
1591
|
|
|
/** |
1592
|
|
|
* Show today's birthdays. |
1593
|
|
|
* |
1594
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a list of users, |
1595
|
|
|
* otherwise returns an array of info about them. |
1596
|
|
|
*/ |
1597
|
|
|
function ssi_todaysBirthdays($output_method = 'echo') |
1598
|
|
|
{ |
1599
|
|
|
global $scripturl, $modSettings; |
1600
|
|
|
|
1601
|
|
|
if (empty($modSettings['cal_enabled']) || !allowedTo('calendar_view') || !allowedTo('profile_view_any')) |
1602
|
|
|
{ |
1603
|
|
|
return ''; |
1604
|
|
|
} |
1605
|
|
|
|
1606
|
|
|
$eventOptions = array( |
1607
|
|
|
'include_birthdays' => true, |
1608
|
|
|
'num_days_shown' => empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index'], |
1609
|
|
|
); |
1610
|
|
|
$return = Cache::instance()->quick_get('calendar_index_offset_' . (User::$info->time_offset + $modSettings['time_offset']), 'subs/Calendar.subs.php', 'cache_getRecentEvents', array($eventOptions)); |
|
|
|
|
1611
|
|
|
|
1612
|
|
|
if ($output_method !== 'echo') |
1613
|
|
|
{ |
1614
|
|
|
return $return['calendar_birthdays']; |
1615
|
|
|
} |
1616
|
|
|
|
1617
|
|
|
foreach ($return['calendar_birthdays'] as $member) |
1618
|
|
|
{ |
1619
|
|
|
echo ' |
1620
|
|
|
<a href="', $scripturl, '?action=profile;u=', $member['id'], '">' . $member['name'] . (isset($member['age']) ? ' (' . $member['age'] . ')' : '') . '</a>' . ($member['is_last'] ? '' : ', '); |
1621
|
|
|
} |
1622
|
|
|
} |
1623
|
|
|
|
1624
|
|
|
/** |
1625
|
|
|
* Show today's holidays. |
1626
|
|
|
* |
1627
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a list of holidays, |
1628
|
|
|
* otherwise returns an array of info about them. |
1629
|
|
|
*/ |
1630
|
|
|
function ssi_todaysHolidays($output_method = 'echo') |
1631
|
|
|
{ |
1632
|
|
|
global $modSettings; |
1633
|
|
|
|
1634
|
|
|
if (empty($modSettings['cal_enabled']) || !allowedTo('calendar_view')) |
1635
|
|
|
{ |
1636
|
|
|
return false; |
1637
|
|
|
} |
1638
|
|
|
|
1639
|
|
|
$eventOptions = array( |
1640
|
|
|
'include_holidays' => true, |
1641
|
|
|
'num_days_shown' => empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index'], |
1642
|
|
|
); |
1643
|
|
|
$return = Cache::instance()->quick_get('calendar_index_offset_' . (User::$info->time_offset + $modSettings['time_offset']), 'subs/Calendar.subs.php', 'cache_getRecentEvents', array($eventOptions)); |
|
|
|
|
1644
|
|
|
|
1645
|
|
|
if ($output_method !== 'echo') |
1646
|
|
|
{ |
1647
|
|
|
return $return['calendar_holidays']; |
1648
|
|
|
} |
1649
|
|
|
|
1650
|
|
|
echo ' |
1651
|
|
|
', implode(', ', $return['calendar_holidays']); |
1652
|
|
|
} |
1653
|
|
|
|
1654
|
|
|
/** |
1655
|
|
|
* Show today's events. |
1656
|
|
|
* |
1657
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a list of events, |
1658
|
|
|
* otherwise returns an array of info about them. |
1659
|
|
|
*/ |
1660
|
|
|
function ssi_todaysEvents($output_method = 'echo') |
1661
|
|
|
{ |
1662
|
|
|
global $modSettings; |
1663
|
|
|
|
1664
|
|
|
if (empty($modSettings['cal_enabled']) || !allowedTo('calendar_view')) |
1665
|
|
|
{ |
1666
|
|
|
return false; |
1667
|
|
|
} |
1668
|
|
|
|
1669
|
|
|
$eventOptions = array( |
1670
|
|
|
'include_events' => true, |
1671
|
|
|
'num_days_shown' => empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index'], |
1672
|
|
|
); |
1673
|
|
|
$return = Cache::instance()->quick_get('calendar_index_offset_' . (User::$info->time_offset + $modSettings['time_offset']), 'subs/Calendar.subs.php', 'cache_getRecentEvents', array($eventOptions)); |
|
|
|
|
1674
|
|
|
|
1675
|
|
|
if ($output_method !== 'echo') |
1676
|
|
|
{ |
1677
|
|
|
return $return['calendar_events']; |
1678
|
|
|
} |
1679
|
|
|
|
1680
|
|
|
foreach ($return['calendar_events'] as $event) |
1681
|
|
|
{ |
1682
|
|
|
if ($event['can_edit']) |
1683
|
|
|
{ |
1684
|
|
|
echo ' |
1685
|
|
|
<a href="' . $event['modify_href'] . '" class="moderation_link">*</a> '; |
1686
|
|
|
} |
1687
|
|
|
|
1688
|
|
|
echo ' |
1689
|
|
|
' . $event['link'] . ($event['is_last'] ? '' : ', '); |
1690
|
|
|
} |
1691
|
|
|
} |
1692
|
|
|
|
1693
|
|
|
/** |
1694
|
|
|
* Show all calendar entries for today. (birthdays, holidays, and events.) |
1695
|
|
|
* |
1696
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a list of calendar |
1697
|
|
|
* items, otherwise returns an array of info about them. |
1698
|
|
|
*/ |
1699
|
|
|
function ssi_todaysCalendar($output_method = 'echo') |
1700
|
|
|
{ |
1701
|
|
|
global $modSettings, $txt, $scripturl; |
1702
|
|
|
|
1703
|
|
|
if (empty($modSettings['cal_enabled']) || !allowedTo('calendar_view')) |
1704
|
|
|
{ |
1705
|
|
|
return ''; |
1706
|
|
|
} |
1707
|
|
|
|
1708
|
|
|
$eventOptions = array( |
1709
|
|
|
'include_birthdays' => allowedTo('profile_view_any'), |
1710
|
|
|
'include_holidays' => true, |
1711
|
|
|
'include_events' => true, |
1712
|
|
|
'num_days_shown' => empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index'], |
1713
|
|
|
); |
1714
|
|
|
|
1715
|
|
|
$return = Cache::instance()->quick_get('calendar_index_offset_' . (User::$info->time_offset + $modSettings['time_offset']), 'subs/Calendar.subs.php', 'cache_getRecentEvents', array($eventOptions)); |
|
|
|
|
1716
|
|
|
|
1717
|
|
|
if ($output_method !== 'echo') |
1718
|
|
|
{ |
1719
|
|
|
return $return; |
1720
|
|
|
} |
1721
|
|
|
|
1722
|
|
|
if (!empty($return['calendar_holidays'])) |
1723
|
|
|
{ |
1724
|
|
|
echo ' |
1725
|
|
|
<span class="holiday">' . $txt['calendar_prompt'] . ' ' . implode(', ', $return['calendar_holidays']) . '<br /></span>'; |
1726
|
|
|
} |
1727
|
|
|
|
1728
|
|
|
if (!empty($return['calendar_birthdays'])) |
1729
|
|
|
{ |
1730
|
|
|
echo ' |
1731
|
|
|
<span class="birthday">' . $txt['birthdays_upcoming'] . '</span> '; |
1732
|
|
|
|
1733
|
|
|
foreach ($return['calendar_birthdays'] as $member) |
1734
|
|
|
{ |
1735
|
|
|
echo ' |
1736
|
|
|
<a href="', $scripturl, '?action=profile;u=', $member['id'], '">', $member['name'], isset($member['age']) ? ' (' . $member['age'] . ')' : '', '</a>', $member['is_last'] ? '' : ', '; |
1737
|
|
|
} |
1738
|
|
|
|
1739
|
|
|
echo ' |
1740
|
|
|
<br />'; |
1741
|
|
|
} |
1742
|
|
|
|
1743
|
|
|
if (!empty($return['calendar_events'])) |
1744
|
|
|
{ |
1745
|
|
|
echo ' |
1746
|
|
|
<span class="event">' . $txt['events_upcoming'] . '</span> '; |
1747
|
|
|
|
1748
|
|
|
foreach ($return['calendar_events'] as $event) |
1749
|
|
|
{ |
1750
|
|
|
if ($event['can_edit']) |
1751
|
|
|
{ |
1752
|
|
|
echo ' |
1753
|
|
|
<a href="' . $event['modify_href'] . '" class="moderation_link">*</a> '; |
1754
|
|
|
} |
1755
|
|
|
|
1756
|
|
|
echo ' |
1757
|
|
|
' . $event['link'] . ($event['is_last'] ? '' : ', '); |
1758
|
|
|
} |
1759
|
|
|
} |
1760
|
|
|
} |
1761
|
|
|
|
1762
|
|
|
/** |
1763
|
|
|
* Show the latest news, with a template... by board. |
1764
|
|
|
* |
1765
|
|
|
* @param int|null $board The ID of the board to get the info from. Defaults to $board or |
1766
|
|
|
* $_GET['board'] if not set. |
1767
|
|
|
* @param int|null $limit How many items to show. Defaults to $_GET['limit'] or 5 if not set. |
1768
|
|
|
* @param int|null $start Start with the specified item. Defaults to $_GET['start'] or 0 if not set. |
1769
|
|
|
* @param int|null $length How many characters to show from each post. Defaults to $_GET['length'] |
1770
|
|
|
* or 0 (no limit) if not set. |
1771
|
|
|
* @param string $preview = 'first' item to fetch, first or last |
1772
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays the news items, |
1773
|
|
|
* otherwise returns an array of info about them. |
1774
|
|
|
*/ |
1775
|
|
|
function ssi_boardNews($board = null, $limit = null, $start = null, $length = null, $preview = 'first', $output_method = 'echo') |
1776
|
|
|
{ |
1777
|
|
|
global $scripturl, $txt, $settings, $modSettings; |
1778
|
|
|
|
1779
|
|
|
\ElkArte\Languages\Txt::load('Stats'); |
1780
|
|
|
|
1781
|
|
|
$db = database(); |
1782
|
|
|
|
1783
|
|
|
// Must be integers.... |
1784
|
|
|
if ($limit === null) |
1785
|
|
|
{ |
1786
|
|
|
$limit = isset($_GET['limit']) ? (int) $_GET['limit'] : 5; |
1787
|
|
|
} |
1788
|
|
|
else |
1789
|
|
|
{ |
1790
|
|
|
$limit = (int) $limit; |
1791
|
|
|
} |
1792
|
|
|
|
1793
|
|
|
if ($start === null) |
1794
|
|
|
{ |
1795
|
|
|
$start = isset($_GET['start']) ? (int) $_GET['start'] : 0; |
1796
|
|
|
} |
1797
|
|
|
else |
1798
|
|
|
{ |
1799
|
|
|
$start = (int) $start; |
1800
|
|
|
} |
1801
|
|
|
|
1802
|
|
|
if ($board !== null) |
1803
|
|
|
{ |
1804
|
|
|
$board = (int) $board; |
1805
|
|
|
} |
1806
|
|
|
elseif (isset($_GET['board'])) |
1807
|
|
|
{ |
1808
|
|
|
$board = (int) $_GET['board']; |
1809
|
|
|
} |
1810
|
|
|
|
1811
|
|
|
if ($length === null) |
1812
|
|
|
{ |
1813
|
|
|
$length = isset($_GET['length']) ? (int) $_GET['length'] : 500; |
1814
|
|
|
} |
1815
|
|
|
else |
1816
|
|
|
{ |
1817
|
|
|
$length = (int) $length; |
1818
|
|
|
} |
1819
|
|
|
|
1820
|
|
|
$limit = max(0, $limit); |
1821
|
|
|
$start = max(0, $start); |
1822
|
|
|
|
1823
|
|
|
// Make sure guests can see this board. |
1824
|
|
|
$request = $db->query('', ' |
1825
|
|
|
SELECT |
1826
|
|
|
id_board |
1827
|
|
|
FROM {db_prefix}boards |
1828
|
|
|
WHERE ' . ($board === null ? '' : 'id_board = {int:current_board} |
1829
|
|
|
AND ') . 'FIND_IN_SET(-1, member_groups) != 0 |
1830
|
|
|
AND redirect = {string:blank_redirect} |
1831
|
|
|
LIMIT 1', |
1832
|
|
|
array( |
1833
|
|
|
'current_board' => $board, |
1834
|
|
|
'blank_redirect' => '', |
1835
|
|
|
) |
1836
|
|
|
); |
1837
|
|
|
if ($request->num_rows() === 0) |
1838
|
|
|
{ |
1839
|
|
|
if ($output_method === 'echo') |
1840
|
|
|
{ |
1841
|
|
|
die($txt['ssi_no_guests']); |
|
|
|
|
1842
|
|
|
} |
1843
|
|
|
|
1844
|
|
|
return array(); |
1845
|
|
|
} |
1846
|
|
|
|
1847
|
|
|
[$board] = $request->fetch_row(); |
1848
|
|
|
$request->free_result(); |
1849
|
|
|
|
1850
|
|
|
// Load the message icons - the usual suspects. |
1851
|
|
|
$icon_sources = new MessageTopicIcons(!empty($modSettings['messageIconChecks_enable']), $settings['theme_dir']); |
1852
|
|
|
|
1853
|
|
|
// Find the posts. |
1854
|
|
|
$indexOptions = array( |
1855
|
|
|
'only_approved' => true, |
1856
|
|
|
'include_sticky' => false, |
1857
|
|
|
'ascending' => false, |
1858
|
|
|
'include_avatars' => false, |
1859
|
|
|
'previews' => $length |
1860
|
|
|
); |
1861
|
|
|
|
1862
|
|
|
require_once(SUBSDIR . '/MessageIndex.subs.php'); |
1863
|
|
|
$topics_info = messageIndexTopics($board, 0, $start, $limit, 'first_post', 't.id_topic', $indexOptions); |
1864
|
|
|
|
1865
|
|
|
if (empty($topics_info)) |
1866
|
|
|
{ |
1867
|
|
|
return false; |
1868
|
|
|
} |
1869
|
|
|
|
1870
|
|
|
$bbc_parser = ParserWrapper::instance(); |
1871
|
|
|
|
1872
|
|
|
$return = array(); |
1873
|
|
|
foreach ($topics_info as $row) |
1874
|
|
|
{ |
1875
|
|
|
if (!isset($row[$preview . '_body'])) |
1876
|
|
|
{ |
1877
|
|
|
$preview = 'first'; |
1878
|
|
|
} |
1879
|
|
|
|
1880
|
|
|
$row['body'] = $row[$preview . '_body']; |
1881
|
|
|
$row['subject'] = $row[$preview . '_subject']; |
1882
|
|
|
$row['id_msg'] = $row['id_' . $preview . '_msg']; |
1883
|
|
|
$row['icon'] = $row[$preview . '_icon']; |
1884
|
|
|
$row['id_member'] = $row[$preview . '_id_member']; |
1885
|
|
|
$row['smileys_enabled'] = $row[$preview . '_smileys']; |
1886
|
|
|
$row['poster_time'] = $row[$preview . '_poster_time']; |
1887
|
|
|
$row['poster_name'] = $row[$preview . '_display_name']; |
1888
|
|
|
$row['body'] = $bbc_parser->parseMessage($row['body'], $row['smileys_enabled']); |
1889
|
|
|
|
1890
|
|
|
$row['subject'] = censor($row['subject']); |
1891
|
|
|
$row['body'] = censor($row['body']); |
1892
|
|
|
|
1893
|
|
|
$return[] = array( |
1894
|
|
|
'id' => $row['id_topic'], |
1895
|
|
|
'message_id' => $row['id_msg'], |
1896
|
|
|
'icon' => '<img src="' . $icon_sources->getIconURL($row['icon']) . '" alt="' . $row['icon'] . '" />', |
1897
|
|
|
'subject' => $row['subject'], |
1898
|
|
|
'time' => standardTime($row['poster_time']), |
1899
|
|
|
'html_time' => htmlTime($row['poster_time']), |
1900
|
|
|
'timestamp' => forum_time(true, $row['poster_time']), |
1901
|
|
|
'body' => $row['body'], |
1902
|
|
|
'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
1903
|
|
|
'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['num_replies'] . ' ' . ($row['num_replies'] == 1 ? $txt['ssi_comment'] : $txt['ssi_comments']) . '</a>', |
1904
|
|
|
'replies' => comma_format($row['num_replies']), |
1905
|
|
|
'comment_href' => empty($row['locked']) ? $scripturl . '?action=post;topic=' . $row['id_topic'] . '.' . $row['num_replies'] . ';last_msg=' . $row['id_last_msg'] : '', |
1906
|
|
|
'comment_link' => empty($row['locked']) ? '<a href="' . $scripturl . '?action=post;topic=' . $row['id_topic'] . '.' . $row['num_replies'] . ';last_msg=' . $row['id_last_msg'] . '">' . $txt['ssi_write_comment'] . '</a>' : '', |
1907
|
|
|
'new_comment' => empty($row['locked']) ? '<a href="' . $scripturl . '?action=post;topic=' . $row['id_topic'] . '.' . $row['num_replies'] . '">' . $txt['ssi_write_comment'] . '</a>' : '', |
1908
|
|
|
'poster' => array( |
1909
|
|
|
'id' => $row['id_member'], |
1910
|
|
|
'name' => $row['poster_name'], |
1911
|
|
|
'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], |
1912
|
|
|
'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>' |
1913
|
|
|
), |
1914
|
|
|
'locked' => !empty($row['locked']), |
1915
|
|
|
'is_last' => false |
1916
|
|
|
); |
1917
|
|
|
} |
1918
|
|
|
|
1919
|
|
|
$return[count($return) - 1]['is_last'] = true; |
1920
|
|
|
|
1921
|
|
|
if ($output_method !== 'echo') |
1922
|
|
|
{ |
1923
|
|
|
return $return; |
1924
|
|
|
} |
1925
|
|
|
|
1926
|
|
|
foreach ($return as $news) |
1927
|
|
|
{ |
1928
|
|
|
echo ' |
1929
|
|
|
<div class="news_item"> |
1930
|
|
|
<h3 class="news_header"> |
1931
|
|
|
', $news['icon'], ' |
1932
|
|
|
<a href="', $news['href'], '">', $news['subject'], '</a> |
1933
|
|
|
</h3> |
1934
|
|
|
<div class="news_timestamp">', $news['time'], ' ', $txt['by'], ' ', $news['poster']['link'], '</div> |
1935
|
|
|
<div class="news_body">', $news['body'], '</div> |
1936
|
|
|
', $news['link'], $news['locked'] ? '' : ' | ' . $news['comment_link'], ' |
1937
|
|
|
</div>'; |
1938
|
|
|
|
1939
|
|
|
if (!$news['is_last']) |
1940
|
|
|
{ |
1941
|
|
|
echo ' |
1942
|
|
|
<hr />'; |
1943
|
|
|
} |
1944
|
|
|
} |
1945
|
|
|
} |
1946
|
|
|
|
1947
|
|
|
/** |
1948
|
|
|
* Show the most recent events. |
1949
|
|
|
* |
1950
|
|
|
* @param int $max_events The maximum number of events to return |
1951
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays the events, |
1952
|
|
|
* otherwise returns an array of info about them. |
1953
|
|
|
*/ |
1954
|
|
|
function ssi_recentEvents($max_events = 7, $output_method = 'echo') |
1955
|
|
|
{ |
1956
|
|
|
global $modSettings, $txt; |
1957
|
|
|
|
1958
|
|
|
if (empty($modSettings['cal_enabled']) || !allowedTo('calendar_view')) |
1959
|
|
|
{ |
1960
|
|
|
return false; |
1961
|
|
|
} |
1962
|
|
|
|
1963
|
|
|
require_once(SUBSDIR . '/Calendar.subs.php'); |
1964
|
|
|
|
1965
|
|
|
// Find all events which are happening in the near future that the member can see. |
1966
|
|
|
$date = Util::strftime('%Y-%m-%d', forum_time(false)); |
1967
|
|
|
$events = getEventRange($date, $date, true, $max_events); |
1968
|
|
|
|
1969
|
|
|
$return = array(); |
1970
|
|
|
$duplicates = array(); |
1971
|
|
|
foreach ($events as $date => $day_events) |
1972
|
|
|
{ |
1973
|
|
|
foreach ($day_events as $row) |
1974
|
|
|
{ |
1975
|
|
|
// Check if we've already come by an event linked to this same topic with the same title... and don't display it if we have. |
1976
|
|
|
if (!empty($duplicates[$row['title'] . $row['id_topic']])) |
1977
|
|
|
{ |
1978
|
|
|
continue; |
1979
|
|
|
} |
1980
|
|
|
|
1981
|
|
|
$return[$date][] = $row; |
1982
|
|
|
|
1983
|
|
|
// Let's not show this one again, huh? |
1984
|
|
|
$duplicates[$row['title'] . $row['id_topic']] = true; |
1985
|
|
|
} |
1986
|
|
|
} |
1987
|
|
|
|
1988
|
|
|
foreach ($return as $mday => $array) |
1989
|
|
|
{ |
1990
|
|
|
$return[$mday][count($array) - 1]['is_last'] = true; |
1991
|
|
|
} |
1992
|
|
|
|
1993
|
|
|
if ($output_method !== 'echo' || empty($return)) |
1994
|
|
|
{ |
1995
|
|
|
return $return; |
1996
|
|
|
} |
1997
|
|
|
|
1998
|
|
|
// Well the output method is echo. |
1999
|
|
|
echo ' |
2000
|
|
|
<span class="event">' . $txt['events'] . '</span> '; |
2001
|
|
|
|
2002
|
|
|
foreach ($return as $array) |
2003
|
|
|
{ |
2004
|
|
|
foreach ($array as $event) |
2005
|
|
|
{ |
2006
|
|
|
if ($event['can_edit']) |
2007
|
|
|
{ |
2008
|
|
|
echo ' |
2009
|
|
|
<a href="' . $event['modify_href'] . '" class="moderation_link">*</a> '; |
2010
|
|
|
} |
2011
|
|
|
|
2012
|
|
|
echo ' |
2013
|
|
|
' . $event['link'] . ($event['is_last'] ? '' : ', '); |
2014
|
|
|
} |
2015
|
|
|
} |
2016
|
|
|
} |
2017
|
|
|
|
2018
|
|
|
/** |
2019
|
|
|
* Check the passed id_member/password. |
2020
|
|
|
* |
2021
|
|
|
* If $is_username is true, treats $id as a username. |
2022
|
|
|
* |
2023
|
|
|
* @param int|string|null $id The ID or username of a user |
2024
|
|
|
* @param string|null $password The password to check |
2025
|
|
|
* @param bool $is_username If true, treats $id as a username rather than a user ID |
2026
|
|
|
*/ |
2027
|
|
|
function ssi_checkPassword($id = null, $password = null, $is_username = false) |
2028
|
|
|
{ |
2029
|
|
|
// If $id is null, this was most likely called from a query string and should do nothing. |
2030
|
|
|
if ($id === null) |
2031
|
|
|
{ |
2032
|
|
|
return false; |
2033
|
|
|
} |
2034
|
|
|
|
2035
|
|
|
require_once(SUBSDIR . '/Auth.subs.php'); |
2036
|
|
|
|
2037
|
|
|
$member = loadExistingMember($id, !$is_username); |
2038
|
|
|
|
2039
|
|
|
return validateLoginPassword($password, $member['passwd'], $member['member_name']) && $member['is_activated'] == 1; |
2040
|
|
|
} |
2041
|
|
|
|
2042
|
|
|
/** |
2043
|
|
|
* We want to show the recent attachments outside of the forum. |
2044
|
|
|
* |
2045
|
|
|
* @param int $num_attachments = 10 How many to return |
2046
|
|
|
* @param string[] $attachment_ext = array() Only show attachments with the specified extensions |
2047
|
|
|
* @param string $output_method = 'echo' The output method. If 'echo', displays a table with links/info, |
2048
|
|
|
* otherwise returns an array with information about the attachments |
2049
|
|
|
*/ |
2050
|
|
|
function ssi_recentAttachments($num_attachments = 10, $attachment_ext = array(), $output_method = 'echo') |
2051
|
|
|
{ |
2052
|
|
|
global $modSettings, $scripturl, $txt; |
2053
|
|
|
|
2054
|
|
|
// We want to make sure that we only get attachments for boards that we can see *if* any. |
2055
|
|
|
$attachments_boards = boardsAllowedTo('view_attachments'); |
2056
|
|
|
|
2057
|
|
|
// No boards? Adios amigo. |
2058
|
|
|
if (empty($attachments_boards)) |
2059
|
|
|
{ |
2060
|
|
|
return array(); |
2061
|
|
|
} |
2062
|
|
|
|
2063
|
|
|
$db = database(); |
2064
|
|
|
|
2065
|
|
|
// Is it an array? |
2066
|
|
|
if (!is_array($attachment_ext)) |
|
|
|
|
2067
|
|
|
{ |
2068
|
|
|
$attachment_ext = array($attachment_ext); |
2069
|
|
|
} |
2070
|
|
|
|
2071
|
|
|
// Lets build the query. |
2072
|
|
|
$attachments = array(); |
2073
|
|
|
$db->fetchQuery(' |
2074
|
|
|
SELECT |
2075
|
|
|
att.id_attach, att.id_msg, att.filename, COALESCE(att.size, 0) AS filesize, att.downloads, mem.id_member, |
2076
|
|
|
COALESCE(mem.real_name, m.poster_name) AS poster_name, m.id_topic, m.subject, t.id_board, m.poster_time, |
2077
|
|
|
att.width, att.height' . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : ', COALESCE(thumb.id_attach, 0) AS id_thumb, thumb.width AS thumb_width, thumb.height AS thumb_height') . ' |
2078
|
|
|
FROM {db_prefix}attachments AS att |
2079
|
|
|
INNER JOIN {db_prefix}messages AS m ON (m.id_msg = att.id_msg) |
2080
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) |
2081
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)' . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : ' |
2082
|
|
|
LEFT JOIN {db_prefix}attachments AS thumb ON (thumb.id_attach = att.id_thumb)') . ' |
2083
|
|
|
WHERE att.attachment_type = 0' . ($attachments_boards === array(0) ? '' : ' |
2084
|
|
|
AND m.id_board IN ({array_int:boards_can_see})') . (empty($attachment_ext) ? '' : ' |
2085
|
|
|
AND att.fileext IN ({array_string:attachment_ext})') . |
2086
|
|
|
(!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
2087
|
|
|
AND t.approved = {int:is_approved} |
2088
|
|
|
AND m.approved = {int:is_approved} |
2089
|
|
|
AND att.approved = {int:is_approved}') . ' |
2090
|
|
|
ORDER BY att.id_attach DESC |
2091
|
|
|
LIMIT {int:num_attachments}', |
2092
|
|
|
array( |
2093
|
|
|
'boards_can_see' => $attachments_boards, |
2094
|
|
|
'attachment_ext' => $attachment_ext, |
2095
|
|
|
'num_attachments' => $num_attachments, |
2096
|
|
|
'is_approved' => 1, |
2097
|
|
|
) |
2098
|
|
|
)->fetch_callback( |
2099
|
|
|
static function ($row) use (&$attachments, $scripturl, $modSettings) { |
2100
|
|
|
// We have something. |
2101
|
|
|
$filename = preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($row['filename'], ENT_COMPAT, 'UTF-8')); |
2102
|
|
|
|
2103
|
|
|
// Is it an image? |
2104
|
|
|
$attachments[$row['id_attach']] = array( |
2105
|
|
|
'member' => array( |
2106
|
|
|
'id' => $row['id_member'], |
2107
|
|
|
'name' => $row['poster_name'], |
2108
|
|
|
'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>', |
2109
|
|
|
), |
2110
|
|
|
'file' => array( |
2111
|
|
|
'filename' => $filename, |
2112
|
|
|
'filesize' => byte_format($row['filesize']), |
2113
|
|
|
'downloads' => $row['downloads'], |
2114
|
|
|
'href' => $scripturl . '?action=dlattach;topic=' . $row['id_topic'] . '.0;attach=' . $row['id_attach'], |
2115
|
|
|
'link' => '<a href="' . $scripturl . '?action=dlattach;topic=' . $row['id_topic'] . '.0;attach=' . $row['id_attach'] . '"><i class="icon i-paperclip"><s>Attachement:</s></i> ' . $filename . '</a>', |
2116
|
|
|
'is_image' => !empty($row['width']) && !empty($row['height']) && !empty($modSettings['attachmentShowImages']), |
2117
|
|
|
), |
2118
|
|
|
'topic' => array( |
2119
|
|
|
'id' => $row['id_topic'], |
2120
|
|
|
'subject' => $row['subject'], |
2121
|
|
|
'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], |
2122
|
|
|
'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '">' . $row['subject'] . '</a>', |
2123
|
|
|
'time' => standardTime($row['poster_time']), |
2124
|
|
|
'html_time' => htmlTime($row['poster_time']), |
2125
|
|
|
'timestamp' => forum_time(true, $row['poster_time']), |
2126
|
|
|
), |
2127
|
|
|
); |
2128
|
|
|
|
2129
|
|
|
// Images. |
2130
|
|
|
if ($attachments[$row['id_attach']]['file']['is_image']) |
2131
|
|
|
{ |
2132
|
|
|
$id_thumb = empty($row['id_thumb']) ? $row['id_attach'] : $row['id_thumb']; |
2133
|
|
|
$attachments[$row['id_attach']]['file']['image'] = array( |
2134
|
|
|
'id' => $id_thumb, |
2135
|
|
|
'width' => $row['width'], |
2136
|
|
|
'height' => $row['height'], |
2137
|
|
|
'img' => '<img src="' . $scripturl . '?action=dlattach;topic=' . $row['id_topic'] . '.0;attach=' . $row['id_attach'] . ';image" alt="' . $filename . '" />', |
2138
|
|
|
'thumb' => '<img src="' . $scripturl . '?action=dlattach;topic=' . $row['id_topic'] . '.0;attach=' . $id_thumb . ';image" alt="' . $filename . '" />', |
2139
|
|
|
'href' => $scripturl . '?action=dlattach;topic=' . $row['id_topic'] . '.0;attach=' . $id_thumb . ';image', |
2140
|
|
|
'link' => '<a href="' . $scripturl . '?action=dlattach;topic=' . $row['id_topic'] . '.0;attach=' . $row['id_attach'] . ';image"><img src="' . $scripturl . '?action=dlattach;topic=' . $row['id_topic'] . '.0;attach=' . $id_thumb . ';image" alt="' . $filename . '" /></a>', |
2141
|
|
|
); |
2142
|
|
|
} |
2143
|
|
|
} |
2144
|
|
|
); |
2145
|
|
|
|
2146
|
|
|
// So you just want an array? Here you can have it. |
2147
|
|
|
if ($output_method === 'array' || empty($attachments)) |
2148
|
|
|
{ |
2149
|
|
|
return $attachments; |
2150
|
|
|
} |
2151
|
|
|
|
2152
|
|
|
// Give them the default. |
2153
|
|
|
echo ' |
2154
|
|
|
<table class="ssi_table"> |
2155
|
|
|
<tr> |
2156
|
|
|
<th>', $txt['file'], '</th> |
2157
|
|
|
<th>', $txt['posted_by'], '</th> |
2158
|
|
|
<th class="centertext">', $txt['downloads'], '</th> |
2159
|
|
|
<th>', $txt['filesize'], '</th> |
2160
|
|
|
</tr>'; |
2161
|
|
|
|
2162
|
|
|
foreach ($attachments as $attach) |
2163
|
|
|
{ |
2164
|
|
|
echo ' |
2165
|
|
|
<tr> |
2166
|
|
|
<td>', $attach['file']['link'], '</td> |
2167
|
|
|
<td>', $attach['member']['link'], '</td> |
2168
|
|
|
<td class="centertext">', $attach['file']['downloads'], '</td> |
2169
|
|
|
<td>', $attach['file']['filesize'], '</td> |
2170
|
|
|
</tr>'; |
2171
|
|
|
} |
2172
|
|
|
|
2173
|
|
|
echo ' |
2174
|
|
|
</table>'; |
2175
|
|
|
} |
2176
|
|
|
|