Issues (1697)

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

1
<?php
2
3
/**
4
 * This file contains a couple of functions for the latest posts on forum.
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * This file contains code covered by:
11
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
12
 *
13
 * @version 2.0 dev
14
 *
15
 */
16
17
use BBC\ParserWrapper;
18
use ElkArte\Helper\Util;
19
use ElkArte\User;
20
21
/**
22
 * Get the latest posts of a forum.
23
 *
24
 * @param array $latestPostOptions
25
 * @return array
26
 */
27
function getLastPosts($latestPostOptions)
28
{
29
	global $modSettings;
30
31
	$db = database();
32
33
	$posts = [];
34
	$bbc_parser = ParserWrapper::instance();
35
36
	// Find all the posts. Newer ones will have higher IDs. (assuming the last 20 * number are accessible...)
37
	// @todo SLOW This query is now slow, NEEDS to be fixed.  Maybe break into two?
38
	$db->fetchQuery('
39
		SELECT
40
			m.poster_time, m.subject, m.id_topic, m.id_member, m.id_msg,
41
			COALESCE(mem.real_name, m.poster_name) AS poster_name, t.id_board, b.name AS board_name,
42
			SUBSTRING(m.body, 1, 385) AS body, m.smileys_enabled, COALESCE(a.id_attach, 0) AS id_attach,
43
			a.filename, a.attachment_type, mem.avatar, mem.email_address
44
		FROM {db_prefix}messages AS m
45
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
46
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
47
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
48
			LEFT JOIN {db_prefix}attachments AS a ON (a.id_member = m.id_member)
49
		WHERE m.id_msg >= {int:likely_max_msg}' .
50
		(!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
51
			AND b.id_board != {int:recycle_board}' : '') . '
52
			AND {query_wanna_see_board}' . ($modSettings['postmod_active'] ? '
53
			AND t.approved = {int:is_approved}
54
			AND m.approved = {int:is_approved}' : '') . '
55
		ORDER BY m.id_msg DESC
56
		LIMIT ' . $latestPostOptions['number_posts'],
57
		[
58
			'likely_max_msg' => max(0, $modSettings['maxMsgID'] - 50 * $latestPostOptions['number_posts']),
59
			'recycle_board' => $modSettings['recycle_board'],
60
			'is_approved' => 1,
61
		]
62
	)->fetch_callback(
63
		function ($row) use (&$posts, $bbc_parser) {
64
			global $modSettings;
65
66
			// Censor the subject and post for the preview ;).
67
			$row['subject'] = censor($row['subject']);
68
			$row['body'] = censor($row['body']);
69
70
			$row['body'] = strip_tags(strtr($bbc_parser->parseMessage($row['body'], $row['smileys_enabled']), ['<br />' => '&#10;']));
71
			$row['body'] = Util::shorten_text($row['body'], !empty($modSettings['lastpost_preview_characters']) ? $modSettings['lastpost_preview_characters'] : 128, true);
72
73
			$board_href = getUrl('board', ['board' => $row['id_board'], 'start' => '0', 'name' => $row['board_name']]);
74
			$poster_href = getUrl('profile', ['action' => 'profile', 'u' => $row['id_member'], 'name' => $row['poster_name']]);
75
			$topic_href = getUrl('topic', ['topic' => $row['id_topic'], 'start' => 'msg' . $row['id_msg'], 'subject' => $row['subject'], 'topicseen']);
76
77
			// Build the array.
78
			$posts[] = [
79
				'board' => [
80
					'id' => $row['id_board'],
81
					'name' => $row['board_name'],
82
					'href' => $board_href,
83
					'link' => '<a href="' . $board_href . '">' . $row['board_name'] . '</a>'
84
				],
85
				'topic' => $row['id_topic'],
86
				'poster' => [
87
					'avatar' => determineAvatar($row),
88
					'id' => $row['id_member'],
89
					'name' => $row['poster_name'],
90
					'href' => empty($row['id_member']) ? '' : $poster_href,
91
					'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $poster_href . '">' . $row['poster_name'] . '</a>'
92
				],
93
				'subject' => $row['subject'],
94
				'short_subject' => Util::shorten_text($row['subject'], !empty($modSettings['subject_length']) ? $modSettings['subject_length'] : 32),
95
				'preview' => $row['body'],
96
				'time' => standardTime($row['poster_time']),
97
				'html_time' => htmlTime($row['poster_time']),
98
				'timestamp' => forum_time(true, $row['poster_time']),
99
				'raw_timestamp' => $row['poster_time'],
100
				'href' => $topic_href . '#msg' . $row['id_msg'],
101
				'link' => '<a href="' . $topic_href . '#msg' . $row['id_msg'] . '" rel="nofollow">' . $row['subject'] . '</a>'
102
			];
103
		}
104
	);
105
106
	return $posts;
107
}
108
109
/**
110
 * Callback-function for the cache for getLastPosts().
111
 *
112
 * @param array $latestPostOptions
113
 *
114
 * @return array
115
 */
116
function cache_getLastPosts($latestPostOptions)
117
{
118
	return [
119
		'data' => getLastPosts($latestPostOptions),
120
		'expires' => time() + 60,
121
		'post_retri_eval' => '
122
			foreach ($cache_block[\'data\'] as $k => $post)
123
			{
124
				$cache_block[\'data\'][$k] += array(
125
					\'time\' => standardTime($post[\'raw_timestamp\']),
126
					\'html_time\' => htmlTime($post[\'raw_timestamp\']),
127
					\'timestamp\' => $post[\'raw_timestamp\'],
128
				);
129
			}',
130
	];
131
}
132
133
/**
134
 * Formats data supplied into a form that can be used in the template
135
 *
136
 * @param array $messages
137
 * @param int $start
138
 *
139
 * @return array
140
 */
141
function prepareRecentPosts($messages, $start)
142 2
{
143
	global $modSettings;
144 2
145 2
	$counter = $start + 1;
146 2
	$posts = [];
147 2
	$board_ids = ['own' => [], 'any' => []];
148 2
	$bbc_parser = ParserWrapper::instance();
149
	foreach ($messages as $row)
150
	{
151 2
		// Censor everything.
152 2
		$row['body'] = censor($row['body']);
153
		$row['subject'] = censor($row['subject']);
154
155 2
		// BBC-atize the message.
156
		$row['body'] = $bbc_parser->parseMessage($row['body'], $row['smileys_enabled']);
157 2
158 2
		$board_href = getUrl('board', ['board' => $row['id_board'], 'start' => '0', 'name' => $row['bname']]);
159 2
		$topic_href = getUrl('topic', ['topic' => $row['id_topic'], 'start' => 'msg' . $row['id_msg'], 'subject' => $row['subject']]);
160 2
		$first_poster_href = getUrl('profile', ['action' => 'profile', 'u' => $row['first_id_member'], 'name' => $row['first_display_name']]);
161
		$poster_href = getUrl('profile', ['action' => 'profile', 'u' => $row['id_member'], 'name' => $row['poster_name']]);
162
163 2
		// And build the array.
164 2
		$posts[$row['id_msg']] = [
165 2
			'id' => $row['id_msg'],
166 2
			'counter' => $counter++,
167
			'category' => [
168 2
				'id' => $row['id_cat'],
169 2
				'name' => $row['cname'],
170 2
				'href' => getUrl('action', $modSettings['default_forum_action']) . '#c' . $row['id_cat'],
171 2
				'link' => '<a href="' . getUrl('action', $modSettings['default_forum_action']) . '#c' . $row['id_cat'] . '">' . $row['cname'] . '</a>'
172
			],
173
			'board' => [
174 2
				'id' => $row['id_board'],
175 2
				'name' => $row['bname'],
176 2
				'href' => $board_href,
177 2
				'link' => '<a href="' . $board_href . '">' . $row['bname'] . '</a>'
178
			],
179 2
			'topic' => $row['id_topic'],
180 2
			'href' => $topic_href . '#msg' . $row['id_msg'],
181 2
			'link' => '<a href="' . $topic_href . '#msg' . $row['id_msg'] . '" rel="nofollow">' . $row['subject'] . '</a>',
182 2
			'start' => $row['num_replies'],
183 2
			'subject' => $row['subject'],
184 2
			'time' => standardTime($row['poster_time']),
185 2
			'html_time' => htmlTime($row['poster_time']),
186 2
			'timestamp' => forum_time(true, $row['poster_time']),
187
			'first_poster' => [
188 2
				'id' => $row['first_id_member'],
189 2
				'name' => $row['first_display_name'],
190 2
				'href' => empty($row['first_id_member']) ? '' : $first_poster_href,
191 2
				'link' => empty($row['first_id_member']) ? $row['first_display_name'] : '<a href="' . $first_poster_href . '">' . $row['first_display_name'] . '</a>'
192
			],
193
			'poster' => [
194 2
				'id' => $row['id_member'],
195 2
				'name' => $row['poster_name'],
196 2
				'href' => empty($row['id_member']) ? '' : $poster_href,
197 2
				'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $poster_href . '">' . $row['poster_name'] . '</a>'
198
			],
199 2
			'body' => $row['body'],
200 2
			'message' => $row['body'],
201
			'tests' => [
202
				'can_reply' => false,
203
				'can_mark_notify' => false,
204
				'can_delete' => false,
205
			],
206 2
			'delete_possible' => ($row['id_first_msg'] != $row['id_msg'] || $row['id_last_msg'] == $row['id_msg']) && (empty($modSettings['edit_disable_time']) || $row['poster_time'] + $modSettings['edit_disable_time'] * 60 >= time()),
207
		];
208
209 2
		if (User::$info->id == $row['first_id_member'])
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
210
		{
211 2
			$board_ids['own'][$row['id_board']][] = $row['id_msg'];
212
		}
213 2
		$board_ids['any'][$row['id_board']][] = $row['id_msg'];
214
	}
215
216 2
	return [$posts, $board_ids];
217
}
218
219
/**
220
 * Return the earliest message a user can...see?
221
 */
222
function earliest_msg()
223
{
224
	global $board;
225
226
	$db = database();
227
228
	if (!empty($board))
229
	{
230
		$request = $db->query('', '
231
			SELECT 
232
				MIN(id_msg)
233
			FROM {db_prefix}log_mark_read
234
			WHERE id_member = {int:current_member}
235
				AND id_board = {int:current_board}',
236
			[
237
				'current_board' => $board,
238
				'current_member' => User::$info->id,
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
239
			]
240
		);
241
		list ($earliest_msg) = $request->fetch_row();
242
		$request->free_result();
243
	}
244
	else
245
	{
246
		$request = $db->query('', '
247
			SELECT 
248
				MIN(lmr.id_msg)
249
			FROM {db_prefix}boards AS b
250
				LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = b.id_board AND lmr.id_member = {int:current_member})
251
			WHERE {query_see_board}',
252
			[
253
				'current_member' => User::$info->id,
254
			]
255
		);
256
		list ($earliest_msg) = $request->fetch_row();
257
		$request->free_result();
258
	}
259
260
	// This is needed in case of topics marked unread.
261
	if (empty($earliest_msg))
262
	{
263
		$earliest_msg = 0;
264
	}
265
	else
266
	{
267
		// Using caching, when possible, to ignore the below slow query.
268
		if (isset($_SESSION['cached_log_time']) && $_SESSION['cached_log_time'][0] + 45 > time())
269
		{
270
			$earliest_msg2 = $_SESSION['cached_log_time'][1];
271
		}
272
		else
273
		{
274
			// This query is pretty slow, but it's needed to ensure nothing crucial is ignored.
275
			$request = $db->query('', '
276
				SELECT 
277
					MIN(id_msg)
278
				FROM {db_prefix}log_topics
279
				WHERE id_member = {int:current_member}',
280
				[
281
					'current_member' => User::$info->id,
282
				]
283
			);
284
			list ($earliest_msg2) = $request->fetch_row();
285
			$request->free_result();
286
287
			// In theory this could be zero, if the first ever post is unread, so fudge it ;)
288
			if ($earliest_msg2 == 0)
289
			{
290
				$earliest_msg2 = -1;
291
			}
292
293
			$_SESSION['cached_log_time'] = [time(), $earliest_msg2];
294
		}
295
296
		$earliest_msg = min($earliest_msg2, $earliest_msg);
297
	}
298
299
	return $earliest_msg;
300
}
301
302
/**
303
 * Callback-function for the cache for getLastTopics().
304
 *
305
 * @param array $latestTopicOptions
306
 *
307
 * @return array
308
 */
309
function cache_getLastTopics($latestTopicOptions)
310
{
311
	return [
312
		'data' => getLastTopics($latestTopicOptions),
313
		'expires' => time() + 60,
314
		'post_retri_eval' => '
315
			foreach ($cache_block[\'data\'] as $k => $post)
316
			{
317
				$cache_block[\'data\'][$k] += array(
318
					\'time\' => standardTime($post[\'raw_timestamp\']),
319
					\'html_time\' => htmlTime($post[\'raw_timestamp\']),
320
					\'timestamp\' => $post[\'raw_timestamp\'],
321
				);
322
			}',
323
	];
324
}
325
326
/**
327
 * Get the latest posts of a forum.
328
 *
329
 * @param array $latestTopicOptions
330
 * @return array
331
 */
332
function getLastTopics($latestTopicOptions)
333
{
334
	global $modSettings;
335
336
	$db = database();
337
338
	$posts = [];
339
	$bbc_parser = ParserWrapper::instance();
340
341
	// Find all the posts. Newer ones will have higher IDs. (assuming the last 20 * number are accessible...)
342
	// @todo SLOW This query is now slow, NEEDS to be fixed.  Maybe break into two?
343
	$db->fetchQuery('
344
		SELECT
345
			ml.poster_time, mf.subject, ml.id_topic, ml.id_member, ml.id_msg, t.id_first_msg, ml.id_msg_modified,
346
			' . ($latestTopicOptions['id_member'] == 0 ? '0' : 'COALESCE(lt.id_msg, lmr.id_msg, -1) + 1') . ' AS new_from,
347
			COALESCE(mem.real_name, ml.poster_name) AS poster_name, t.id_board, b.name AS board_name,
348
			SUBSTRING(ml.body, 1, 385) AS body, ml.smileys_enabled, COALESCE(a.id_attach, 0) AS id_attach,
349
			a.filename, a.attachment_type, mem.avatar, mem.email_address
350
		FROM {db_prefix}topics AS t
351
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
352
			LEFT JOIN {db_prefix}messages AS mf ON (t.id_first_msg = mf.id_msg)
353
			LEFT JOIN {db_prefix}messages AS ml ON (t.id_last_msg = ml.id_msg)
354
			LEFT JOIN {db_prefix}attachments AS a ON (a.id_member = ml.id_member)
355
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ml.id_member)' . ($latestTopicOptions['id_member'] == 0 ? '' : '
356
			LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
357
			LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})') . '
358
		WHERE ml.id_msg >= {int:likely_max_msg}' .
359
		(!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
360
			AND b.id_board != {int:recycle_board}' : '') . '
361
			AND {query_wanna_see_board}' . ($modSettings['postmod_active'] ? '
362
			AND t.approved = {int:is_approved}' : '') . '
363
		ORDER BY t.id_last_msg DESC
364
		LIMIT {int:num_msgs}',
365
		[
366
			'likely_max_msg' => max(0, $modSettings['maxMsgID'] - 50 * $latestTopicOptions['number_posts']),
367
			'recycle_board' => $modSettings['recycle_board'],
368
			'is_approved' => 1,
369
			'num_msgs' => $latestTopicOptions['number_posts'],
370
			'current_member' => $latestTopicOptions['id_member'],
371
		]
372
	)->fetch_callback(
373
		function ($row) use (&$posts, $bbc_parser) {
374
			global $modSettings, $txt;
375
376
			// Censor the subject and post for the preview ;).
377
			$row['subject'] = censor($row['subject']);
378
			$row['body'] = censor($row['body']);
379
380
			$row['body'] = strip_tags(strtr($bbc_parser->parseMessage($row['body'], $row['smileys_enabled']), ['<br />' => '&#10;']));
381
			$row['body'] = Util::shorten_text($row['body'], !empty($modSettings['lastpost_preview_characters']) ? $modSettings['lastpost_preview_characters'] : 128, true);
382
383
			$board_href = getUrl('board', ['board' => $row['id_board'], 'start' => '0', 'name' => $row['board_name']]);
384
			$poster_href = getUrl('profile', ['action' => 'profile', 'u' => $row['id_member'], 'name' => $row['poster_name']]);
385
			$topic_href = getUrl('topic', ['topic' => $row['id_topic'], 'start' => 'msg' . $row['id_msg'], 'subject' => $row['subject'], 'topicseen']);
386
387
			// Build the array.
388
			$post = [
389
				'board' => [
390
					'id' => $row['id_board'],
391
					'name' => $row['board_name'],
392
					'href' => $board_href,
393
					'link' => '<a href="' . $board_href . '">' . $row['board_name'] . '</a>'
394
				],
395
				'topic' => $row['id_topic'],
396
				'poster' => [
397
					'avatar' => determineAvatar($row),
398
					'id' => $row['id_member'],
399
					'name' => $row['poster_name'],
400
					'href' => empty($row['id_member']) ? '' : $poster_href,
401
					'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $poster_href . '">' . $row['poster_name'] . '</a>'
402
				],
403
				'subject' => $row['subject'],
404
				'short_subject' => Util::shorten_text($row['subject'], !empty($modSettings['subject_length']) ? $modSettings['subject_length'] : 32),
405
				'preview' => $row['body'],
406
				'time' => standardTime($row['poster_time']),
407
				'html_time' => htmlTime($row['poster_time']),
408
				'timestamp' => forum_time(true, $row['poster_time']),
409
				'raw_timestamp' => $row['poster_time'],
410
				'href' => $topic_href . '#msg' . $row['id_msg'],
411
				'link' => '<a href="' . $topic_href . '#msg' . $row['id_msg'] . '" rel="nofollow">' . $row['subject'] . '</a>',
412
				'new' => $row['new_from'] <= $row['id_msg_modified'],
413
				'new_from' => $row['new_from'],
414
				'newtime' => $row['new_from'],
415
				'new_href' => getUrl('topic', ['topic' => $row['id_topic'], 'start' => 'msg' . $row['new_from'], 'subject' => $row['subject']]) . '#new',
416
			];
417
418
			if ($post['new'])
419
			{
420
				$post['link'] .= '
421
							<a class="new_posts" href="' . $post['new_href'] . '" id="newicon' . $row['id_msg'] . '">' . $txt['new'] . '</a>';
422
			}
423
424
			$posts[] = $post;
425
		}
426
	);
427
428
	return $posts;
429
}
430