PageRenderTime 58ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/phpBB/viewtopic.php

https://github.com/Jipem/phpbb
PHP | 2061 lines | 1508 code | 299 blank | 254 comment | 435 complexity | 44db9c9049fb449d6185e2de68a997dc MD5 | raw file
Possible License(s): AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. *
  4. * This file is part of the phpBB Forum Software package.
  5. *
  6. * @copyright (c) phpBB Limited <https://www.phpbb.com>
  7. * @license GNU General Public License, version 2 (GPL-2.0)
  8. *
  9. * For full copyright and license information, please see
  10. * the docs/CREDITS.txt file.
  11. *
  12. */
  13. /**
  14. * @ignore
  15. */
  16. define('IN_PHPBB', true);
  17. $phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
  18. $phpEx = substr(strrchr(__FILE__, '.'), 1);
  19. include($phpbb_root_path . 'common.' . $phpEx);
  20. include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
  21. include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
  22. include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
  23. // Start session management
  24. $user->session_begin();
  25. $auth->acl($user->data);
  26. // Initial var setup
  27. $forum_id = request_var('f', 0);
  28. $topic_id = request_var('t', 0);
  29. $post_id = request_var('p', 0);
  30. $voted_id = request_var('vote_id', array('' => 0));
  31. $voted_id = (sizeof($voted_id) > 1) ? array_unique($voted_id) : $voted_id;
  32. $start = request_var('start', 0);
  33. $view = request_var('view', '');
  34. $default_sort_days = (!empty($user->data['user_post_show_days'])) ? $user->data['user_post_show_days'] : 0;
  35. $default_sort_key = (!empty($user->data['user_post_sortby_type'])) ? $user->data['user_post_sortby_type'] : 't';
  36. $default_sort_dir = (!empty($user->data['user_post_sortby_dir'])) ? $user->data['user_post_sortby_dir'] : 'a';
  37. $sort_days = request_var('st', $default_sort_days);
  38. $sort_key = request_var('sk', $default_sort_key);
  39. $sort_dir = request_var('sd', $default_sort_dir);
  40. $update = request_var('update', false);
  41. $pagination = $phpbb_container->get('pagination');
  42. $s_can_vote = false;
  43. /**
  44. * @todo normalize?
  45. */
  46. $hilit_words = request_var('hilit', '', true);
  47. // Do we have a topic or post id?
  48. if (!$topic_id && !$post_id)
  49. {
  50. trigger_error('NO_TOPIC');
  51. }
  52. $phpbb_content_visibility = $phpbb_container->get('content.visibility');
  53. // Find topic id if user requested a newer or older topic
  54. if ($view && !$post_id)
  55. {
  56. if (!$forum_id)
  57. {
  58. $sql = 'SELECT forum_id
  59. FROM ' . TOPICS_TABLE . "
  60. WHERE topic_id = $topic_id";
  61. $result = $db->sql_query($sql);
  62. $forum_id = (int) $db->sql_fetchfield('forum_id');
  63. $db->sql_freeresult($result);
  64. if (!$forum_id)
  65. {
  66. trigger_error('NO_TOPIC');
  67. }
  68. }
  69. if ($view == 'unread')
  70. {
  71. // Get topic tracking info
  72. $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id);
  73. $topic_last_read = (isset($topic_tracking_info[$topic_id])) ? $topic_tracking_info[$topic_id] : 0;
  74. $sql = 'SELECT post_id, topic_id, forum_id
  75. FROM ' . POSTS_TABLE . "
  76. WHERE topic_id = $topic_id
  77. AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . "
  78. AND post_time > $topic_last_read
  79. AND forum_id = $forum_id
  80. ORDER BY post_time ASC";
  81. $result = $db->sql_query_limit($sql, 1);
  82. $row = $db->sql_fetchrow($result);
  83. $db->sql_freeresult($result);
  84. if (!$row)
  85. {
  86. $sql = 'SELECT topic_last_post_id as post_id, topic_id, forum_id
  87. FROM ' . TOPICS_TABLE . '
  88. WHERE topic_id = ' . $topic_id;
  89. $result = $db->sql_query($sql);
  90. $row = $db->sql_fetchrow($result);
  91. $db->sql_freeresult($result);
  92. }
  93. if (!$row)
  94. {
  95. // Setup user environment so we can process lang string
  96. $user->setup('viewtopic');
  97. trigger_error('NO_TOPIC');
  98. }
  99. $post_id = $row['post_id'];
  100. $topic_id = $row['topic_id'];
  101. }
  102. else if ($view == 'next' || $view == 'previous')
  103. {
  104. $sql_condition = ($view == 'next') ? '>' : '<';
  105. $sql_ordering = ($view == 'next') ? 'ASC' : 'DESC';
  106. $sql = 'SELECT forum_id, topic_last_post_time
  107. FROM ' . TOPICS_TABLE . '
  108. WHERE topic_id = ' . $topic_id;
  109. $result = $db->sql_query($sql);
  110. $row = $db->sql_fetchrow($result);
  111. $db->sql_freeresult($result);
  112. if (!$row)
  113. {
  114. $user->setup('viewtopic');
  115. // OK, the topic doesn't exist. This error message is not helpful, but technically correct.
  116. trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS');
  117. }
  118. else
  119. {
  120. $sql = 'SELECT topic_id, forum_id
  121. FROM ' . TOPICS_TABLE . '
  122. WHERE forum_id = ' . $row['forum_id'] . "
  123. AND topic_moved_id = 0
  124. AND topic_last_post_time $sql_condition {$row['topic_last_post_time']}
  125. AND " . $phpbb_content_visibility->get_visibility_sql('topic', $row['forum_id']) . "
  126. ORDER BY topic_last_post_time $sql_ordering";
  127. $result = $db->sql_query_limit($sql, 1);
  128. $row = $db->sql_fetchrow($result);
  129. $db->sql_freeresult($result);
  130. if (!$row)
  131. {
  132. $sql = 'SELECT forum_style
  133. FROM ' . FORUMS_TABLE . "
  134. WHERE forum_id = $forum_id";
  135. $result = $db->sql_query($sql);
  136. $forum_style = (int) $db->sql_fetchfield('forum_style');
  137. $db->sql_freeresult($result);
  138. $user->setup('viewtopic', $forum_style);
  139. trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS');
  140. }
  141. else
  142. {
  143. $topic_id = $row['topic_id'];
  144. $forum_id = $row['forum_id'];
  145. }
  146. }
  147. }
  148. if (isset($row) && $row['forum_id'])
  149. {
  150. $forum_id = $row['forum_id'];
  151. }
  152. }
  153. // This rather complex gaggle of code handles querying for topics but
  154. // also allows for direct linking to a post (and the calculation of which
  155. // page the post is on and the correct display of viewtopic)
  156. $sql_array = array(
  157. 'SELECT' => 't.*, f.*',
  158. 'FROM' => array(FORUMS_TABLE => 'f'),
  159. );
  160. // The FROM-Order is quite important here, else t.* columns can not be correctly bound.
  161. if ($post_id)
  162. {
  163. $sql_array['SELECT'] .= ', p.post_visibility, p.post_time, p.post_id';
  164. $sql_array['FROM'][POSTS_TABLE] = 'p';
  165. }
  166. // Topics table need to be the last in the chain
  167. $sql_array['FROM'][TOPICS_TABLE] = 't';
  168. if ($user->data['is_registered'])
  169. {
  170. $sql_array['SELECT'] .= ', tw.notify_status';
  171. $sql_array['LEFT_JOIN'] = array();
  172. $sql_array['LEFT_JOIN'][] = array(
  173. 'FROM' => array(TOPICS_WATCH_TABLE => 'tw'),
  174. 'ON' => 'tw.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tw.topic_id'
  175. );
  176. if ($config['allow_bookmarks'])
  177. {
  178. $sql_array['SELECT'] .= ', bm.topic_id as bookmarked';
  179. $sql_array['LEFT_JOIN'][] = array(
  180. 'FROM' => array(BOOKMARKS_TABLE => 'bm'),
  181. 'ON' => 'bm.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = bm.topic_id'
  182. );
  183. }
  184. if ($config['load_db_lastread'])
  185. {
  186. $sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time';
  187. $sql_array['LEFT_JOIN'][] = array(
  188. 'FROM' => array(TOPICS_TRACK_TABLE => 'tt'),
  189. 'ON' => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id'
  190. );
  191. $sql_array['LEFT_JOIN'][] = array(
  192. 'FROM' => array(FORUMS_TRACK_TABLE => 'ft'),
  193. 'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id'
  194. );
  195. }
  196. }
  197. if (!$post_id)
  198. {
  199. $sql_array['WHERE'] = "t.topic_id = $topic_id";
  200. }
  201. else
  202. {
  203. $sql_array['WHERE'] = "p.post_id = $post_id AND t.topic_id = p.topic_id";
  204. }
  205. $sql_array['WHERE'] .= ' AND f.forum_id = t.forum_id';
  206. $sql = $db->sql_build_query('SELECT', $sql_array);
  207. $result = $db->sql_query($sql);
  208. $topic_data = $db->sql_fetchrow($result);
  209. $db->sql_freeresult($result);
  210. // link to unapproved post or incorrect link
  211. if (!$topic_data)
  212. {
  213. // If post_id was submitted, we try at least to display the topic as a last resort...
  214. if ($post_id && $topic_id)
  215. {
  216. redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&amp;f=$forum_id" : '')));
  217. }
  218. trigger_error('NO_TOPIC');
  219. }
  220. $forum_id = (int) $topic_data['forum_id'];
  221. // Now we know the forum_id and can check the permissions
  222. if ($topic_data['topic_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $forum_id))
  223. {
  224. trigger_error('NO_TOPIC');
  225. }
  226. // This is for determining where we are (page)
  227. if ($post_id)
  228. {
  229. // are we where we are supposed to be?
  230. if (($topic_data['post_visibility'] == ITEM_UNAPPROVED || $topic_data['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $topic_data['forum_id']))
  231. {
  232. // If post_id was submitted, we try at least to display the topic as a last resort...
  233. if ($topic_id)
  234. {
  235. redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&amp;f=$forum_id" : '')));
  236. }
  237. trigger_error('NO_TOPIC');
  238. }
  239. if ($post_id == $topic_data['topic_first_post_id'] || $post_id == $topic_data['topic_last_post_id'])
  240. {
  241. $check_sort = ($post_id == $topic_data['topic_first_post_id']) ? 'd' : 'a';
  242. if ($sort_dir == $check_sort)
  243. {
  244. $topic_data['prev_posts'] = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1;
  245. }
  246. else
  247. {
  248. $topic_data['prev_posts'] = 0;
  249. }
  250. }
  251. else
  252. {
  253. $sql = 'SELECT COUNT(p.post_id) AS prev_posts
  254. FROM ' . POSTS_TABLE . " p
  255. WHERE p.topic_id = {$topic_data['topic_id']}
  256. AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.');
  257. if ($sort_dir == 'd')
  258. {
  259. $sql .= " AND (p.post_time > {$topic_data['post_time']} OR (p.post_time = {$topic_data['post_time']} AND p.post_id >= {$topic_data['post_id']}))";
  260. }
  261. else
  262. {
  263. $sql .= " AND (p.post_time < {$topic_data['post_time']} OR (p.post_time = {$topic_data['post_time']} AND p.post_id <= {$topic_data['post_id']}))";
  264. }
  265. $result = $db->sql_query($sql);
  266. $row = $db->sql_fetchrow($result);
  267. $db->sql_freeresult($result);
  268. $topic_data['prev_posts'] = $row['prev_posts'] - 1;
  269. }
  270. }
  271. $topic_id = (int) $topic_data['topic_id'];
  272. $topic_replies = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1;
  273. // Check sticky/announcement time limit
  274. if (($topic_data['topic_type'] == POST_STICKY || $topic_data['topic_type'] == POST_ANNOUNCE) && $topic_data['topic_time_limit'] && ($topic_data['topic_time'] + $topic_data['topic_time_limit']) < time())
  275. {
  276. $sql = 'UPDATE ' . TOPICS_TABLE . '
  277. SET topic_type = ' . POST_NORMAL . ', topic_time_limit = 0
  278. WHERE topic_id = ' . $topic_id;
  279. $db->sql_query($sql);
  280. $topic_data['topic_type'] = POST_NORMAL;
  281. $topic_data['topic_time_limit'] = 0;
  282. }
  283. // Setup look and feel
  284. $user->setup('viewtopic', $topic_data['forum_style']);
  285. // Start auth check
  286. if (!$auth->acl_get('f_read', $forum_id))
  287. {
  288. if ($user->data['user_id'] != ANONYMOUS)
  289. {
  290. trigger_error('SORRY_AUTH_READ');
  291. }
  292. login_box('', $user->lang['LOGIN_VIEWFORUM']);
  293. }
  294. // Forum is passworded ... check whether access has been granted to this
  295. // user this session, if not show login box
  296. if ($topic_data['forum_password'])
  297. {
  298. login_forum_box($topic_data);
  299. }
  300. // Redirect to login upon emailed notification links if user is not logged in.
  301. if (isset($_GET['e']) && $user->data['user_id'] == ANONYMOUS)
  302. {
  303. login_box(build_url('e') . '#unread', $user->lang['LOGIN_NOTIFY_TOPIC']);
  304. }
  305. // What is start equal to?
  306. if ($post_id)
  307. {
  308. $start = floor(($topic_data['prev_posts']) / $config['posts_per_page']) * $config['posts_per_page'];
  309. }
  310. // Get topic tracking info
  311. if (!isset($topic_tracking_info))
  312. {
  313. $topic_tracking_info = array();
  314. // Get topic tracking info
  315. if ($config['load_db_lastread'] && $user->data['is_registered'])
  316. {
  317. $tmp_topic_data = array($topic_id => $topic_data);
  318. $topic_tracking_info = get_topic_tracking($forum_id, $topic_id, $tmp_topic_data, array($forum_id => $topic_data['forum_mark_time']));
  319. unset($tmp_topic_data);
  320. }
  321. else if ($config['load_anon_lastread'] || $user->data['is_registered'])
  322. {
  323. $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id);
  324. }
  325. }
  326. // Post ordering options
  327. $limit_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
  328. $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']);
  329. $sort_by_sql = array('a' => array('u.username_clean', 'p.post_id'), 't' => 'p.post_time', 's' => array('p.post_subject', 'p.post_id'));
  330. $join_user_sql = array('a' => true, 't' => false, 's' => false);
  331. $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
  332. gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param, $default_sort_days, $default_sort_key, $default_sort_dir);
  333. // Obtain correct post count and ordering SQL if user has
  334. // requested anything different
  335. if ($sort_days)
  336. {
  337. $min_post_time = time() - ($sort_days * 86400);
  338. $sql = 'SELECT COUNT(post_id) AS num_posts
  339. FROM ' . POSTS_TABLE . "
  340. WHERE topic_id = $topic_id
  341. AND post_time >= $min_post_time
  342. AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id);
  343. $result = $db->sql_query($sql);
  344. $total_posts = (int) $db->sql_fetchfield('num_posts');
  345. $db->sql_freeresult($result);
  346. $limit_posts_time = "AND p.post_time >= $min_post_time ";
  347. if (isset($_POST['sort']))
  348. {
  349. $start = 0;
  350. }
  351. }
  352. else
  353. {
  354. $total_posts = $topic_replies + 1;
  355. $limit_posts_time = '';
  356. }
  357. // Was a highlight request part of the URI?
  358. $highlight_match = $highlight = '';
  359. if ($hilit_words)
  360. {
  361. $highlight_match = phpbb_clean_search_string($hilit_words);
  362. $highlight = urlencode($highlight_match);
  363. $highlight_match = str_replace('\*', '\w+?', preg_quote($highlight_match, '#'));
  364. $highlight_match = preg_replace('#(?<=^|\s)\\\\w\*\?(?=\s|$)#', '\w+?', $highlight_match);
  365. $highlight_match = str_replace(' ', '|', $highlight_match);
  366. }
  367. // Make sure $start is set to the last page if it exceeds the amount
  368. $start = $pagination->validate_start($start, $config['posts_per_page'], $total_posts);
  369. // General Viewtopic URL for return links
  370. $viewtopic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start") . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : '') . (($highlight_match) ? "&amp;hilit=$highlight" : ''));
  371. // Are we watching this topic?
  372. $s_watching_topic = array(
  373. 'link' => '',
  374. 'link_toggle' => '',
  375. 'title' => '',
  376. 'title_toggle' => '',
  377. 'is_watching' => false,
  378. );
  379. if (($config['email_enable'] || $config['jab_enable']) && $config['allow_topic_notify'])
  380. {
  381. $notify_status = (isset($topic_data['notify_status'])) ? $topic_data['notify_status'] : null;
  382. watch_topic_forum('topic', $s_watching_topic, $user->data['user_id'], $forum_id, $topic_id, $notify_status, $start, $topic_data['topic_title']);
  383. // Reset forum notification if forum notify is set
  384. if ($config['allow_forum_notify'] && $auth->acl_get('f_subscribe', $forum_id))
  385. {
  386. $s_watching_forum = $s_watching_topic;
  387. watch_topic_forum('forum', $s_watching_forum, $user->data['user_id'], $forum_id, 0);
  388. }
  389. }
  390. // Bookmarks
  391. if ($config['allow_bookmarks'] && $user->data['is_registered'] && request_var('bookmark', 0))
  392. {
  393. if (check_link_hash(request_var('hash', ''), "topic_$topic_id"))
  394. {
  395. if (!$topic_data['bookmarked'])
  396. {
  397. $sql = 'INSERT INTO ' . BOOKMARKS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
  398. 'user_id' => $user->data['user_id'],
  399. 'topic_id' => $topic_id,
  400. ));
  401. $db->sql_query($sql);
  402. }
  403. else
  404. {
  405. $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . "
  406. WHERE user_id = {$user->data['user_id']}
  407. AND topic_id = $topic_id";
  408. $db->sql_query($sql);
  409. }
  410. $message = (($topic_data['bookmarked']) ? $user->lang['BOOKMARK_REMOVED'] : $user->lang['BOOKMARK_ADDED']);
  411. if (!$request->is_ajax())
  412. {
  413. $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $viewtopic_url . '">', '</a>');
  414. }
  415. }
  416. else
  417. {
  418. $message = $user->lang['BOOKMARK_ERR'];
  419. if (!$request->is_ajax())
  420. {
  421. $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $viewtopic_url . '">', '</a>');
  422. }
  423. }
  424. meta_refresh(3, $viewtopic_url);
  425. trigger_error($message);
  426. }
  427. // Grab ranks
  428. $ranks = $cache->obtain_ranks();
  429. // Grab icons
  430. $icons = $cache->obtain_icons();
  431. // Grab extensions
  432. $extensions = array();
  433. if ($topic_data['topic_attachment'])
  434. {
  435. $extensions = $cache->obtain_attach_extensions($forum_id);
  436. }
  437. // Forum rules listing
  438. $s_forum_rules = '';
  439. gen_forum_auth_level('topic', $forum_id, $topic_data['forum_status']);
  440. // Quick mod tools
  441. $allow_change_type = ($auth->acl_get('m_', $forum_id) || ($user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'])) ? true : false;
  442. $quickmod_array = array(
  443. // 'key' => array('LANG_KEY', $userHasPermissions),
  444. 'lock' => array('LOCK_TOPIC', ($topic_data['topic_status'] == ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'] && $topic_data['topic_status'] == ITEM_UNLOCKED))),
  445. 'unlock' => array('UNLOCK_TOPIC', ($topic_data['topic_status'] != ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id) || ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'] && $topic_data['topic_status'] == ITEM_UNLOCKED))),
  446. 'delete_topic' => array('DELETE_TOPIC', ($auth->acl_get('m_delete', $forum_id) || (($topic_data['topic_visibility'] != ITEM_DELETED) && $auth->acl_get('m_softdelete', $forum_id)))),
  447. 'restore_topic' => array('RESTORE_TOPIC', (($topic_data['topic_visibility'] == ITEM_DELETED) && $auth->acl_get('m_approve', $forum_id))),
  448. 'move' => array('MOVE_TOPIC', $auth->acl_get('m_move', $forum_id) && $topic_data['topic_status'] != ITEM_MOVED),
  449. 'split' => array('SPLIT_TOPIC', $auth->acl_get('m_split', $forum_id)),
  450. 'merge' => array('MERGE_POSTS', $auth->acl_get('m_merge', $forum_id)),
  451. 'merge_topic' => array('MERGE_TOPIC', $auth->acl_get('m_merge', $forum_id)),
  452. 'fork' => array('FORK_TOPIC', $auth->acl_get('m_move', $forum_id)),
  453. 'make_normal' => array('MAKE_NORMAL', ($allow_change_type && $auth->acl_gets('f_sticky', 'f_announce', $forum_id) && $topic_data['topic_type'] != POST_NORMAL)),
  454. 'make_sticky' => array('MAKE_STICKY', ($allow_change_type && $auth->acl_get('f_sticky', $forum_id) && $topic_data['topic_type'] != POST_STICKY)),
  455. 'make_announce' => array('MAKE_ANNOUNCE', ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_ANNOUNCE)),
  456. 'make_global' => array('MAKE_GLOBAL', ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL)),
  457. 'topic_logs' => array('VIEW_TOPIC_LOGS', $auth->acl_get('m_', $forum_id)),
  458. );
  459. foreach($quickmod_array as $option => $qm_ary)
  460. {
  461. if (!empty($qm_ary[1]))
  462. {
  463. phpbb_add_quickmod_option($option, $qm_ary[0]);
  464. }
  465. }
  466. // Navigation links
  467. generate_forum_nav($topic_data);
  468. // Forum Rules
  469. generate_forum_rules($topic_data);
  470. // Moderators
  471. $forum_moderators = array();
  472. if ($config['load_moderators'])
  473. {
  474. get_moderators($forum_moderators, $forum_id);
  475. }
  476. // This is only used for print view so ...
  477. $server_path = (!$view) ? $phpbb_root_path : generate_board_url() . '/';
  478. // Replace naughty words in title
  479. $topic_data['topic_title'] = censor_text($topic_data['topic_title']);
  480. $s_search_hidden_fields = array(
  481. 't' => $topic_id,
  482. 'sf' => 'msgonly',
  483. );
  484. if ($_SID)
  485. {
  486. $s_search_hidden_fields['sid'] = $_SID;
  487. }
  488. if (!empty($_EXTRA_URL))
  489. {
  490. foreach ($_EXTRA_URL as $url_param)
  491. {
  492. $url_param = explode('=', $url_param, 2);
  493. $s_search_hidden_fields[$url_param[0]] = $url_param[1];
  494. }
  495. }
  496. // If we've got a hightlight set pass it on to pagination.
  497. $base_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : '') . (($highlight_match) ? "&amp;hilit=$highlight" : ''));
  498. $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_posts, $config['posts_per_page'], $start);
  499. // Send vars to template
  500. $template->assign_vars(array(
  501. 'FORUM_ID' => $forum_id,
  502. 'FORUM_NAME' => $topic_data['forum_name'],
  503. 'FORUM_DESC' => generate_text_for_display($topic_data['forum_desc'], $topic_data['forum_desc_uid'], $topic_data['forum_desc_bitfield'], $topic_data['forum_desc_options']),
  504. 'TOPIC_ID' => $topic_id,
  505. 'TOPIC_TITLE' => $topic_data['topic_title'],
  506. 'TOPIC_POSTER' => $topic_data['topic_poster'],
  507. 'TOPIC_AUTHOR_FULL' => get_username_string('full', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
  508. 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
  509. 'TOPIC_AUTHOR' => get_username_string('username', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
  510. 'TOTAL_POSTS' => $user->lang('VIEW_TOPIC_POSTS', (int) $total_posts),
  511. 'U_MCP' => ($auth->acl_get('m_', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&amp;mode=topic_view&amp;f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start") . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : ''), true, $user->session_id) : '',
  512. 'MODERATORS' => (isset($forum_moderators[$forum_id]) && sizeof($forum_moderators[$forum_id])) ? implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]) : '',
  513. 'POST_IMG' => ($topic_data['forum_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'FORUM_LOCKED') : $user->img('button_topic_new', 'POST_NEW_TOPIC'),
  514. 'QUOTE_IMG' => $user->img('icon_post_quote', 'REPLY_WITH_QUOTE'),
  515. 'REPLY_IMG' => ($topic_data['forum_status'] == ITEM_LOCKED || $topic_data['topic_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'TOPIC_LOCKED') : $user->img('button_topic_reply', 'REPLY_TO_TOPIC'),
  516. 'EDIT_IMG' => $user->img('icon_post_edit', 'EDIT_POST'),
  517. 'DELETE_IMG' => $user->img('icon_post_delete', 'DELETE_POST'),
  518. 'DELETED_IMG' => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'),
  519. 'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'),
  520. 'PROFILE_IMG' => $user->img('icon_user_profile', 'READ_PROFILE'),
  521. 'SEARCH_IMG' => $user->img('icon_user_search', 'SEARCH_USER_POSTS'),
  522. 'PM_IMG' => $user->img('icon_contact_pm', 'SEND_PRIVATE_MESSAGE'),
  523. 'EMAIL_IMG' => $user->img('icon_contact_email', 'SEND_EMAIL'),
  524. 'JABBER_IMG' => $user->img('icon_contact_jabber', 'JABBER') ,
  525. 'REPORT_IMG' => $user->img('icon_post_report', 'REPORT_POST'),
  526. 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'),
  527. 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'),
  528. 'WARN_IMG' => $user->img('icon_user_warn', 'WARN_USER'),
  529. 'S_IS_LOCKED' => ($topic_data['topic_status'] == ITEM_UNLOCKED && $topic_data['forum_status'] == ITEM_UNLOCKED) ? false : true,
  530. 'S_SELECT_SORT_DIR' => $s_sort_dir,
  531. 'S_SELECT_SORT_KEY' => $s_sort_key,
  532. 'S_SELECT_SORT_DAYS' => $s_limit_days,
  533. 'S_SINGLE_MODERATOR' => (!empty($forum_moderators[$forum_id]) && sizeof($forum_moderators[$forum_id]) > 1) ? false : true,
  534. 'S_TOPIC_ACTION' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start")),
  535. 'S_MOD_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start") . "&amp;quickmod=1&amp;redirect=" . urlencode(str_replace('&amp;', '&', $viewtopic_url)), true, $user->session_id),
  536. 'L_RETURN_TO_FORUM' => $user->lang('RETURN_TO', $topic_data['forum_name']),
  537. 'S_VIEWTOPIC' => true,
  538. 'S_UNREAD_VIEW' => $view == 'unread',
  539. 'S_DISPLAY_SEARCHBOX' => ($auth->acl_get('u_search') && $auth->acl_get('f_search', $forum_id) && $config['load_search']) ? true : false,
  540. 'S_SEARCHBOX_ACTION' => append_sid("{$phpbb_root_path}search.$phpEx"),
  541. 'S_SEARCH_LOCAL_HIDDEN_FIELDS' => build_hidden_fields($s_search_hidden_fields),
  542. 'S_DISPLAY_POST_INFO' => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false,
  543. 'S_DISPLAY_REPLY_INFO' => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false,
  544. 'S_ENABLE_FEEDS_TOPIC' => ($config['feed_topic'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $topic_data['forum_options'])) ? true : false,
  545. 'U_TOPIC' => "{$server_path}viewtopic.$phpEx?f=$forum_id&amp;t=$topic_id",
  546. 'U_FORUM' => $server_path,
  547. 'U_VIEW_TOPIC' => $viewtopic_url,
  548. 'U_CANONICAL' => generate_board_url() . '/' . append_sid("viewtopic.$phpEx", "t=$topic_id" . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : '') . (($start) ? "&amp;start=$start" : ''), true, ''),
  549. 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id),
  550. 'U_VIEW_OLDER_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;view=previous"),
  551. 'U_VIEW_NEWER_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;view=next"),
  552. 'U_PRINT_TOPIC' => ($auth->acl_get('f_print', $forum_id)) ? $viewtopic_url . '&amp;view=print' : '',
  553. 'U_EMAIL_TOPIC' => ($auth->acl_get('f_email', $forum_id) && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&amp;t=$topic_id") : '',
  554. 'U_WATCH_TOPIC' => $s_watching_topic['link'],
  555. 'U_WATCH_TOPIC_TOGGLE' => $s_watching_topic['link_toggle'],
  556. 'S_WATCH_TOPIC_TITLE' => $s_watching_topic['title'],
  557. 'S_WATCH_TOPIC_TOGGLE' => $s_watching_topic['title_toggle'],
  558. 'S_WATCHING_TOPIC' => $s_watching_topic['is_watching'],
  559. 'U_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks']) ? $viewtopic_url . '&amp;bookmark=1&amp;hash=' . generate_link_hash("topic_$topic_id") : '',
  560. 'S_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'],
  561. 'S_BOOKMARK_TOGGLE' => (!$user->data['is_registered'] || !$config['allow_bookmarks'] || !$topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'],
  562. 'S_BOOKMARKED_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? true : false,
  563. 'U_POST_NEW_TOPIC' => ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=post&amp;f=$forum_id") : '',
  564. 'U_POST_REPLY_TOPIC' => ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&amp;f=$forum_id&amp;t=$topic_id") : '',
  565. 'U_BUMP_TOPIC' => (bump_topic_allowed($forum_id, $topic_data['topic_bumped'], $topic_data['topic_last_post_time'], $topic_data['topic_poster'], $topic_data['topic_last_poster_id'])) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=bump&amp;f=$forum_id&amp;t=$topic_id&amp;hash=" . generate_link_hash("topic_$topic_id")) : '')
  566. );
  567. // Does this topic contain a poll?
  568. if (!empty($topic_data['poll_start']))
  569. {
  570. $sql = 'SELECT o.*, p.bbcode_bitfield, p.bbcode_uid
  571. FROM ' . POLL_OPTIONS_TABLE . ' o, ' . POSTS_TABLE . " p
  572. WHERE o.topic_id = $topic_id
  573. AND p.post_id = {$topic_data['topic_first_post_id']}
  574. AND p.topic_id = o.topic_id
  575. ORDER BY o.poll_option_id";
  576. $result = $db->sql_query($sql);
  577. $poll_info = $vote_counts = array();
  578. while ($row = $db->sql_fetchrow($result))
  579. {
  580. $poll_info[] = $row;
  581. $option_id = (int) $row['poll_option_id'];
  582. $vote_counts[$option_id] = (int) $row['poll_option_total'];
  583. }
  584. $db->sql_freeresult($result);
  585. $cur_voted_id = array();
  586. if ($user->data['is_registered'])
  587. {
  588. $sql = 'SELECT poll_option_id
  589. FROM ' . POLL_VOTES_TABLE . '
  590. WHERE topic_id = ' . $topic_id . '
  591. AND vote_user_id = ' . $user->data['user_id'];
  592. $result = $db->sql_query($sql);
  593. while ($row = $db->sql_fetchrow($result))
  594. {
  595. $cur_voted_id[] = $row['poll_option_id'];
  596. }
  597. $db->sql_freeresult($result);
  598. }
  599. else
  600. {
  601. // Cookie based guest tracking ... I don't like this but hum ho
  602. // it's oft requested. This relies on "nice" users who don't feel
  603. // the need to delete cookies to mess with results.
  604. if ($request->is_set($config['cookie_name'] . '_poll_' . $topic_id, \phpbb\request\request_interface::COOKIE))
  605. {
  606. $cur_voted_id = explode(',', $request->variable($config['cookie_name'] . '_poll_' . $topic_id, '', true, \phpbb\request\request_interface::COOKIE));
  607. $cur_voted_id = array_map('intval', $cur_voted_id);
  608. }
  609. }
  610. // Can not vote at all if no vote permission
  611. $s_can_vote = ($auth->acl_get('f_vote', $forum_id) &&
  612. (($topic_data['poll_length'] != 0 && $topic_data['poll_start'] + $topic_data['poll_length'] > time()) || $topic_data['poll_length'] == 0) &&
  613. $topic_data['topic_status'] != ITEM_LOCKED &&
  614. $topic_data['forum_status'] != ITEM_LOCKED &&
  615. (!sizeof($cur_voted_id) ||
  616. ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']))) ? true : false;
  617. $s_display_results = (!$s_can_vote || ($s_can_vote && sizeof($cur_voted_id)) || $view == 'viewpoll') ? true : false;
  618. if ($update && $s_can_vote)
  619. {
  620. if (!sizeof($voted_id) || sizeof($voted_id) > $topic_data['poll_max_options'] || in_array(VOTE_CONVERTED, $cur_voted_id) || !check_form_key('posting'))
  621. {
  622. $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start"));
  623. meta_refresh(5, $redirect_url);
  624. if (!sizeof($voted_id))
  625. {
  626. $message = 'NO_VOTE_OPTION';
  627. }
  628. else if (sizeof($voted_id) > $topic_data['poll_max_options'])
  629. {
  630. $message = 'TOO_MANY_VOTE_OPTIONS';
  631. }
  632. else if (in_array(VOTE_CONVERTED, $cur_voted_id))
  633. {
  634. $message = 'VOTE_CONVERTED';
  635. }
  636. else
  637. {
  638. $message = 'FORM_INVALID';
  639. }
  640. $message = $user->lang[$message] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>');
  641. trigger_error($message);
  642. }
  643. foreach ($voted_id as $option)
  644. {
  645. if (in_array($option, $cur_voted_id))
  646. {
  647. continue;
  648. }
  649. $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . '
  650. SET poll_option_total = poll_option_total + 1
  651. WHERE poll_option_id = ' . (int) $option . '
  652. AND topic_id = ' . (int) $topic_id;
  653. $db->sql_query($sql);
  654. $vote_counts[$option]++;
  655. if ($user->data['is_registered'])
  656. {
  657. $sql_ary = array(
  658. 'topic_id' => (int) $topic_id,
  659. 'poll_option_id' => (int) $option,
  660. 'vote_user_id' => (int) $user->data['user_id'],
  661. 'vote_user_ip' => (string) $user->ip,
  662. );
  663. $sql = 'INSERT INTO ' . POLL_VOTES_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
  664. $db->sql_query($sql);
  665. }
  666. }
  667. foreach ($cur_voted_id as $option)
  668. {
  669. if (!in_array($option, $voted_id))
  670. {
  671. $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . '
  672. SET poll_option_total = poll_option_total - 1
  673. WHERE poll_option_id = ' . (int) $option . '
  674. AND topic_id = ' . (int) $topic_id;
  675. $db->sql_query($sql);
  676. $vote_counts[$option]--;
  677. if ($user->data['is_registered'])
  678. {
  679. $sql = 'DELETE FROM ' . POLL_VOTES_TABLE . '
  680. WHERE topic_id = ' . (int) $topic_id . '
  681. AND poll_option_id = ' . (int) $option . '
  682. AND vote_user_id = ' . (int) $user->data['user_id'];
  683. $db->sql_query($sql);
  684. }
  685. }
  686. }
  687. if ($user->data['user_id'] == ANONYMOUS && !$user->data['is_bot'])
  688. {
  689. $user->set_cookie('poll_' . $topic_id, implode(',', $voted_id), time() + 31536000);
  690. }
  691. $sql = 'UPDATE ' . TOPICS_TABLE . '
  692. SET poll_last_vote = ' . time() . "
  693. WHERE topic_id = $topic_id";
  694. //, topic_last_post_time = ' . time() . " -- for bumping topics with new votes, ignore for now
  695. $db->sql_query($sql);
  696. $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start"));
  697. $message = $user->lang['VOTE_SUBMITTED'] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>');
  698. if ($request->is_ajax())
  699. {
  700. // Filter out invalid options
  701. $valid_user_votes = array_intersect(array_keys($vote_counts), $voted_id);
  702. $data = array(
  703. 'NO_VOTES' => $user->lang['NO_VOTES'],
  704. 'success' => true,
  705. 'user_votes' => array_flip($valid_user_votes),
  706. 'vote_counts' => $vote_counts,
  707. 'total_votes' => array_sum($vote_counts),
  708. 'can_vote' => !sizeof($valid_user_votes) || ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']),
  709. );
  710. $json_response = new \phpbb\json_response();
  711. $json_response->send($data);
  712. }
  713. meta_refresh(5, $redirect_url);
  714. trigger_error($message);
  715. }
  716. $poll_total = 0;
  717. $poll_most = 0;
  718. foreach ($poll_info as $poll_option)
  719. {
  720. $poll_total += $poll_option['poll_option_total'];
  721. $poll_most = ($poll_option['poll_option_total'] >= $poll_most) ? $poll_option['poll_option_total'] : $poll_most;
  722. }
  723. $parse_flags = ($poll_info[0]['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
  724. for ($i = 0, $size = sizeof($poll_info); $i < $size; $i++)
  725. {
  726. $poll_info[$i]['poll_option_text'] = generate_text_for_display($poll_info[$i]['poll_option_text'], $poll_info[$i]['bbcode_uid'], $poll_option['bbcode_bitfield'], $parse_flags, true);
  727. }
  728. $topic_data['poll_title'] = generate_text_for_display($topic_data['poll_title'], $poll_info[0]['bbcode_uid'], $poll_info[0]['bbcode_bitfield'], $parse_flags, true);
  729. foreach ($poll_info as $poll_option)
  730. {
  731. $option_pct = ($poll_total > 0) ? $poll_option['poll_option_total'] / $poll_total : 0;
  732. $option_pct_txt = sprintf("%.1d%%", round($option_pct * 100));
  733. $option_pct_rel = ($poll_most > 0) ? $poll_option['poll_option_total'] / $poll_most : 0;
  734. $option_pct_rel_txt = sprintf("%.1d%%", round($option_pct_rel * 100));
  735. $option_most_votes = ($poll_option['poll_option_total'] > 0 && $poll_option['poll_option_total'] == $poll_most) ? true : false;
  736. $template->assign_block_vars('poll_option', array(
  737. 'POLL_OPTION_ID' => $poll_option['poll_option_id'],
  738. 'POLL_OPTION_CAPTION' => $poll_option['poll_option_text'],
  739. 'POLL_OPTION_RESULT' => $poll_option['poll_option_total'],
  740. 'POLL_OPTION_PERCENT' => $option_pct_txt,
  741. 'POLL_OPTION_PERCENT_REL' => $option_pct_rel_txt,
  742. 'POLL_OPTION_PCT' => round($option_pct * 100),
  743. 'POLL_OPTION_WIDTH' => round($option_pct * 250),
  744. 'POLL_OPTION_VOTED' => (in_array($poll_option['poll_option_id'], $cur_voted_id)) ? true : false,
  745. 'POLL_OPTION_MOST_VOTES' => $option_most_votes,
  746. ));
  747. }
  748. $poll_end = $topic_data['poll_length'] + $topic_data['poll_start'];
  749. $template->assign_vars(array(
  750. 'POLL_QUESTION' => $topic_data['poll_title'],
  751. 'TOTAL_VOTES' => $poll_total,
  752. 'POLL_LEFT_CAP_IMG' => $user->img('poll_left'),
  753. 'POLL_RIGHT_CAP_IMG'=> $user->img('poll_right'),
  754. 'L_MAX_VOTES' => $user->lang('MAX_OPTIONS_SELECT', (int) $topic_data['poll_max_options']),
  755. 'L_POLL_LENGTH' => ($topic_data['poll_length']) ? sprintf($user->lang[($poll_end > time()) ? 'POLL_RUN_TILL' : 'POLL_ENDED_AT'], $user->format_date($poll_end)) : '',
  756. 'S_HAS_POLL' => true,
  757. 'S_CAN_VOTE' => $s_can_vote,
  758. 'S_DISPLAY_RESULTS' => $s_display_results,
  759. 'S_IS_MULTI_CHOICE' => ($topic_data['poll_max_options'] > 1) ? true : false,
  760. 'S_POLL_ACTION' => $viewtopic_url,
  761. 'U_VIEW_RESULTS' => $viewtopic_url . '&amp;view=viewpoll',
  762. ));
  763. unset($poll_end, $poll_info, $voted_id);
  764. }
  765. // If the user is trying to reach the second half of the topic, fetch it starting from the end
  766. $store_reverse = false;
  767. $sql_limit = $config['posts_per_page'];
  768. $sql_sort_order = $direction = '';
  769. if ($start > $total_posts / 2)
  770. {
  771. $store_reverse = true;
  772. // Select the sort order
  773. $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC');
  774. $sql_limit = $pagination->reverse_limit($start, $sql_limit, $total_posts);
  775. $sql_start = $pagination->reverse_start($start, $sql_limit, $total_posts);
  776. }
  777. else
  778. {
  779. // Select the sort order
  780. $direction = (($sort_dir == 'd') ? 'DESC' : 'ASC');
  781. $sql_start = $start;
  782. }
  783. if (is_array($sort_by_sql[$sort_key]))
  784. {
  785. $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction;
  786. }
  787. else
  788. {
  789. $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction;
  790. }
  791. // Container for user details, only process once
  792. $post_list = $user_cache = $id_cache = $attachments = $attach_list = $rowset = $update_count = $post_edit_list = $post_delete_list = array();
  793. $has_unapproved_attachments = $has_approved_attachments = $display_notice = false;
  794. $bbcode_bitfield = '';
  795. $i = $i_total = 0;
  796. // Go ahead and pull all data for this topic
  797. $sql = 'SELECT p.post_id
  798. FROM ' . POSTS_TABLE . ' p' . (($join_user_sql[$sort_key]) ? ', ' . USERS_TABLE . ' u': '') . "
  799. WHERE p.topic_id = $topic_id
  800. AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . "
  801. " . (($join_user_sql[$sort_key]) ? 'AND u.user_id = p.poster_id': '') . "
  802. $limit_posts_time
  803. ORDER BY $sql_sort_order";
  804. $result = $db->sql_query_limit($sql, $sql_limit, $sql_start);
  805. $i = ($store_reverse) ? $sql_limit - 1 : 0;
  806. while ($row = $db->sql_fetchrow($result))
  807. {
  808. $post_list[$i] = (int) $row['post_id'];
  809. ($store_reverse) ? $i-- : $i++;
  810. }
  811. $db->sql_freeresult($result);
  812. if (!sizeof($post_list))
  813. {
  814. if ($sort_days)
  815. {
  816. trigger_error('NO_POSTS_TIME_FRAME');
  817. }
  818. else
  819. {
  820. trigger_error('NO_TOPIC');
  821. }
  822. }
  823. // Holding maximum post time for marking topic read
  824. // We need to grab it because we do reverse ordering sometimes
  825. $max_post_time = 0;
  826. $sql_ary = array(
  827. 'SELECT' => 'u.*, z.friend, z.foe, p.*',
  828. 'FROM' => array(
  829. USERS_TABLE => 'u',
  830. POSTS_TABLE => 'p',
  831. ),
  832. 'LEFT_JOIN' => array(
  833. array(
  834. 'FROM' => array(ZEBRA_TABLE => 'z'),
  835. 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id',
  836. ),
  837. ),
  838. 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . '
  839. AND u.user_id = p.poster_id',
  840. );
  841. /**
  842. * Event to modify the SQL query before the post and poster data is retrieved
  843. *
  844. * @event core.viewtopic_get_post_data
  845. * @var int forum_id Forum ID
  846. * @var int topic_id Topic ID
  847. * @var array topic_data Array with topic data
  848. * @var array post_list Array with post_ids we are going to retrieve
  849. * @var int sort_days Display posts of previous x days
  850. * @var string sort_key Key the posts are sorted by
  851. * @var string sort_dir Direction the posts are sorted by
  852. * @var int start Pagination information
  853. * @var array sql_ary The SQL array to get the data of posts and posters
  854. * @since 3.1.0-a1
  855. * @change 3.1.0-a2 Added vars forum_id, topic_id, topic_data, post_list, sort_days, sort_key, sort_dir, start
  856. */
  857. $vars = array(
  858. 'forum_id',
  859. 'topic_id',
  860. 'topic_data',
  861. 'post_list',
  862. 'sort_days',
  863. 'sort_key',
  864. 'sort_dir',
  865. 'start',
  866. 'sql_ary',
  867. );
  868. extract($phpbb_dispatcher->trigger_event('core.viewtopic_get_post_data', compact($vars)));
  869. $sql = $db->sql_build_query('SELECT', $sql_ary);
  870. $result = $db->sql_query($sql);
  871. $now = $user->create_datetime();
  872. $now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset());
  873. // Posts are stored in the $rowset array while $attach_list, $user_cache
  874. // and the global bbcode_bitfield are built
  875. while ($row = $db->sql_fetchrow($result))
  876. {
  877. // Set max_post_time
  878. if ($row['post_time'] > $max_post_time)
  879. {
  880. $max_post_time = $row['post_time'];
  881. }
  882. $poster_id = (int) $row['poster_id'];
  883. // Does post have an attachment? If so, add it to the list
  884. if ($row['post_attachment'] && $config['allow_attachments'])
  885. {
  886. $attach_list[] = (int) $row['post_id'];
  887. if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE)
  888. {
  889. $has_unapproved_attachments = true;
  890. }
  891. else if ($row['post_visibility'] == ITEM_APPROVED)
  892. {
  893. $has_approved_attachments = true;
  894. }
  895. }
  896. $rowset_data = array(
  897. 'hide_post' => (($row['foe'] || $row['post_visibility'] == ITEM_DELETED) && ($view != 'show' || $post_id != $row['post_id'])) ? true : false,
  898. 'post_id' => $row['post_id'],
  899. 'post_time' => $row['post_time'],
  900. 'user_id' => $row['user_id'],
  901. 'username' => $row['username'],
  902. 'user_colour' => $row['user_colour'],
  903. 'topic_id' => $row['topic_id'],
  904. 'forum_id' => $row['forum_id'],
  905. 'post_subject' => $row['post_subject'],
  906. 'post_edit_count' => $row['post_edit_count'],
  907. 'post_edit_time' => $row['post_edit_time'],
  908. 'post_edit_reason' => $row['post_edit_reason'],
  909. 'post_edit_user' => $row['post_edit_user'],
  910. 'post_edit_locked' => $row['post_edit_locked'],
  911. 'post_delete_time' => $row['post_delete_time'],
  912. 'post_delete_reason'=> $row['post_delete_reason'],
  913. 'post_delete_user' => $row['post_delete_user'],
  914. // Make sure the icon actually exists
  915. 'icon_id' => (isset($icons[$row['icon_id']]['img'], $icons[$row['icon_id']]['height'], $icons[$row['icon_id']]['width'])) ? $row['icon_id'] : 0,
  916. 'post_attachment' => $row['post_attachment'],
  917. 'post_visibility' => $row['post_visibility'],
  918. 'post_reported' => $row['post_reported'],
  919. 'post_username' => $row['post_username'],
  920. 'post_text' => $row['post_text'],
  921. 'bbcode_uid' => $row['bbcode_uid'],
  922. 'bbcode_bitfield' => $row['bbcode_bitfield'],
  923. 'enable_smilies' => $row['enable_smilies'],
  924. 'enable_sig' => $row['enable_sig'],
  925. 'friend' => $row['friend'],
  926. 'foe' => $row['foe'],
  927. );
  928. /**
  929. * Modify the post rowset containing data to be displayed with posts
  930. *
  931. * @event core.viewtopic_post_rowset_data
  932. * @var array rowset_data Array with the rowset data for this post
  933. * @var array row Array with original user and post data
  934. * @since 3.1.0-a1
  935. */
  936. $vars = array('rowset_data', 'row');
  937. extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_rowset_data', compact($vars)));
  938. $rowset[$row['post_id']] = $rowset_data;
  939. // Define the global bbcode bitfield, will be used to load bbcodes
  940. $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']);
  941. // Is a signature attached? Are we going to display it?
  942. if ($row['enable_sig'] && $config['allow_sig'] && $user->optionget('viewsigs'))
  943. {
  944. $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['user_sig_bbcode_bitfield']);
  945. }
  946. // Cache various user specific data ... so we don't have to recompute
  947. // this each time the same user appears on this page
  948. if (!isset($user_cache[$poster_id]))
  949. {
  950. if ($poster_id == ANONYMOUS)
  951. {
  952. $user_cache_data = array(
  953. 'user_type' => USER_IGNORE,
  954. 'joined' => '',
  955. 'posts' => '',
  956. 'sig' => '',
  957. 'sig_bbcode_uid' => '',
  958. 'sig_bbcode_bitfield' => '',
  959. 'online' => false,
  960. 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '',
  961. 'rank_title' => '',
  962. 'rank_image' => '',
  963. 'rank_image_src' => '',
  964. 'sig' => '',
  965. 'pm' => '',
  966. 'email' => '',
  967. 'jabber' => '',
  968. 'search' => '',
  969. 'age' => '',
  970. 'username' => $row['username'],
  971. 'user_colour' => $row['user_colour'],
  972. 'warnings' => 0,
  973. 'allow_pm' => 0,
  974. );
  975. /**
  976. * Modify the guest user's data displayed with the posts
  977. *
  978. * @event core.viewtopic_cache_guest_data
  979. * @var array user_cache_data Array with the user's data
  980. * @var int poster_id Poster's user id
  981. * @var array row Array with original user and post data
  982. * @since 3.1.0-a1
  983. */
  984. $vars = array('user_cache_data', 'poster_id', 'row');
  985. extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_guest_data', compact($vars)));
  986. $user_cache[$poster_id] = $user_cache_data;
  987. get_user_rank($row['user_rank'], false, $user_cache[$poster_id]['rank_title'], $user_cache[$poster_id]['rank_image'], $user_cache[$poster_id]['rank_image_src']);
  988. }
  989. else
  990. {
  991. $user_sig = '';
  992. // We add the signature to every posters entry because enable_sig is post dependent
  993. if ($row['user_sig'] && $config['allow_sig'] && $user->optionget('viewsigs'))
  994. {
  995. $user_sig = $row['user_sig'];
  996. }
  997. $id_cache[] = $poster_id;
  998. $user_cache_data = array(
  999. 'user_type' => $row['user_type'],
  1000. 'user_inactive_reason' => $row['user_inactive_reason'],
  1001. 'joined' => $user->format_date($row['user_regdate']),
  1002. 'posts' => $row['user_posts'],
  1003. 'warnings' => (isset($row['user_warnings'])) ? $row['user_warnings'] : 0,
  1004. 'sig' => $user_sig,
  1005. 'sig_bbcode_uid' => (!empty($row['user_sig_bbcode_uid'])) ? $row['user_sig_bbcode_uid'] : '',
  1006. 'sig_bbcode_bitfield' => (!empty($row['user_sig_bbcode_bitfield'])) ? $row['user_sig_bbcode_bitfield'] : '',
  1007. 'viewonline' => $row['user_allow_viewonline'],
  1008. 'allow_pm' => $row['user_allow_pm'],
  1009. 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '',
  1010. 'age' => '',
  1011. 'rank_title' => '',
  1012. 'rank_image' => '',
  1013. 'rank_image_src' => '',
  1014. 'username' => $row['username'],
  1015. 'user_colour' => $row['user_colour'],
  1016. 'online' => false,
  1017. 'jabber' => ($row['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&amp;action=jabber&amp;u=$poster_id") : '',
  1018. 'search' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$poster_id&amp;sr=posts") : '',
  1019. 'author_full' => get_username_string('full', $poster_id, $row['username'], $row['user_colour']),
  1020. 'author_colour' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour']),
  1021. 'author_username' => get_username_string('username', $poster_id, $row['username'], $row['user_colour']),
  1022. 'author_profile' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour']),
  1023. );
  1024. /**
  1025. * Modify the users' data displayed with their posts
  1026. *
  1027. * @event core.viewtopic_cache_user_data
  1028. * @var array user_cache_data Array with the user's data
  1029. * @var int poster_id Poster's user id
  1030. * @var array row Array with original user and post data
  1031. * @since 3.1.0-a1
  1032. */
  1033. $vars = array('user_cache_data', 'poster_id', 'row');
  1034. extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_user_data', compact($vars)));
  1035. $user_cache[$poster_id] = $user_cache_data;
  1036. get_user_rank($row['user_rank'], $row['user_posts'], $user_cache[$poster_id]['rank_title'], $user_cache[$poster_id]['rank_image'], $user_cache[$poster_id]['rank_image_src']);
  1037. if ((!empty($row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email'))
  1038. {
  1039. $user_cache[$poster_id]['email'] = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&amp;u=$poster_id") : (($config['board_hide_emails'] && !$auth->acl_get('a_email')) ? '' : 'mailto:' . $row['user_email']);
  1040. }
  1041. else
  1042. {
  1043. $user_cache[$poster_id]['email'] = '';
  1044. }
  1045. if ($config['allow_birthdays'] && !empty($row['user_birthday']))
  1046. {
  1047. list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $row['user_birthday']));
  1048. if ($bday_year)
  1049. {
  1050. $diff = $now['mon'] - $bday_month;
  1051. if ($diff == 0)
  1052. {
  1053. $diff = ($now['mday'] - $bday_day < 0) ? 1 : 0;
  1054. }
  1055. else
  1056. {
  1057. $diff = ($diff < 0) ? 1 : 0;
  1058. }
  1059. $user_cache[$poster_id]['age'] = (int) ($now['year'] - $bday_year - $diff);
  1060. }
  1061. }
  1062. }
  1063. }
  1064. }
  1065. $db->sql_freeresult($result);
  1066. // Load custom profile fields
  1067. if ($config['load_cpf_viewtopic'])
  1068. {
  1069. $cp = $phpbb_container->get('profilefields.manager');
  1070. // Grab all profile fields from users in id cache for later use - similar to the poster cache
  1071. $profile_fields_tmp = $cp->grab_profile_fields_data($id_cache);
  1072. // filter out fields not to be displayed on viewtopic. Yes, it's a hack, but this shouldn't break any MODs.
  1073. $profile_fields_cache = array();
  1074. foreach ($profile_fields_tmp as $profile_user_id => $profile_fields)
  1075. {
  1076. $profile_fields_cache[$profile_user_id] = array();
  1077. foreach ($profile_fields as $used_ident => $profile_field)
  1078. {
  1079. if ($profile_field['data']['field_show_on_vt'])
  1080. {
  1081. $profile_fields_cache[$profile_user_id][$used_ident] = $profile_field;
  1082. }
  1083. }
  1084. }
  1085. unset($profile_fields_tmp);
  1086. }
  1087. // Generate online information for user
  1088. if ($config['load_onlinetrack'] && sizeof($id_cache))
  1089. {
  1090. $sql = 'SELECT session_user_id, MAX(session_time) as online_time, MIN(session_viewonline) AS viewonline
  1091. FROM ' . SESSIONS_TABLE . '
  1092. WHERE ' . $db->sql_in_set('session_user_id', $id_cache) . '
  1093. GROUP BY session_user_id';
  1094. $result = $db->sql_query($sql);
  1095. $update_time = $config['load_online_time'] * 60;
  1096. while ($row = $db->sql_fetchrow($result))
  1097. {
  1098. $user_cache[$row['session_user_id']]['online'] = (time() - $update_time < $row['online_time'] && (($row['viewonline']) || $auth->acl_get('u_viewonline'))) ? true : false;
  1099. }
  1100. $db->sql_freeresult($result);
  1101. }
  1102. unset($id_cache);
  1103. // Pull attachment data
  1104. if (sizeof($attach_list))
  1105. {
  1106. if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
  1107. {
  1108. $sql = 'SELECT *
  1109. FROM ' . ATTACHMENTS_TABLE . '
  1110. WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . '
  1111. AND in_message = 0
  1112. ORDER BY filetime DESC, post_msg_id ASC';
  1113. $result = $db->sql_query($sql);
  1114. while ($row = $db->sql_fetchrow($result))
  1115. {
  1116. $attachments[$row['post_msg_id']][] = $row;
  1117. }
  1118. $db->sql_freeresult($result);
  1119. // No attachments exist, but post table thinks they do so go ahead and reset post_attach flags
  1120. if (!sizeof($attachments))
  1121. {
  1122. $sql = 'UPDATE ' . POSTS_TABLE . '
  1123. SET post_attachment = 0
  1124. WHERE ' . $db->sql_in_set('post_id', $attach_list);
  1125. $db->sql_query($sql);
  1126. // We need to update the topic indicator too if the complete topic is now without an attachment
  1127. if (sizeof($rowset) != $total_posts)
  1128. {
  1129. // Not all posts are displayed so we query the db to find if there's any attachment for this topic
  1130. $sql = 'SELECT a.post_msg_id as post_id
  1131. FROM ' . ATTACHMENTS_TABLE . ' a, ' . POSTS_TABLE . " p
  1132. WHERE p.topic_id = $topic_id
  1133. AND p.post_visibility = " . ITEM_APPROVED . '
  1134. AND p.topic_id = a.topic_id';
  1135. $result = $db->sql_query_limit($sql, 1);
  1136. $row = $db->sql_fetchrow($result);
  1137. $db->sql_freeresult($result);
  1138. if (!$row)
  1139. {
  1140. $sql = 'UPDATE ' . TOPICS_TABLE . "
  1141. SET topic_attachment = 0
  1142. WHERE topic_id = $topic_id";
  1143. $db->sql_query($sql);
  1144. }
  1145. }
  1146. else
  1147. {
  1148. $sql = 'UPDATE ' . TOPICS_TABLE . "
  1149. SET topic_attachment = 0
  1150. WHERE topic_id = $topic_id";
  1151. $db->sql

Large files files are truncated, but you can click here to view the full file