Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

viewtopic.php

Zuletzt modifiziert: 02.04.2025, 15:01 - Dateigröße: 90.50 KiB


0001  <?php
0002  /**
0003  *
0004  * This file is part of the phpBB Forum Software package.
0005  *
0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007  * @license GNU General Public License, version 2 (GPL-2.0)
0008  *
0009  * For full copyright and license information, please see
0010  * the docs/CREDITS.txt file.
0011  *
0012  */
0013   
0014  /**
0015  * @ignore
0016  */
0017  define('IN_PHPBB', true);
0018  $phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
0019  $phpEx = substr(strrchr(__FILE__, '.'), 1);
0020  include($phpbb_root_path . 'common.' . $phpEx);
0021  include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
0022  include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
0023  include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
0024   
0025  // Start session management
0026  $user->session_begin();
0027  $auth->acl($user->data);
0028   
0029  // Initial var setup
0030  $forum_id    = 0;
0031  $topic_id    = $request->variable('t', 0);
0032  $post_id    = $request->variable('p', 0);
0033  $voted_id    = $request->variable('vote_id', array('' => 0));
0034   
0035  $voted_id = (count($voted_id) > 1) ? array_unique($voted_id) : $voted_id;
0036   
0037   
0038  $start        = $request->variable('start', 0);
0039  $view        = $request->variable('view', '');
0040   
0041  $default_sort_days    = (!empty($user->data['user_post_show_days'])) ? $user->data['user_post_show_days'] : 0;
0042  $default_sort_key    = (!empty($user->data['user_post_sortby_type'])) ? $user->data['user_post_sortby_type'] : 't';
0043  $default_sort_dir    = (!empty($user->data['user_post_sortby_dir'])) ? $user->data['user_post_sortby_dir'] : 'a';
0044   
0045  $sort_days    = $request->variable('st', $default_sort_days);
0046  $sort_key    = $request->variable('sk', $default_sort_key);
0047  $sort_dir    = $request->variable('sd', $default_sort_dir);
0048   
0049  $update        = $request->variable('update', false);
0050   
0051  /* @var $pagination \phpbb\pagination */
0052  $pagination = $phpbb_container->get('pagination');
0053   
0054  $s_can_vote = false;
0055  /**
0056  * @todo normalize?
0057  */
0058  $hilit_words    = $request->variable('hilit', '', true);
0059   
0060  // Do we have a topic or post id?
0061  if (!$topic_id && !$post_id)
0062  {
0063      trigger_error('NO_TOPIC');
0064  }
0065   
0066  /* @var $phpbb_content_visibility \phpbb\content_visibility */
0067  $phpbb_content_visibility = $phpbb_container->get('content.visibility');
0068   
0069  // Find topic id if user requested a newer or older topic
0070  if ($view && !$post_id)
0071  {
0072   
0073      if ($view == 'unread')
0074      {
0075          $sql = 'SELECT forum_id
0076              FROM ' . TOPICS_TABLE . "
0077              WHERE topic_id = $topic_id";
0078          $result = $db->sql_query($sql);
0079          $forum_id = (int) $db->sql_fetchfield('forum_id');
0080          $db->sql_freeresult($result);
0081   
0082          if (!$forum_id)
0083          {
0084              trigger_error('NO_TOPIC');
0085          }
0086   
0087          // Get topic tracking info
0088          $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id);
0089          $topic_last_read = (isset($topic_tracking_info[$topic_id])) ? $topic_tracking_info[$topic_id] : 0;
0090   
0091          $sql = 'SELECT post_id, topic_id, forum_id
0092              FROM ' . POSTS_TABLE . "
0093              WHERE topic_id = $topic_id
0094                  AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . "
0095                  AND post_time > $topic_last_read
0096                  AND forum_id = $forum_id
0097              ORDER BY post_time ASC, post_id ASC";
0098          $result = $db->sql_query_limit($sql, 1);
0099          $row = $db->sql_fetchrow($result);
0100          $db->sql_freeresult($result);
0101   
0102          if (!$row)
0103          {
0104              $sql = 'SELECT topic_last_post_id as post_id, topic_id, forum_id
0105                  FROM ' . TOPICS_TABLE . '
0106                  WHERE topic_id = ' . $topic_id;
0107              $result = $db->sql_query($sql);
0108              $row = $db->sql_fetchrow($result);
0109              $db->sql_freeresult($result);
0110          }
0111   
0112          if (!$row)
0113          {
0114              // Setup user environment so we can process lang string
0115              $user->setup('viewtopic');
0116   
0117              trigger_error('NO_TOPIC');
0118          }
0119   
0120          $post_id = $row['post_id'];
0121          $topic_id = $row['topic_id'];
0122      }
0123      else if ($view == 'next' || $view == 'previous')
0124      {
0125          $sql_condition = ($view == 'next') ? '>' : '<';
0126          $sql_ordering = ($view == 'next') ? 'ASC' : 'DESC';
0127   
0128          $sql = 'SELECT forum_id, topic_last_post_time
0129              FROM ' . TOPICS_TABLE . '
0130              WHERE topic_id = ' . $topic_id;
0131          $result = $db->sql_query($sql);
0132          $row = $db->sql_fetchrow($result);
0133          $db->sql_freeresult($result);
0134   
0135          if (!$row)
0136          {
0137              $user->setup('viewtopic');
0138              // OK, the topic doesn't exist. This error message is not helpful, but technically correct.
0139              trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS');
0140          }
0141          else
0142          {
0143              $forum_id = $row['forum_id'];
0144              $sql = 'SELECT topic_id, forum_id
0145                  FROM ' . TOPICS_TABLE . '
0146                  WHERE forum_id = ' . $forum_id . "
0147                      AND topic_moved_id = 0
0148                      AND topic_last_post_time $sql_condition {$row['topic_last_post_time']}
0149                      AND " . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id) . "
0150                  ORDER BY topic_last_post_time $sql_ordering, topic_last_post_id $sql_ordering";
0151              $result = $db->sql_query_limit($sql, 1);
0152              $row = $db->sql_fetchrow($result);
0153              $db->sql_freeresult($result);
0154   
0155              if (!$row)
0156              {
0157                  $sql = 'SELECT forum_style
0158                      FROM ' . FORUMS_TABLE . "
0159                      WHERE forum_id = $forum_id";
0160                  $result = $db->sql_query($sql);
0161                  $forum_style = (int) $db->sql_fetchfield('forum_style');
0162                  $db->sql_freeresult($result);
0163   
0164                  $user->setup('viewtopic', $forum_style);
0165                  trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS');
0166              }
0167              else
0168              {
0169                  $topic_id = $row['topic_id'];
0170                  $forum_id = $row['forum_id'];
0171              }
0172          }
0173      }
0174   
0175      if (isset($row) && $row['forum_id'])
0176      {
0177          $forum_id = $row['forum_id'];
0178      }
0179  }
0180   
0181  // This rather complex gaggle of code handles querying for topics but
0182  // also allows for direct linking to a post (and the calculation of which
0183  // page the post is on and the correct display of viewtopic)
0184  $sql_array = array(
0185      'SELECT'    => 't.*, f.*',
0186   
0187      'FROM'        => array(FORUMS_TABLE => 'f'),
0188  );
0189   
0190  // The FROM-Order is quite important here, else t.* columns can not be correctly bound.
0191  if ($post_id)
0192  {
0193      $sql_array['SELECT'] .= ', p.post_visibility, p.post_time, p.post_id';
0194      $sql_array['FROM'][POSTS_TABLE] = 'p';
0195  }
0196   
0197  // Topics table need to be the last in the chain
0198  $sql_array['FROM'][TOPICS_TABLE] = 't';
0199   
0200  if ($user->data['is_registered'])
0201  {
0202      $sql_array['SELECT'] .= ', tw.notify_status';
0203      $sql_array['LEFT_JOIN'] = array();
0204   
0205      $sql_array['LEFT_JOIN'][] = array(
0206          'FROM'    => array(TOPICS_WATCH_TABLE => 'tw'),
0207          'ON'    => 'tw.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tw.topic_id'
0208      );
0209   
0210      if ($config['allow_bookmarks'])
0211      {
0212          $sql_array['SELECT'] .= ', bm.topic_id as bookmarked';
0213          $sql_array['LEFT_JOIN'][] = array(
0214              'FROM'    => array(BOOKMARKS_TABLE => 'bm'),
0215              'ON'    => 'bm.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = bm.topic_id'
0216          );
0217      }
0218   
0219      if ($config['load_db_lastread'])
0220      {
0221          $sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time';
0222   
0223          $sql_array['LEFT_JOIN'][] = array(
0224              'FROM'    => array(TOPICS_TRACK_TABLE => 'tt'),
0225              'ON'    => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id'
0226          );
0227   
0228          $sql_array['LEFT_JOIN'][] = array(
0229              'FROM'    => array(FORUMS_TRACK_TABLE => 'ft'),
0230              'ON'    => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id'
0231          );
0232      }
0233  }
0234   
0235  if (!$post_id)
0236  {
0237      $sql_array['WHERE'] = "t.topic_id = $topic_id";
0238  }
0239  else
0240  {
0241      $sql_array['WHERE'] = "p.post_id = $post_id AND t.topic_id = p.topic_id";
0242  }
0243   
0244  $sql_array['WHERE'] .= ' AND f.forum_id = t.forum_id';
0245   
0246  $sql = $db->sql_build_query('SELECT', $sql_array);
0247  $result = $db->sql_query($sql);
0248  $topic_data = $db->sql_fetchrow($result);
0249  $db->sql_freeresult($result);
0250   
0251  // link to unapproved post or incorrect link
0252  if (!$topic_data)
0253  {
0254      // If post_id was submitted, we try at least to display the topic as a last resort...
0255      if ($post_id && $topic_id)
0256      {
0257          redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id"));
0258      }
0259   
0260      trigger_error('NO_TOPIC');
0261  }
0262   
0263  $forum_id = (int) $topic_data['forum_id'];
0264   
0265  /**
0266   * Modify the forum ID to handle the correct display of viewtopic if needed
0267   *
0268   * @event core.viewtopic_modify_forum_id
0269   * @var string    forum_id        forum ID
0270   * @var array    topic_data        array of topic's data
0271   * @since 3.2.5-RC1
0272   */
0273  $vars = array(
0274      'forum_id',
0275      'topic_data',
0276  );
0277  extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_forum_id', compact($vars)));
0278   
0279  // If the request is missing the f parameter, the forum id in the user session data is 0 at the moment.
0280  // Let's fix that now so that the user can't hide from the forum's Who Is Online list.
0281  $user->page['forum'] = $forum_id;
0282   
0283  // Now we know the forum_id and can check the permissions
0284  if (!$phpbb_content_visibility->is_visible('topic', $forum_id, $topic_data))
0285  {
0286      trigger_error('NO_TOPIC');
0287  }
0288   
0289  // This is for determining where we are (page)
0290  if ($post_id)
0291  {
0292      // are we where we are supposed to be?
0293      if (($topic_data['post_visibility'] == ITEM_UNAPPROVED || $topic_data['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $topic_data['forum_id']))
0294      {
0295          // If post_id was submitted, we try at least to display the topic as a last resort...
0296          if ($topic_id)
0297          {
0298              redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id"));
0299          }
0300   
0301          trigger_error('NO_TOPIC');
0302      }
0303      if ($post_id == $topic_data['topic_first_post_id'] || $post_id == $topic_data['topic_last_post_id'])
0304      {
0305          $check_sort = ($post_id == $topic_data['topic_first_post_id']) ? 'd' : 'a';
0306   
0307          if ($sort_dir == $check_sort)
0308          {
0309              $topic_data['prev_posts'] = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1;
0310          }
0311          else
0312          {
0313              $topic_data['prev_posts'] = 0;
0314          }
0315      }
0316      else
0317      {
0318          $sql = 'SELECT COUNT(p.post_id) AS prev_posts
0319              FROM ' . POSTS_TABLE . " p
0320              WHERE p.topic_id = {$topic_data['topic_id']}
0321                  AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.');
0322   
0323          if ($sort_dir == 'd')
0324          {
0325              $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']}))";
0326          }
0327          else
0328          {
0329              $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']}))";
0330          }
0331   
0332          $result = $db->sql_query($sql);
0333          $row = $db->sql_fetchrow($result);
0334          $db->sql_freeresult($result);
0335   
0336          $topic_data['prev_posts'] = $row['prev_posts'] - 1;
0337      }
0338  }
0339   
0340  $topic_id = (int) $topic_data['topic_id'];
0341  $topic_replies = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1;
0342   
0343  // Check sticky/announcement/global  time limit
0344  if (($topic_data['topic_type'] != POST_NORMAL) && $topic_data['topic_time_limit'] && ($topic_data['topic_time'] + $topic_data['topic_time_limit']) < time())
0345  {
0346      $sql = 'UPDATE ' . TOPICS_TABLE . '
0347          SET topic_type = ' . POST_NORMAL . ', topic_time_limit = 0
0348          WHERE topic_id = ' . $topic_id;
0349      $db->sql_query($sql);
0350   
0351      $topic_data['topic_type'] = POST_NORMAL;
0352      $topic_data['topic_time_limit'] = 0;
0353  }
0354   
0355  // Setup look and feel
0356  $user->setup('viewtopic', $topic_data['forum_style']);
0357   
0358  if ($view == 'print' && !$auth->acl_get('f_print', $forum_id))
0359  {
0360      send_status_line(403, 'Forbidden');
0361      trigger_error('NO_AUTH_PRINT_TOPIC');
0362  }
0363   
0364  $overrides_f_read_check = false;
0365  $overrides_forum_password_check = false;
0366  $topic_tracking_info = isset($topic_tracking_info) ? $topic_tracking_info : null;
0367   
0368  /**
0369  * Event to apply extra permissions and to override original phpBB's f_read permission and forum password check
0370  * on viewtopic access
0371  *
0372  * @event core.viewtopic_before_f_read_check
0373  * @var    int        forum_id                        The forum id from where the topic belongs
0374  * @var    int        topic_id                        The id of the topic the user tries to access
0375  * @var    int        post_id                            The id of the post the user tries to start viewing at.
0376  *                                                It may be 0 for none given.
0377  * @var    array    topic_data                        All the information from the topic and forum tables for this topic
0378  *                                                 It includes posts information if post_id is not 0
0379  * @var    bool    overrides_f_read_check            Set true to remove f_read check afterwards
0380  * @var    bool    overrides_forum_password_check    Set true to remove forum_password check afterwards
0381  * @var    array    topic_tracking_info                Information upon calling get_topic_tracking()
0382  *                                                Set it to NULL to allow auto-filling later.
0383  *                                                Set it to an array to override original data.
0384  * @since 3.1.3-RC1
0385  */
0386  $vars = array(
0387      'forum_id',
0388      'topic_id',
0389      'post_id',
0390      'topic_data',
0391      'overrides_f_read_check',
0392      'overrides_forum_password_check',
0393      'topic_tracking_info',
0394  );
0395  extract($phpbb_dispatcher->trigger_event('core.viewtopic_before_f_read_check', compact($vars)));
0396   
0397  // Start auth check
0398  if (!$overrides_f_read_check && !$auth->acl_get('f_read', $forum_id))
0399  {
0400      if ($user->data['user_id'] != ANONYMOUS)
0401      {
0402          send_status_line(403, 'Forbidden');
0403          trigger_error('SORRY_AUTH_READ');
0404      }
0405   
0406      login_box('', $user->lang['LOGIN_VIEWFORUM']);
0407  }
0408   
0409  // Forum is passworded ... check whether access has been granted to this
0410  // user this session, if not show login box
0411  if (!$overrides_forum_password_check && $topic_data['forum_password'])
0412  {
0413      login_forum_box($topic_data);
0414  }
0415   
0416  // Redirect to login upon emailed notification links if user is not logged in.
0417  if (isset($_GET['e']) && $user->data['user_id'] == ANONYMOUS)
0418  {
0419      login_box(build_url('e') . '#unread', $user->lang['LOGIN_NOTIFY_TOPIC']);
0420  }
0421   
0422  // What is start equal to?
0423  if ($post_id)
0424  {
0425      $start = floor(($topic_data['prev_posts']) / $config['posts_per_page']) * $config['posts_per_page'];
0426  }
0427   
0428  // Get topic tracking info
0429  if (!isset($topic_tracking_info))
0430  {
0431      $topic_tracking_info = array();
0432   
0433      // Get topic tracking info
0434      if ($config['load_db_lastread'] && $user->data['is_registered'])
0435      {
0436          $tmp_topic_data = array($topic_id => $topic_data);
0437          $topic_tracking_info = get_topic_tracking($forum_id, $topic_id, $tmp_topic_data, array($forum_id => $topic_data['forum_mark_time']));
0438          unset($tmp_topic_data);
0439      }
0440      else if ($config['load_anon_lastread'] || $user->data['is_registered'])
0441      {
0442          $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id);
0443      }
0444  }
0445   
0446  // Post ordering options
0447  $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']);
0448   
0449  $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']);
0450  $sort_by_sql = array('a' => array('u.username_clean', 'p.post_id'), 't' => array('p.post_time', 'p.post_id'), 's' => array('p.post_subject', 'p.post_id'));
0451  $join_user_sql = array('a' => true, 't' => false, 's' => false);
0452   
0453  $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
0454   
0455  /**
0456  * Event to add new sorting options
0457  *
0458  * @event core.viewtopic_gen_sort_selects_before
0459  * @var    array    limit_days        Limit results by time
0460  * @var    array    sort_by_text    Language strings for sorting options
0461  * @var    array    sort_by_sql        SQL conditions for sorting options
0462  * @var    array    join_user_sql    SQL joins required for sorting options
0463  * @var    int        sort_days        User selected sort days
0464  * @var    string    sort_key        User selected sort key
0465  * @var    string    sort_dir        User selected sort direction
0466  * @var    string    s_limit_days    Initial value of limit days selectbox
0467  * @var    string    s_sort_key        Initial value of sort key selectbox
0468  * @var    string    s_sort_dir        Initial value of sort direction selectbox
0469  * @var    string    u_sort_param    Initial value of sorting form action
0470  * @since 3.2.8-RC1
0471  */
0472  $vars = array(
0473      'limit_days',
0474      'sort_by_text',
0475      'sort_by_sql',
0476      'join_user_sql',
0477      'sort_days',
0478      'sort_key',
0479      'sort_dir',
0480      's_limit_days',
0481      's_sort_key',
0482      's_sort_dir',
0483      'u_sort_param',
0484  );
0485  extract($phpbb_dispatcher->trigger_event('core.viewtopic_gen_sort_selects_before', compact($vars)));
0486   
0487  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);
0488   
0489  // Obtain correct post count and ordering SQL if user has
0490  // requested anything different
0491  if ($sort_days)
0492  {
0493      $min_post_time = time() - ($sort_days * 86400);
0494   
0495      $sql = 'SELECT COUNT(post_id) AS num_posts
0496          FROM ' . POSTS_TABLE . "
0497          WHERE topic_id = $topic_id
0498              AND post_time >= $min_post_time
0499                  AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id);
0500      $result = $db->sql_query($sql);
0501      $total_posts = (int) $db->sql_fetchfield('num_posts');
0502      $db->sql_freeresult($result);
0503   
0504      $limit_posts_time = "AND p.post_time >= $min_post_time ";
0505   
0506      if (isset($_POST['sort']))
0507      {
0508          $start = 0;
0509      }
0510  }
0511  else
0512  {
0513      $total_posts = $topic_replies + 1;
0514      $limit_posts_time = '';
0515  }
0516   
0517  // Was a highlight request part of the URI?
0518  $highlight_match = $highlight = '';
0519  if ($hilit_words)
0520  {
0521      $highlight_match = phpbb_clean_search_string($hilit_words);
0522      $highlight = urlencode($highlight_match);
0523      $highlight_match = str_replace('\*', '\w+?', preg_quote($highlight_match, '#'));
0524      $highlight_match = preg_replace('#(?<=^|\s)\\\\w\*\?(?=\s|$)#', '\w+?', $highlight_match);
0525      $highlight_match = str_replace(' ', '|', $highlight_match);
0526  }
0527   
0528  // Make sure $start is set to the last page if it exceeds the amount
0529  $start = $pagination->validate_start($start, $config['posts_per_page'], $total_posts);
0530   
0531  // General Viewtopic URL for return links
0532  $viewtopic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start") . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : '') . (($highlight_match) ? "&amp;hilit=$highlight" : ''));
0533   
0534  // Are we watching this topic?
0535  $s_watching_topic = array(
0536      'link'            => '',
0537      'link_toggle'    => '',
0538      'title'            => '',
0539      'title_toggle'    => '',
0540      'is_watching'    => false,
0541  );
0542   
0543  if ($config['allow_topic_notify'])
0544  {
0545      $notify_status = (isset($topic_data['notify_status'])) ? $topic_data['notify_status'] : null;
0546      watch_topic_forum('topic', $s_watching_topic, $user->data['user_id'], $forum_id, $topic_id, $notify_status, $start, $topic_data['topic_title']);
0547   
0548      // Reset forum notification if forum notify is set
0549      if ($config['allow_forum_notify'] && $auth->acl_get('f_subscribe', $forum_id))
0550      {
0551          $s_watching_forum = $s_watching_topic;
0552          watch_topic_forum('forum', $s_watching_forum, $user->data['user_id'], $forum_id, 0);
0553      }
0554  }
0555   
0556  /**
0557  * Event to modify highlight.
0558  *
0559  * @event core.viewtopic_highlight_modify
0560  * @var    string    highlight            String to be highlighted
0561  * @var    string    highlight_match        Highlight string to be used in preg_replace
0562  * @var    array    topic_data            Topic data
0563  * @var    int        start                Pagination start
0564  * @var    int        total_posts            Number of posts
0565  * @var    string    viewtopic_url        Current viewtopic URL
0566  * @since 3.1.11-RC1
0567  */
0568  $vars = array(
0569      'highlight',
0570      'highlight_match',
0571      'topic_data',
0572      'start',
0573      'total_posts',
0574      'viewtopic_url',
0575  );
0576  extract($phpbb_dispatcher->trigger_event('core.viewtopic_highlight_modify', compact($vars)));
0577   
0578  // Bookmarks
0579  if ($config['allow_bookmarks'] && $user->data['is_registered'] && $request->variable('bookmark', 0))
0580  {
0581      if (check_link_hash($request->variable('hash', ''), "topic_$topic_id"))
0582      {
0583          if (!$topic_data['bookmarked'])
0584          {
0585              $sql = 'INSERT INTO ' . BOOKMARKS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
0586                  'user_id'    => $user->data['user_id'],
0587                  'topic_id'    => $topic_id,
0588              ));
0589              $db->sql_query($sql);
0590          }
0591          else
0592          {
0593              $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . "
0594                  WHERE user_id = {$user->data['user_id']}
0595                      AND topic_id = $topic_id";
0596              $db->sql_query($sql);
0597          }
0598          $message = (($topic_data['bookmarked']) ? $user->lang['BOOKMARK_REMOVED'] : $user->lang['BOOKMARK_ADDED']);
0599   
0600          if (!$request->is_ajax())
0601          {
0602              $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $viewtopic_url . '">', '</a>');
0603          }
0604      }
0605      else
0606      {
0607          $message = $user->lang['BOOKMARK_ERR'];
0608   
0609          if (!$request->is_ajax())
0610          {
0611              $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $viewtopic_url . '">', '</a>');
0612          }
0613      }
0614      meta_refresh(3, $viewtopic_url);
0615   
0616      trigger_error($message);
0617  }
0618   
0619  // Grab ranks
0620  $ranks = $cache->obtain_ranks();
0621   
0622  // Grab icons
0623  $icons = $cache->obtain_icons();
0624   
0625  // Grab extensions
0626  $extensions = array();
0627  if ($topic_data['topic_attachment'])
0628  {
0629      $extensions = $cache->obtain_attach_extensions($forum_id);
0630  }
0631   
0632  // Forum rules listing
0633  $s_forum_rules = '';
0634  gen_forum_auth_level('topic', $forum_id, $topic_data['forum_status']);
0635   
0636  // Quick mod tools
0637  $allow_change_type = ($auth->acl_get('m_', $forum_id) || ($user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'])) ? true : false;
0638   
0639  $s_quickmod_action = append_sid(
0640      "{$phpbb_root_path}mcp.$phpEx",
0641      array(
0642          'f'    => $forum_id,
0643          't'    => $topic_id,
0644          'start'        => $start,
0645          'quickmod'    => 1,
0646          'redirect'    => urlencode(str_replace('&amp;', '&', $viewtopic_url)),
0647      ),
0648      true,
0649      $user->session_id
0650  );
0651   
0652  $quickmod_array = array(
0653  //    'key'            => array('LANG_KEY', $userHasPermissions),
0654   
0655      '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']))),
0656      'unlock'                => array('UNLOCK_TOPIC', ($topic_data['topic_status'] != ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id))),
0657      '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)))),
0658      'restore_topic'        => array('RESTORE_TOPIC', (($topic_data['topic_visibility'] == ITEM_DELETED) && $auth->acl_get('m_approve', $forum_id))),
0659      'move'                    => array('MOVE_TOPIC', $auth->acl_get('m_move', $forum_id) && $topic_data['topic_status'] != ITEM_MOVED),
0660      'split'                    => array('SPLIT_TOPIC', $auth->acl_get('m_split', $forum_id)),
0661      'merge'                    => array('MERGE_POSTS', $auth->acl_get('m_merge', $forum_id)),
0662      'merge_topic'        => array('MERGE_TOPIC', $auth->acl_get('m_merge', $forum_id)),
0663      'fork'                    => array('FORK_TOPIC', $auth->acl_get('m_move', $forum_id)),
0664      'make_normal'        => array('MAKE_NORMAL', ($allow_change_type && $auth->acl_gets('f_sticky', 'f_announce', 'f_announce_global', $forum_id) && $topic_data['topic_type'] != POST_NORMAL)),
0665      'make_sticky'        => array('MAKE_STICKY', ($allow_change_type && $auth->acl_get('f_sticky', $forum_id) && $topic_data['topic_type'] != POST_STICKY)),
0666      'make_announce'    => array('MAKE_ANNOUNCE', ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_ANNOUNCE)),
0667      'make_global'        => array('MAKE_GLOBAL', ($allow_change_type && $auth->acl_get('f_announce_global', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL)),
0668      'topic_logs'            => array('VIEW_TOPIC_LOGS', $auth->acl_get('m_', $forum_id)),
0669  );
0670   
0671  /**
0672  * Event to modify data in the quickmod_array before it gets sent to the
0673  * phpbb_add_quickmod_option function.
0674  *
0675  * @event core.viewtopic_add_quickmod_option_before
0676  * @var    int                forum_id                Forum ID
0677  * @var    int                post_id                    Post ID
0678  * @var    array            quickmod_array            Array with quick moderation options data
0679  * @var    array            topic_data                Array with topic data
0680  * @var    int                topic_id                Topic ID
0681  * @var    array            topic_tracking_info        Array with topic tracking data
0682  * @var    string            viewtopic_url            URL to the topic page
0683  * @var    bool            allow_change_type        Topic change permissions check
0684  * @since 3.1.9-RC1
0685  */
0686  $vars = array(
0687      'forum_id',
0688      'post_id',
0689      'quickmod_array',
0690      'topic_data',
0691      'topic_id',
0692      'topic_tracking_info',
0693      'viewtopic_url',
0694      'allow_change_type',
0695  );
0696  extract($phpbb_dispatcher->trigger_event('core.viewtopic_add_quickmod_option_before', compact($vars)));
0697   
0698  foreach ($quickmod_array as $option => $qm_ary)
0699  {
0700      if (!empty($qm_ary[1]))
0701      {
0702          phpbb_add_quickmod_option($s_quickmod_action, $option, $qm_ary[0]);
0703      }
0704  }
0705   
0706  // Navigation links
0707  generate_forum_nav($topic_data);
0708   
0709  // Forum Rules
0710  generate_forum_rules($topic_data);
0711   
0712  // Moderators
0713  $forum_moderators = array();
0714  if ($config['load_moderators'])
0715  {
0716      get_moderators($forum_moderators, $forum_id);
0717  }
0718   
0719  // This is only used for print view so ...
0720  $server_path = (!$view) ? $phpbb_root_path : generate_board_url() . '/';
0721   
0722  // Replace naughty words in title
0723  $topic_data['topic_title'] = censor_text($topic_data['topic_title']);
0724   
0725  $s_search_hidden_fields = array(
0726      't' => $topic_id,
0727      'sf' => 'msgonly',
0728  );
0729  if ($_SID)
0730  {
0731      $s_search_hidden_fields['sid'] = $_SID;
0732  }
0733   
0734  if (!empty($_EXTRA_URL))
0735  {
0736      foreach ($_EXTRA_URL as $url_param)
0737      {
0738          $url_param = explode('=', $url_param, 2);
0739          $s_search_hidden_fields[$url_param[0]] = $url_param[1];
0740      }
0741  }
0742   
0743  // If we've got a hightlight set pass it on to pagination.
0744  $base_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : '') . (($highlight_match) ? "&amp;hilit=$highlight" : ''));
0745   
0746  /**
0747  * Event to modify data before template variables are being assigned
0748  *
0749  * @event core.viewtopic_assign_template_vars_before
0750  * @var    string    base_url            URL to be passed to generate pagination
0751  * @var    int        forum_id            Forum ID
0752  * @var    int        post_id                Post ID
0753  * @var    array    quickmod_array        Array with quick moderation options data
0754  * @var    int        start                Pagination information
0755  * @var    array    topic_data            Array with topic data
0756  * @var    int        topic_id            Topic ID
0757  * @var    array    topic_tracking_info    Array with topic tracking data
0758  * @var    int        total_posts            Topic total posts count
0759  * @var    string    viewtopic_url        URL to the topic page
0760  * @since 3.1.0-RC4
0761  * @changed 3.1.2-RC1 Added viewtopic_url
0762  */
0763  $vars = array(
0764      'base_url',
0765      'forum_id',
0766      'post_id',
0767      'quickmod_array',
0768      'start',
0769      'topic_data',
0770      'topic_id',
0771      'topic_tracking_info',
0772      'total_posts',
0773      'viewtopic_url',
0774  );
0775  extract($phpbb_dispatcher->trigger_event('core.viewtopic_assign_template_vars_before', compact($vars)));
0776   
0777  $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_posts, $config['posts_per_page'], $start);
0778   
0779  // Send vars to template
0780  $template->assign_vars(array(
0781      'FORUM_ID'         => $forum_id,
0782      'FORUM_NAME'     => $topic_data['forum_name'],
0783      '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']),
0784      'TOPIC_ID'         => $topic_id,
0785      'TOPIC_TITLE'     => $topic_data['topic_title'],
0786      'TOPIC_POSTER'    => $topic_data['topic_poster'],
0787   
0788      'TOPIC_AUTHOR_FULL'        => get_username_string('full', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
0789      'TOPIC_AUTHOR_COLOUR'    => get_username_string('colour', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
0790      'TOPIC_AUTHOR'            => get_username_string('username', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
0791   
0792      'TOTAL_POSTS'    => $user->lang('VIEW_TOPIC_POSTS', (int) $total_posts),
0793      'U_MCP'         => ($auth->acl_get('m_', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&amp;mode=topic_view&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start") . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : ''), true, $user->session_id) : '',
0794      'MODERATORS'    => (isset($forum_moderators[$forum_id]) && count($forum_moderators[$forum_id])) ? implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]) : '',
0795   
0796      'POST_IMG'             => ($topic_data['forum_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'FORUM_LOCKED') : $user->img('button_topic_new', 'POST_NEW_TOPIC'),
0797      'QUOTE_IMG'         => $user->img('icon_post_quote', 'REPLY_WITH_QUOTE'),
0798      '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'),
0799      'EDIT_IMG'             => $user->img('icon_post_edit', 'EDIT_POST'),
0800      'DELETE_IMG'         => $user->img('icon_post_delete', 'DELETE_POST'),
0801      'DELETED_IMG'        => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'),
0802      'INFO_IMG'             => $user->img('icon_post_info', 'VIEW_INFO'),
0803      'PROFILE_IMG'        => $user->img('icon_user_profile', 'READ_PROFILE'),
0804      'SEARCH_IMG'         => $user->img('icon_user_search', 'SEARCH_USER_POSTS'),
0805      'PM_IMG'             => $user->img('icon_contact_pm', 'SEND_PRIVATE_MESSAGE'),
0806      'EMAIL_IMG'         => $user->img('icon_contact_email', 'SEND_EMAIL'),
0807      'JABBER_IMG'        => $user->img('icon_contact_jabber', 'JABBER') ,
0808      'REPORT_IMG'        => $user->img('icon_post_report', 'REPORT_POST'),
0809      'REPORTED_IMG'        => $user->img('icon_topic_reported', 'POST_REPORTED'),
0810      'UNAPPROVED_IMG'    => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'),
0811      'WARN_IMG'            => $user->img('icon_user_warn', 'WARN_USER'),
0812   
0813      'S_IS_LOCKED'            => ($topic_data['topic_status'] == ITEM_UNLOCKED && $topic_data['forum_status'] == ITEM_UNLOCKED) ? false : true,
0814      'S_SELECT_SORT_DIR'     => $s_sort_dir,
0815      'S_SELECT_SORT_KEY'     => $s_sort_key,
0816      'S_SELECT_SORT_DAYS'     => $s_limit_days,
0817      'S_SINGLE_MODERATOR'    => (!empty($forum_moderators[$forum_id]) && count($forum_moderators[$forum_id]) > 1) ? false : true,
0818      'S_TOPIC_ACTION'         => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start")),
0819      'S_MOD_ACTION'             => $s_quickmod_action,
0820   
0821      'L_RETURN_TO_FORUM'        => $user->lang('RETURN_TO', $topic_data['forum_name']),
0822      'S_VIEWTOPIC'            => true,
0823      'S_UNREAD_VIEW'            => $view == 'unread',
0824      'S_DISPLAY_SEARCHBOX'    => ($auth->acl_get('u_search') && $auth->acl_get('f_search', $forum_id) && $config['load_search']) ? true : false,
0825      'S_SEARCHBOX_ACTION'    => append_sid("{$phpbb_root_path}search.$phpEx"),
0826      'S_SEARCH_LOCAL_HIDDEN_FIELDS'    => build_hidden_fields($s_search_hidden_fields),
0827   
0828      'S_DISPLAY_POST_INFO'    => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false,
0829      'S_DISPLAY_REPLY_INFO'    => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false,
0830      'S_ENABLE_FEEDS_TOPIC'    => ($config['feed_topic'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $topic_data['forum_options'])) ? true : false,
0831   
0832      'U_TOPIC'                => "{$server_path}viewtopic.$phpEx?t=$topic_id",
0833      'U_FORUM'                => $server_path,
0834      'U_VIEW_TOPIC'             => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start") . (strlen($u_sort_param) ? "&amp;$u_sort_param" : '')),
0835      'U_CANONICAL'            => generate_board_url() . '/' . append_sid("viewtopic.$phpEx", "t=$topic_id" . (($start) ? "&amp;start=$start" : ''), true, ''),
0836      'U_VIEW_FORUM'             => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id),
0837      'U_VIEW_OLDER_TOPIC'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id&amp;view=previous"),
0838      'U_VIEW_NEWER_TOPIC'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id&amp;view=next"),
0839      'U_PRINT_TOPIC'            => ($auth->acl_get('f_print', $forum_id)) ? $viewtopic_url . '&amp;view=print' : '',
0840      '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") : '',
0841   
0842      'U_WATCH_TOPIC'            => $s_watching_topic['link'],
0843      'U_WATCH_TOPIC_TOGGLE'    => $s_watching_topic['link_toggle'],
0844      'S_WATCH_TOPIC_TITLE'    => $s_watching_topic['title'],
0845      'S_WATCH_TOPIC_TOGGLE'    => $s_watching_topic['title_toggle'],
0846      'S_WATCHING_TOPIC'        => $s_watching_topic['is_watching'],
0847   
0848      'U_BOOKMARK_TOPIC'        => ($user->data['is_registered'] && $config['allow_bookmarks']) ? $viewtopic_url . '&amp;bookmark=1&amp;hash=' . generate_link_hash("topic_$topic_id") : '',
0849      'S_BOOKMARK_TOPIC'        => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'],
0850      'S_BOOKMARK_TOGGLE'        => (!$user->data['is_registered'] || !$config['allow_bookmarks'] || !$topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'],
0851      'S_BOOKMARKED_TOPIC'    => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? true : false,
0852   
0853      '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") : '',
0854      '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;t=$topic_id") : '',
0855      '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;t=$topic_id&amp;hash=" . generate_link_hash("topic_$topic_id")) : '')
0856  );
0857   
0858  // Does this topic contain a poll?
0859  if (!empty($topic_data['poll_start']))
0860  {
0861      $sql = 'SELECT o.*, p.bbcode_bitfield, p.bbcode_uid
0862          FROM ' . POLL_OPTIONS_TABLE . ' o, ' . POSTS_TABLE . " p
0863          WHERE o.topic_id = $topic_id
0864              AND p.post_id = {$topic_data['topic_first_post_id']}
0865              AND p.topic_id = o.topic_id
0866          ORDER BY o.poll_option_id";
0867      $result = $db->sql_query($sql);
0868   
0869      $poll_info = $vote_counts = array();
0870      while ($row = $db->sql_fetchrow($result))
0871      {
0872          $poll_info[] = $row;
0873          $option_id = (int) $row['poll_option_id'];
0874          $vote_counts[$option_id] = (int) $row['poll_option_total'];
0875      }
0876      $db->sql_freeresult($result);
0877   
0878      $cur_voted_id = array();
0879      if ($user->data['is_registered'])
0880      {
0881          $sql = 'SELECT poll_option_id
0882              FROM ' . POLL_VOTES_TABLE . '
0883              WHERE topic_id = ' . $topic_id . '
0884                  AND vote_user_id = ' . $user->data['user_id'];
0885          $result = $db->sql_query($sql);
0886   
0887          while ($row = $db->sql_fetchrow($result))
0888          {
0889              $cur_voted_id[] = $row['poll_option_id'];
0890          }
0891          $db->sql_freeresult($result);
0892      }
0893      else
0894      {
0895          // Cookie based guest tracking ... I don't like this but hum ho
0896          // it's oft requested. This relies on "nice" users who don't feel
0897          // the need to delete cookies to mess with results.
0898          if ($request->is_set($config['cookie_name'] . '_poll_' . $topic_id, \phpbb\request\request_interface::COOKIE))
0899          {
0900              $cur_voted_id = explode(',', $request->variable($config['cookie_name'] . '_poll_' . $topic_id, '', true, \phpbb\request\request_interface::COOKIE));
0901              $cur_voted_id = array_map('intval', $cur_voted_id);
0902          }
0903      }
0904   
0905      // Can not vote at all if no vote permission
0906      $s_can_vote = ($auth->acl_get('f_vote', $forum_id) &&
0907          (($topic_data['poll_length'] != 0 && $topic_data['poll_start'] + $topic_data['poll_length'] > time()) || $topic_data['poll_length'] == 0) &&
0908          $topic_data['topic_status'] != ITEM_LOCKED &&
0909          $topic_data['forum_status'] != ITEM_LOCKED &&
0910          (!count($cur_voted_id) ||
0911          ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']))) ? true : false;
0912      $s_display_results = (!$s_can_vote || ($s_can_vote && count($cur_voted_id)) || $view == 'viewpoll') ? true : false;
0913   
0914      /**
0915      * Event to manipulate the poll data
0916      *
0917      * @event core.viewtopic_modify_poll_data
0918      * @var    array    cur_voted_id                Array with options' IDs current user has voted for
0919      * @var    int        forum_id                    The topic's forum id
0920      * @var    array    poll_info                    Array with the poll information
0921      * @var    bool    s_can_vote                    Flag indicating if a user can vote
0922      * @var    bool    s_display_results            Flag indicating if results or poll options should be displayed
0923      * @var    int        topic_id                    The id of the topic the user tries to access
0924      * @var    array    topic_data                    All the information from the topic and forum tables for this topic
0925      * @var    string    viewtopic_url                URL to the topic page
0926      * @var    array    vote_counts                    Array with the vote counts for every poll option
0927      * @var    array    voted_id                    Array with updated options' IDs current user is voting for
0928      * @since 3.1.5-RC1
0929      */
0930      $vars = array(
0931          'cur_voted_id',
0932          'forum_id',
0933          'poll_info',
0934          's_can_vote',
0935          's_display_results',
0936          'topic_id',
0937          'topic_data',
0938          'viewtopic_url',
0939          'vote_counts',
0940          'voted_id',
0941      );
0942      extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_data', compact($vars)));
0943   
0944      if ($update && $s_can_vote)
0945      {
0946   
0947          if (!count($voted_id) || count($voted_id) > $topic_data['poll_max_options'] || in_array(VOTE_CONVERTED, $cur_voted_id) || !check_form_key('posting'))
0948          {
0949              $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start"));
0950   
0951              meta_refresh(5, $redirect_url);
0952              if (!count($voted_id))
0953              {
0954                  $message = 'NO_VOTE_OPTION';
0955              }
0956              else if (count($voted_id) > $topic_data['poll_max_options'])
0957              {
0958                  $message = 'TOO_MANY_VOTE_OPTIONS';
0959              }
0960              else if (in_array(VOTE_CONVERTED, $cur_voted_id))
0961              {
0962                  $message = 'VOTE_CONVERTED';
0963              }
0964              else
0965              {
0966                  $message = 'FORM_INVALID';
0967              }
0968   
0969              $message = $user->lang[$message] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>');
0970              trigger_error($message);
0971          }
0972   
0973          foreach ($voted_id as $option)
0974          {
0975              if (in_array($option, $cur_voted_id))
0976              {
0977                  continue;
0978              }
0979   
0980              $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . '
0981                  SET poll_option_total = poll_option_total + 1
0982                  WHERE poll_option_id = ' . (int) $option . '
0983                      AND topic_id = ' . (int) $topic_id;
0984              $db->sql_query($sql);
0985   
0986              $vote_counts[$option]++;
0987   
0988              if ($user->data['is_registered'])
0989              {
0990                  $sql_ary = array(
0991                      'topic_id'            => (int) $topic_id,
0992                      'poll_option_id'    => (int) $option,
0993                      'vote_user_id'        => (int) $user->data['user_id'],
0994                      'vote_user_ip'        => (string) $user->ip,
0995                  );
0996   
0997                  $sql = 'INSERT INTO ' . POLL_VOTES_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
0998                  $db->sql_query($sql);
0999              }
1000          }
1001   
1002          foreach ($cur_voted_id as $option)
1003          {
1004              if (!in_array($option, $voted_id))
1005              {
1006                  $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . '
1007                      SET poll_option_total = poll_option_total - 1
1008                      WHERE poll_option_id = ' . (int) $option . '
1009                          AND topic_id = ' . (int) $topic_id;
1010                  $db->sql_query($sql);
1011   
1012                  $vote_counts[$option]--;
1013   
1014                  if ($user->data['is_registered'])
1015                  {
1016                      $sql = 'DELETE FROM ' . POLL_VOTES_TABLE . '
1017                          WHERE topic_id = ' . (int) $topic_id . '
1018                              AND poll_option_id = ' . (int) $option . '
1019                              AND vote_user_id = ' . (int) $user->data['user_id'];
1020                      $db->sql_query($sql);
1021                  }
1022              }
1023          }
1024   
1025          if ($user->data['user_id'] == ANONYMOUS && !$user->data['is_bot'])
1026          {
1027              $user->set_cookie('poll_' . $topic_id, implode(',', $voted_id), time() + 31536000);
1028          }
1029   
1030          $sql = 'UPDATE ' . TOPICS_TABLE . '
1031              SET poll_last_vote = ' . time() . "
1032              WHERE topic_id = $topic_id";
1033          //, topic_last_post_time = ' . time() . " -- for bumping topics with new votes, ignore for now
1034          $db->sql_query($sql);
1035   
1036          $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start"));
1037          $message = $user->lang['VOTE_SUBMITTED'] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>');
1038   
1039          if ($request->is_ajax())
1040          {
1041              // Filter out invalid options
1042              $valid_user_votes = array_intersect(array_keys($vote_counts), $voted_id);
1043   
1044              $data = array(
1045                  'NO_VOTES'            => $user->lang['NO_VOTES'],
1046                  'success'            => true,
1047                  'user_votes'        => array_flip($valid_user_votes),
1048                  'vote_counts'        => $vote_counts,
1049                  'total_votes'        => array_sum($vote_counts),
1050                  'can_vote'            => !count($valid_user_votes) || ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']),
1051              );
1052   
1053              /**
1054              * Event to manipulate the poll data sent by AJAX response
1055              *
1056              * @event core.viewtopic_modify_poll_ajax_data
1057              * @var    array    data                JSON response data
1058              * @var    array    valid_user_votes    Valid user votes
1059              * @var    array    vote_counts            Vote counts
1060              * @var    int        forum_id            Forum ID
1061              * @var    array    topic_data            Topic data
1062              * @var    array    poll_info            Array with the poll information
1063              * @since 3.2.4-RC1
1064              */
1065              $vars = array(
1066                  'data',
1067                  'valid_user_votes',
1068                  'vote_counts',
1069                  'forum_id',
1070                  'topic_data',
1071                  'poll_info',
1072              );
1073              extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_ajax_data', compact($vars)));
1074   
1075              $json_response = new \phpbb\json_response();
1076              $json_response->send($data);
1077          }
1078   
1079          meta_refresh(5, $redirect_url);
1080          trigger_error($message);
1081      }
1082   
1083      $poll_total = 0;
1084      $poll_most = 0;
1085      foreach ($poll_info as $poll_option)
1086      {
1087          $poll_total += $poll_option['poll_option_total'];
1088          $poll_most = ($poll_option['poll_option_total'] >= $poll_most) ? $poll_option['poll_option_total'] : $poll_most;
1089      }
1090   
1091      $parse_flags = ($poll_info[0]['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
1092   
1093      for ($i = 0, $size = count($poll_info); $i < $size; $i++)
1094      {
1095          $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);
1096      }
1097   
1098      $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);
1099   
1100      $poll_template_data = $poll_options_template_data = array();
1101      foreach ($poll_info as $poll_option)
1102      {
1103          $option_pct = ($poll_total > 0) ? $poll_option['poll_option_total'] / $poll_total : 0;
1104          $option_pct_txt = sprintf("%.1d%%", round($option_pct * 100));
1105          $option_pct_rel = ($poll_most > 0) ? $poll_option['poll_option_total'] / $poll_most : 0;
1106          $option_pct_rel_txt = sprintf("%.1d%%", round($option_pct_rel * 100));
1107          $option_most_votes = ($poll_option['poll_option_total'] > 0 && $poll_option['poll_option_total'] == $poll_most) ? true : false;
1108   
1109          $poll_options_template_data[] = array(
1110              'POLL_OPTION_ID'             => $poll_option['poll_option_id'],
1111              'POLL_OPTION_CAPTION'         => $poll_option['poll_option_text'],
1112              'POLL_OPTION_RESULT'         => $poll_option['poll_option_total'],
1113              'POLL_OPTION_PERCENT'         => $option_pct_txt,
1114              'POLL_OPTION_PERCENT_REL'     => $option_pct_rel_txt,
1115              'POLL_OPTION_PCT'            => round($option_pct * 100),
1116              'POLL_OPTION_WIDTH'         => round($option_pct * 250),
1117              'POLL_OPTION_VOTED'            => (in_array($poll_option['poll_option_id'], $cur_voted_id)) ? true : false,
1118              'POLL_OPTION_MOST_VOTES'    => $option_most_votes,
1119          );
1120      }
1121   
1122      $poll_end = $topic_data['poll_length'] + $topic_data['poll_start'];
1123   
1124      $poll_template_data = array(
1125          'POLL_QUESTION'        => $topic_data['poll_title'],
1126          'TOTAL_VOTES'         => $poll_total,
1127          'POLL_LEFT_CAP_IMG'    => $user->img('poll_left'),
1128          'POLL_RIGHT_CAP_IMG'=> $user->img('poll_right'),
1129   
1130          'L_MAX_VOTES'        => $user->lang('MAX_OPTIONS_SELECT', (int) $topic_data['poll_max_options']),
1131          'L_POLL_LENGTH'        => ($topic_data['poll_length']) ? sprintf($user->lang[($poll_end > time()) ? 'POLL_RUN_TILL' : 'POLL_ENDED_AT'], $user->format_date($poll_end)) : '',
1132   
1133          'S_HAS_POLL'        => true,
1134          'S_CAN_VOTE'        => $s_can_vote,
1135          'S_DISPLAY_RESULTS'    => $s_display_results,
1136          'S_IS_MULTI_CHOICE'    => ($topic_data['poll_max_options'] > 1) ? true : false,
1137          'S_POLL_ACTION'        => $viewtopic_url,
1138   
1139          'U_VIEW_RESULTS'    => $viewtopic_url . '&amp;view=viewpoll',
1140      );
1141   
1142      /**
1143      * Event to add/modify poll template data
1144      *
1145      * @event core.viewtopic_modify_poll_template_data
1146      * @var    array    cur_voted_id                    Array with options' IDs current user has voted for
1147      * @var    int        poll_end                        The poll end time
1148      * @var    array    poll_info                        Array with the poll information
1149      * @var    array    poll_options_template_data        Array with the poll options template data
1150      * @var    array    poll_template_data                Array with the common poll template data
1151      * @var    int        poll_total                        Total poll votes count
1152      * @var    int        poll_most                        Mostly voted option votes count
1153      * @var    array    topic_data                        All the information from the topic and forum tables for this topic
1154      * @var    string    viewtopic_url                    URL to the topic page
1155      * @var    array    vote_counts                        Array with the vote counts for every poll option
1156      * @var    array    voted_id                        Array with updated options' IDs current user is voting for
1157      * @since 3.1.5-RC1
1158      */
1159      $vars = array(
1160          'cur_voted_id',
1161          'poll_end',
1162          'poll_info',
1163          'poll_options_template_data',
1164          'poll_template_data',
1165          'poll_total',
1166          'poll_most',
1167          'topic_data',
1168          'viewtopic_url',
1169          'vote_counts',
1170          'voted_id',
1171      );
1172      extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_template_data', compact($vars)));
1173   
1174      $template->assign_block_vars_array('poll_option', $poll_options_template_data);
1175   
1176      $template->assign_vars($poll_template_data);
1177   
1178      unset($poll_end, $poll_info, $poll_options_template_data, $poll_template_data, $voted_id);
1179  }
1180   
1181  // If the user is trying to reach the second half of the topic, fetch it starting from the end
1182  $store_reverse = false;
1183  $sql_limit = $config['posts_per_page'];
1184  $sql_sort_order = $direction = '';
1185   
1186  if ($start > $total_posts / 2)
1187  {
1188      $store_reverse = true;
1189   
1190      // Select the sort order
1191      $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC');
1192   
1193      $sql_limit = $pagination->reverse_limit($start, $sql_limit, $total_posts);
1194      $sql_start = $pagination->reverse_start($start, $sql_limit, $total_posts);
1195  }
1196  else
1197  {
1198      // Select the sort order
1199      $direction = (($sort_dir == 'd') ? 'DESC' : 'ASC');
1200      $sql_start = $start;
1201  }
1202   
1203  if (is_array($sort_by_sql[$sort_key]))
1204  {
1205      $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction;
1206  }
1207  else
1208  {
1209      $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction;
1210  }
1211   
1212  // Container for user details, only process once
1213  $post_list = $user_cache = $id_cache = $attachments = $attach_list = $rowset = $update_count = $post_edit_list = $post_delete_list = array();
1214  $has_unapproved_attachments = $has_approved_attachments = $display_notice = false;
1215  $i = $i_total = 0;
1216   
1217  // Go ahead and pull all data for this topic
1218  $sql = 'SELECT p.post_id
1219      FROM ' . POSTS_TABLE . ' p' . (($join_user_sql[$sort_key]) ? ', ' . USERS_TABLE . ' u': '') . "
1220      WHERE p.topic_id = $topic_id
1221          AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . "
1222          " . (($join_user_sql[$sort_key]) ? 'AND u.user_id = p.poster_id': '') . "
1223          $limit_posts_time
1224      ORDER BY $sql_sort_order";
1225   
1226  /**
1227  * Event to modify the SQL query that gets post_list
1228  *
1229  * @event core.viewtopic_modify_post_list_sql
1230  * @var    string    sql            The SQL query to generate the post_list
1231  * @var    int        sql_limit    The number of posts the query fetches
1232  * @var    int        sql_start    The index the query starts to fetch from
1233  * @var    string    sort_key    Key the posts are sorted by
1234  * @var    string    sort_days    Display posts of previous x days
1235  * @var    int        forum_id    Forum ID
1236  * @since 3.2.4-RC1
1237  */
1238  $vars = array(
1239      'sql',
1240      'sql_limit',
1241      'sql_start',
1242      'sort_key',
1243      'sort_days',
1244      'forum_id',
1245  );
1246  extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_list_sql', compact($vars)));
1247   
1248  $result = $db->sql_query_limit($sql, $sql_limit, $sql_start);
1249   
1250  $i = ($store_reverse) ? $sql_limit - 1 : 0;
1251  while ($row = $db->sql_fetchrow($result))
1252  {
1253      $post_list[$i] = (int) $row['post_id'];
1254      ($store_reverse) ? $i-- : $i++;
1255  }
1256  $db->sql_freeresult($result);
1257   
1258  if (!count($post_list))
1259  {
1260      if ($sort_days)
1261      {
1262          trigger_error('NO_POSTS_TIME_FRAME');
1263      }
1264      else
1265      {
1266          trigger_error('NO_TOPIC');
1267      }
1268  }
1269   
1270  // Holding maximum post time for marking topic read
1271  // We need to grab it because we do reverse ordering sometimes
1272  $max_post_time = 0;
1273   
1274  $sql_ary = array(
1275      'SELECT'    => 'u.*, z.friend, z.foe, p.*',
1276   
1277      'FROM'        => array(
1278          USERS_TABLE        => 'u',
1279          POSTS_TABLE        => 'p',
1280      ),
1281   
1282      'LEFT_JOIN'    => array(
1283          array(
1284              'FROM'    => array(ZEBRA_TABLE => 'z'),
1285              'ON'    => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id',
1286          ),
1287      ),
1288   
1289      'WHERE'        => $db->sql_in_set('p.post_id', $post_list) . '
1290          AND u.user_id = p.poster_id',
1291  );
1292   
1293  /**
1294  * Event to modify the SQL query before the post and poster data is retrieved
1295  *
1296  * @event core.viewtopic_get_post_data
1297  * @var    int        forum_id    Forum ID
1298  * @var    int        topic_id    Topic ID
1299  * @var    array    topic_data    Array with topic data
1300  * @var    array    post_list    Array with post_ids we are going to retrieve
1301  * @var    int        sort_days    Display posts of previous x days
1302  * @var    string    sort_key    Key the posts are sorted by
1303  * @var    string    sort_dir    Direction the posts are sorted by
1304  * @var    int        start        Pagination information
1305  * @var    array    sql_ary        The SQL array to get the data of posts and posters
1306  * @since 3.1.0-a1
1307  * @changed 3.1.0-a2 Added vars forum_id, topic_id, topic_data, post_list, sort_days, sort_key, sort_dir, start
1308  */
1309  $vars = array(
1310      'forum_id',
1311      'topic_id',
1312      'topic_data',
1313      'post_list',
1314      'sort_days',
1315      'sort_key',
1316      'sort_dir',
1317      'start',
1318      'sql_ary',
1319  );
1320  extract($phpbb_dispatcher->trigger_event('core.viewtopic_get_post_data', compact($vars)));
1321   
1322  $sql = $db->sql_build_query('SELECT', $sql_ary);
1323  $result = $db->sql_query($sql);
1324   
1325  $now = $user->create_datetime();
1326  $now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset());
1327   
1328  // Posts are stored in the $rowset array while $attach_list, $user_cache
1329  // and the global bbcode_bitfield are built
1330  while ($row = $db->sql_fetchrow($result))
1331  {
1332      // Set max_post_time
1333      if ($row['post_time'] > $max_post_time)
1334      {
1335          $max_post_time = $row['post_time'];
1336      }
1337   
1338      $poster_id = (int) $row['poster_id'];
1339   
1340      // Does post have an attachment? If so, add it to the list
1341      if ($row['post_attachment'] && $config['allow_attachments'])
1342      {
1343          $attach_list[] = (int) $row['post_id'];
1344   
1345          if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE)
1346          {
1347              $has_unapproved_attachments = true;
1348          }
1349          else if ($row['post_visibility'] == ITEM_APPROVED)
1350          {
1351              $has_approved_attachments = true;
1352          }
1353      }
1354   
1355      $rowset_data = array(
1356          'hide_post'            => (($row['foe'] || $row['post_visibility'] == ITEM_DELETED) && ($view != 'show' || $post_id != $row['post_id'])) ? true : false,
1357   
1358          'post_id'            => $row['post_id'],
1359          'post_time'            => $row['post_time'],
1360          'user_id'            => $row['user_id'],
1361          'username'            => $row['username'],
1362          'user_colour'        => $row['user_colour'],
1363          'topic_id'            => $row['topic_id'],
1364          'forum_id'            => $row['forum_id'],
1365          'post_subject'        => $row['post_subject'],
1366          'post_edit_count'    => $row['post_edit_count'],
1367          'post_edit_time'    => $row['post_edit_time'],
1368          'post_edit_reason'    => $row['post_edit_reason'],
1369          'post_edit_user'    => $row['post_edit_user'],
1370          'post_edit_locked'    => $row['post_edit_locked'],
1371          'post_delete_time'    => $row['post_delete_time'],
1372          'post_delete_reason'=> $row['post_delete_reason'],
1373          'post_delete_user'    => $row['post_delete_user'],
1374   
1375          // Make sure the icon actually exists
1376          'icon_id'            => (isset($icons[$row['icon_id']]['img'], $icons[$row['icon_id']]['height'], $icons[$row['icon_id']]['width'])) ? $row['icon_id'] : 0,
1377          'post_attachment'    => $row['post_attachment'],
1378          'post_visibility'    => $row['post_visibility'],
1379          'post_reported'        => $row['post_reported'],
1380          'post_username'        => $row['post_username'],
1381          'post_text'            => $row['post_text'],
1382          'bbcode_uid'        => $row['bbcode_uid'],
1383          'bbcode_bitfield'    => $row['bbcode_bitfield'],
1384          'enable_smilies'    => $row['enable_smilies'],
1385          'enable_sig'        => $row['enable_sig'],
1386          'friend'            => $row['friend'],
1387          'foe'                => $row['foe'],
1388      );
1389   
1390      /**
1391      * Modify the post rowset containing data to be displayed with posts
1392      *
1393      * @event core.viewtopic_post_rowset_data
1394      * @var    array    rowset_data    Array with the rowset data for this post
1395      * @var    array    row            Array with original user and post data
1396      * @since 3.1.0-a1
1397      */
1398      $vars = array('rowset_data', 'row');
1399      extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_rowset_data', compact($vars)));
1400   
1401      $rowset[$row['post_id']] = $rowset_data;
1402   
1403      // Cache various user specific data ... so we don't have to recompute
1404      // this each time the same user appears on this page
1405      if (!isset($user_cache[$poster_id]))
1406      {
1407          if ($poster_id == ANONYMOUS)
1408          {
1409              $user_cache_data = array(
1410                  'user_type'        => USER_IGNORE,
1411                  'joined'        => '',
1412                  'posts'            => '',
1413   
1414                  'sig'                    => '',
1415                  'sig_bbcode_uid'        => '',
1416                  'sig_bbcode_bitfield'    => '',
1417   
1418                  'online'            => false,
1419                  'avatar'            => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '',
1420                  'rank_title'        => '',
1421                  'rank_image'        => '',
1422                  'rank_image_src'    => '',
1423                  'pm'                => '',
1424                  'email'                => '',
1425                  'jabber'            => '',
1426                  'search'            => '',
1427                  'age'                => '',
1428   
1429                  'username'            => $row['username'],
1430                  'user_colour'        => $row['user_colour'],
1431                  'contact_user'        => '',
1432   
1433                  'warnings'            => 0,
1434                  'allow_pm'            => 0,
1435              );
1436   
1437              /**
1438              * Modify the guest user's data displayed with the posts
1439              *
1440              * @event core.viewtopic_cache_guest_data
1441              * @var    array    user_cache_data    Array with the user's data
1442              * @var    int        poster_id        Poster's user id
1443              * @var    array    row                Array with original user and post data
1444              * @since 3.1.0-a1
1445              */
1446              $vars = array('user_cache_data', 'poster_id', 'row');
1447              extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_guest_data', compact($vars)));
1448   
1449              $user_cache[$poster_id] = $user_cache_data;
1450   
1451              $user_rank_data = phpbb_get_user_rank($row, false);
1452              $user_cache[$poster_id]['rank_title'] = $user_rank_data['title'];
1453              $user_cache[$poster_id]['rank_image'] = $user_rank_data['img'];
1454              $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src'];
1455          }
1456          else
1457          {
1458              $user_sig = '';
1459   
1460              // We add the signature to every posters entry because enable_sig is post dependent
1461              if ($row['user_sig'] && $config['allow_sig'] && $user->optionget('viewsigs'))
1462              {
1463                  $user_sig = $row['user_sig'];
1464              }
1465   
1466              $id_cache[] = $poster_id;
1467   
1468              $user_cache_data = array(
1469                  'user_type'                    => $row['user_type'],
1470                  'user_inactive_reason'        => $row['user_inactive_reason'],
1471   
1472                  'joined'        => $user->format_date($row['user_regdate']),
1473                  'posts'            => $row['user_posts'],
1474                  'warnings'        => (isset($row['user_warnings'])) ? $row['user_warnings'] : 0,
1475   
1476                  'sig'                    => $user_sig,
1477                  'sig_bbcode_uid'        => (!empty($row['user_sig_bbcode_uid'])) ? $row['user_sig_bbcode_uid'] : '',
1478                  'sig_bbcode_bitfield'    => (!empty($row['user_sig_bbcode_bitfield'])) ? $row['user_sig_bbcode_bitfield'] : '',
1479   
1480                  'viewonline'    => $row['user_allow_viewonline'],
1481                  'allow_pm'        => $row['user_allow_pm'],
1482   
1483                  'avatar'        => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '',
1484                  'age'            => '',
1485   
1486                  'rank_title'        => '',
1487                  'rank_image'        => '',
1488                  'rank_image_src'    => '',
1489   
1490                  'username'            => $row['username'],
1491                  'user_colour'        => $row['user_colour'],
1492                  'contact_user'         => $user->lang('CONTACT_USER', get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['username'])),
1493   
1494                  'online'        => false,
1495                  'jabber'        => ($config['jab_enable'] && $row['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&amp;action=jabber&amp;u=$poster_id") : '',
1496                  'search'        => ($config['load_search'] && $auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$poster_id&amp;sr=posts") : '',
1497   
1498                  'author_full'        => get_username_string('full', $poster_id, $row['username'], $row['user_colour']),
1499                  'author_colour'        => get_username_string('colour', $poster_id, $row['username'], $row['user_colour']),
1500                  'author_username'    => get_username_string('username', $poster_id, $row['username'], $row['user_colour']),
1501                  'author_profile'    => get_username_string('profile', $poster_id, $row['username'], $row['user_colour']),
1502              );
1503   
1504              /**
1505              * Modify the users' data displayed with their posts
1506              *
1507              * @event core.viewtopic_cache_user_data
1508              * @var    array    user_cache_data    Array with the user's data
1509              * @var    int        poster_id        Poster's user id
1510              * @var    array    row                Array with original user and post data
1511              * @since 3.1.0-a1
1512              */
1513              $vars = array('user_cache_data', 'poster_id', 'row');
1514              extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_user_data', compact($vars)));
1515   
1516              $user_cache[$poster_id] = $user_cache_data;
1517   
1518              $user_rank_data = phpbb_get_user_rank($row, $row['user_posts']);
1519              $user_cache[$poster_id]['rank_title'] = $user_rank_data['title'];
1520              $user_cache[$poster_id]['rank_image'] = $user_rank_data['img'];
1521              $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src'];
1522   
1523              if ((!empty($row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email'))
1524              {
1525                  $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']);
1526              }
1527              else
1528              {
1529                  $user_cache[$poster_id]['email'] = '';
1530              }
1531   
1532              if ($config['allow_birthdays'] && !empty($row['user_birthday']))
1533              {
1534                  list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $row['user_birthday']));
1535   
1536                  if ($bday_year)
1537                  {
1538                      $diff = $now['mon'] - $bday_month;
1539                      if ($diff == 0)
1540                      {
1541                          $diff = ($now['mday'] - $bday_day < 0) ? 1 : 0;
1542                      }
1543                      else
1544                      {
1545                          $diff = ($diff < 0) ? 1 : 0;
1546                      }
1547   
1548                      $user_cache[$poster_id]['age'] = (int) ($now['year'] - $bday_year - $diff);
1549                  }
1550              }
1551          }
1552      }
1553  }
1554  $db->sql_freeresult($result);
1555   
1556  // Load custom profile fields
1557  if ($config['load_cpf_viewtopic'])
1558  {
1559      /* @var $cp \phpbb\profilefields\manager */
1560      $cp = $phpbb_container->get('profilefields.manager');
1561   
1562      // Grab all profile fields from users in id cache for later use - similar to the poster cache
1563      $profile_fields_tmp = $cp->grab_profile_fields_data($id_cache);
1564   
1565      // filter out fields not to be displayed on viewtopic. Yes, it's a hack, but this shouldn't break any MODs.
1566      $profile_fields_cache = array();
1567      foreach ($profile_fields_tmp as $profile_user_id => $profile_fields)
1568      {
1569          $profile_fields_cache[$profile_user_id] = array();
1570          foreach ($profile_fields as $used_ident => $profile_field)
1571          {
1572              if ($profile_field['data']['field_show_on_vt'])
1573              {
1574                  $profile_fields_cache[$profile_user_id][$used_ident] = $profile_field;
1575              }
1576          }
1577      }
1578      unset($profile_fields_tmp);
1579  }
1580   
1581  // Generate online information for user
1582  if ($config['load_onlinetrack'] && count($id_cache))
1583  {
1584      $sql = 'SELECT session_user_id, MAX(session_time) as online_time, MIN(session_viewonline) AS viewonline
1585          FROM ' . SESSIONS_TABLE . '
1586          WHERE ' . $db->sql_in_set('session_user_id', $id_cache) . '
1587          GROUP BY session_user_id';
1588      $result = $db->sql_query($sql);
1589   
1590      $update_time = $config['load_online_time'] * 60;
1591      while ($row = $db->sql_fetchrow($result))
1592      {
1593          $user_cache[$row['session_user_id']]['online'] = (time() - $update_time < $row['online_time'] && (($row['viewonline']) || $auth->acl_get('u_viewonline'))) ? true : false;
1594      }
1595      $db->sql_freeresult($result);
1596  }
1597  unset($id_cache);
1598   
1599  // Pull attachment data
1600  if (count($attach_list))
1601  {
1602      if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
1603      {
1604          $sql = 'SELECT *
1605              FROM ' . ATTACHMENTS_TABLE . '
1606              WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . '
1607                  AND in_message = 0
1608              ORDER BY attach_id DESC, post_msg_id ASC';
1609          $result = $db->sql_query($sql);
1610   
1611          while ($row = $db->sql_fetchrow($result))
1612          {
1613              $attachments[$row['post_msg_id']][] = $row;
1614          }
1615          $db->sql_freeresult($result);
1616   
1617          // No attachments exist, but post table thinks they do so go ahead and reset post_attach flags
1618          if (!count($attachments))
1619          {
1620              $sql = 'UPDATE ' . POSTS_TABLE . '
1621                  SET post_attachment = 0
1622                  WHERE ' . $db->sql_in_set('post_id', $attach_list);
1623              $db->sql_query($sql);
1624   
1625              // We need to update the topic indicator too if the complete topic is now without an attachment
1626              if (count($rowset) != $total_posts)
1627              {
1628                  // Not all posts are displayed so we query the db to find if there's any attachment for this topic
1629                  $sql = 'SELECT a.post_msg_id as post_id
1630                      FROM ' . ATTACHMENTS_TABLE . ' a, ' . POSTS_TABLE . " p
1631                      WHERE p.topic_id = $topic_id
1632                          AND p.post_visibility = " . ITEM_APPROVED . '
1633                          AND p.topic_id = a.topic_id';
1634                  $result = $db->sql_query_limit($sql, 1);
1635                  $row = $db->sql_fetchrow($result);
1636                  $db->sql_freeresult($result);
1637   
1638                  if (!$row)
1639                  {
1640                      $sql = 'UPDATE ' . TOPICS_TABLE . "
1641                          SET topic_attachment = 0
1642                          WHERE topic_id = $topic_id";
1643                      $db->sql_query($sql);
1644                  }
1645              }
1646              else
1647              {
1648                  $sql = 'UPDATE ' . TOPICS_TABLE . "
1649                      SET topic_attachment = 0
1650                      WHERE topic_id = $topic_id";
1651                  $db->sql_query($sql);
1652              }
1653          }
1654          else if ($has_approved_attachments && !$topic_data['topic_attachment'])
1655          {
1656              // Topic has approved attachments but its flag is wrong
1657              $sql = 'UPDATE ' . TOPICS_TABLE . "
1658                  SET topic_attachment = 1
1659                  WHERE topic_id = $topic_id";
1660              $db->sql_query($sql);
1661   
1662              $topic_data['topic_attachment'] = 1;
1663          }
1664          else if ($has_unapproved_attachments && !$topic_data['topic_attachment'])
1665          {
1666              // Topic has only unapproved attachments but we have the right to see and download them
1667              $topic_data['topic_attachment'] = 1;
1668          }
1669      }
1670      else
1671      {
1672          $display_notice = true;
1673      }
1674  }
1675   
1676  if ($config['enable_accurate_pm_button'])
1677  {
1678      // Get the list of users who can receive private messages
1679      $can_receive_pm_list = $auth->acl_get_list(array_keys($user_cache), 'u_readpm');
1680      $can_receive_pm_list = (empty($can_receive_pm_list) || !isset($can_receive_pm_list[0]['u_readpm'])) ? array() : $can_receive_pm_list[0]['u_readpm'];
1681   
1682      // Get the list of permanently banned users
1683      $permanently_banned_users = phpbb_get_banned_user_ids(array_keys($user_cache), false);
1684  }
1685  else
1686  {
1687      $can_receive_pm_list = array_keys($user_cache);
1688      $permanently_banned_users = [];
1689  }
1690   
1691  $i_total = count($rowset) - 1;
1692  $prev_post_id = '';
1693   
1694  $template->assign_vars(array(
1695      'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'],
1696      'S_NUM_POSTS' => count($post_list))
1697  );
1698   
1699  /**
1700  * Event to modify the post, poster and attachment data before assigning the posts
1701  *
1702  * @event core.viewtopic_modify_post_data
1703  * @var    int        forum_id    Forum ID
1704  * @var    int        topic_id    Topic ID
1705  * @var    array    topic_data    Array with topic data
1706  * @var    array    post_list    Array with post_ids we are going to display
1707  * @var    array    rowset        Array with post_id => post data
1708  * @var    array    user_cache    Array with prepared user data
1709  * @var    int        start        Pagination information
1710  * @var    int        sort_days    Display posts of previous x days
1711  * @var    string    sort_key    Key the posts are sorted by
1712  * @var    string    sort_dir    Direction the posts are sorted by
1713  * @var    bool    display_notice                Shall we display a notice instead of attachments
1714  * @var    bool    has_approved_attachments    Does the topic have approved attachments
1715  * @var    array    attachments                    List of attachments post_id => array of attachments
1716  * @var    array    permanently_banned_users    List of permanently banned users
1717  * @var    array    can_receive_pm_list            Array with posters that can receive pms
1718  * @since 3.1.0-RC3
1719  */
1720  $vars = array(
1721      'forum_id',
1722      'topic_id',
1723      'topic_data',
1724      'post_list',
1725      'rowset',
1726      'user_cache',
1727      'sort_days',
1728      'sort_key',
1729      'sort_dir',
1730      'start',
1731      'permanently_banned_users',
1732      'can_receive_pm_list',
1733      'display_notice',
1734      'has_approved_attachments',
1735      'attachments',
1736  );
1737  extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_data', compact($vars)));
1738   
1739  // Output the posts
1740  $first_unread = $post_unread = false;
1741  for ($i = 0, $end = count($post_list); $i < $end; ++$i)
1742  {
1743      // A non-existing rowset only happens if there was no user present for the entered poster_id
1744      // This could be a broken posts table.
1745      if (!isset($rowset[$post_list[$i]]))
1746      {
1747          continue;
1748      }
1749   
1750      $row = $rowset[$post_list[$i]];
1751      $poster_id = $row['user_id'];
1752   
1753      // End signature parsing, only if needed
1754      if ($user_cache[$poster_id]['sig'] && $row['enable_sig'] && empty($user_cache[$poster_id]['sig_parsed']))
1755      {
1756          $parse_flags = ($user_cache[$poster_id]['sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
1757          $user_cache[$poster_id]['sig'] = generate_text_for_display($user_cache[$poster_id]['sig'], $user_cache[$poster_id]['sig_bbcode_uid'], $user_cache[$poster_id]['sig_bbcode_bitfield'],  $parse_flags, true);
1758          $user_cache[$poster_id]['sig_parsed'] = true;
1759      }
1760   
1761      // Parse the message and subject
1762      $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
1763      $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true);
1764   
1765      if (!empty($attachments[$row['post_id']]))
1766      {
1767          parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count);
1768      }
1769   
1770      // Replace naughty words such as farty pants
1771      $row['post_subject'] = censor_text($row['post_subject']);
1772   
1773      // Highlight active words (primarily for search)
1774      if ($highlight_match)
1775      {
1776          $message = preg_replace('#(?!<.*)(?<!\w)(' . $highlight_match . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#is', '<span class="posthilit">\1</span>', $message);
1777          $row['post_subject'] = preg_replace('#(?!<.*)(?<!\w)(' . $highlight_match . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#is', '<span class="posthilit">\1</span>', $row['post_subject']);
1778      }
1779   
1780      // Editing information
1781      if (($row['post_edit_count'] && $config['display_last_edited']) || $row['post_edit_reason'])
1782      {
1783          // Get usernames for all following posts if not already stored
1784          if (!count($post_edit_list) && ($row['post_edit_reason'] || ($row['post_edit_user'] && !isset($user_cache[$row['post_edit_user']]))))
1785          {
1786              // Remove all post_ids already parsed (we do not have to check them)
1787              $post_storage_list = (!$store_reverse) ? array_slice($post_list, $i) : array_slice(array_reverse($post_list), $i);
1788   
1789              $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour
1790                  FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1791                  WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . '
1792                      AND p.post_edit_count <> 0
1793                      AND p.post_edit_user <> 0
1794                      AND p.post_edit_user = u.user_id';
1795              $result2 = $db->sql_query($sql);
1796              while ($user_edit_row = $db->sql_fetchrow($result2))
1797              {
1798                  $post_edit_list[$user_edit_row['user_id']] = $user_edit_row;
1799              }
1800              $db->sql_freeresult($result2);
1801   
1802              unset($post_storage_list);
1803          }
1804   
1805          if ($row['post_edit_reason'])
1806          {
1807              // User having edited the post also being the post author?
1808              if (!$row['post_edit_user'] || $row['post_edit_user'] == $poster_id)
1809              {
1810                  $display_username = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']);
1811              }
1812              else
1813              {
1814                  $display_username = get_username_string('full', $row['post_edit_user'], $post_edit_list[$row['post_edit_user']]['username'], $post_edit_list[$row['post_edit_user']]['user_colour']);
1815              }
1816   
1817              $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true));
1818          }
1819          else
1820          {
1821              if ($row['post_edit_user'] && !isset($user_cache[$row['post_edit_user']]))
1822              {
1823                  $user_cache[$row['post_edit_user']] = $post_edit_list[$row['post_edit_user']];
1824              }
1825   
1826              // User having edited the post also being the post author?
1827              if (!$row['post_edit_user'] || $row['post_edit_user'] == $poster_id)
1828              {
1829                  $display_username = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']);
1830              }
1831              else
1832              {
1833                  $display_username = get_username_string('full', $row['post_edit_user'], $user_cache[$row['post_edit_user']]['username'], $user_cache[$row['post_edit_user']]['user_colour']);
1834              }
1835   
1836              $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true));
1837          }
1838      }
1839      else
1840      {
1841          $l_edited_by = '';
1842      }
1843   
1844      // Deleting information
1845      if ($row['post_visibility'] == ITEM_DELETED && $row['post_delete_user'])
1846      {
1847          // Get usernames for all following posts if not already stored
1848          if (!count($post_delete_list) && ($row['post_delete_reason'] || ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']]))))
1849          {
1850              // Remove all post_ids already parsed (we do not have to check them)
1851              $post_storage_list = (!$store_reverse) ? array_slice($post_list, $i) : array_slice(array_reverse($post_list), $i);
1852   
1853              $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour
1854                  FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1855                  WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . '
1856                      AND p.post_delete_user <> 0
1857                      AND p.post_delete_user = u.user_id';
1858              $result2 = $db->sql_query($sql);
1859              while ($user_delete_row = $db->sql_fetchrow($result2))
1860              {
1861                  $post_delete_list[$user_delete_row['user_id']] = $user_delete_row;
1862              }
1863              $db->sql_freeresult($result2);
1864   
1865              unset($post_storage_list);
1866          }
1867   
1868          if ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']]))
1869          {
1870              $user_cache[$row['post_delete_user']] = $post_delete_list[$row['post_delete_user']];
1871          }
1872   
1873          $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']);
1874   
1875          // User having deleted the post also being the post author?
1876          if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id)
1877          {
1878              $display_username = $display_postername;
1879          }
1880          else
1881          {
1882              $display_username = get_username_string('full', $row['post_delete_user'], $user_cache[$row['post_delete_user']]['username'], $user_cache[$row['post_delete_user']]['user_colour']);
1883          }
1884   
1885          if ($row['post_delete_reason'])
1886          {
1887              $l_deleted_message = $user->lang('POST_DELETED_BY_REASON', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true), $row['post_delete_reason']);
1888          }
1889          else
1890          {
1891              $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true));
1892          }
1893          $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($row['post_delete_time'], false, true));
1894      }
1895      else
1896      {
1897          $l_deleted_by = $l_deleted_message = '';
1898      }
1899   
1900      // Bump information
1901      if ($topic_data['topic_bumped'] && $row['post_id'] == $topic_data['topic_last_post_id'] && isset($user_cache[$topic_data['topic_bumper']]) )
1902      {
1903          // It is safe to grab the username from the user cache array, we are at the last
1904          // post and only the topic poster and last poster are allowed to bump.
1905          // Admins and mods are bound to the above rules too...
1906          $l_bumped_by = sprintf($user->lang['BUMPED_BY'], $user_cache[$topic_data['topic_bumper']]['username'], $user->format_date($topic_data['topic_last_post_time'], false, true));
1907      }
1908      else
1909      {
1910          $l_bumped_by = '';
1911      }
1912   
1913      $cp_row = array();
1914   
1915      //
1916      if ($config['load_cpf_viewtopic'])
1917      {
1918          $cp_row = (isset($profile_fields_cache[$poster_id])) ? $cp->generate_profile_fields_template_data($profile_fields_cache[$poster_id]) : array();
1919      }
1920   
1921      $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false;
1922   
1923      $s_first_unread = false;
1924      if (!$first_unread && $post_unread)
1925      {
1926          $s_first_unread = $first_unread = true;
1927      }
1928   
1929      $force_edit_allowed = $force_delete_allowed = $force_softdelete_allowed = false;
1930   
1931      $s_cannot_edit = !$auth->acl_get('f_edit', $forum_id) || $user->data['user_id'] != $poster_id;
1932      $s_cannot_edit_time = $config['edit_time'] && $row['post_time'] <= time() - ($config['edit_time'] * 60);
1933      $s_cannot_edit_locked = ($topic_data['topic_status'] == ITEM_LOCKED && !$auth->acl_get('m_lock', $forum_id)) || $row['post_edit_locked'];
1934   
1935      $s_cannot_delete = $user->data['user_id'] != $poster_id || (
1936              !$auth->acl_get('f_delete', $forum_id) &&
1937              (!$auth->acl_get('f_softdelete', $forum_id) || $row['post_visibility'] == ITEM_DELETED)
1938      );
1939      $s_cannot_delete_lastpost = $topic_data['topic_last_post_id'] != $row['post_id'];
1940      $s_cannot_delete_time = $config['delete_time'] && $row['post_time'] <= time() - ($config['delete_time'] * 60);
1941      // we do not want to allow removal of the last post if a moderator locked it!
1942      $s_cannot_delete_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked'];
1943   
1944      /**
1945      * This event allows you to modify the conditions for the "can edit post" and "can delete post" checks
1946      *
1947      * @event core.viewtopic_modify_post_action_conditions
1948      * @var    array    row            Array with post data
1949      * @var    array    topic_data    Array with topic data
1950      * @var    bool    force_edit_allowed        Allow the user to edit the post (all permissions and conditions are ignored)
1951      * @var    bool    s_cannot_edit            User can not edit the post because it's not his
1952      * @var    bool    s_cannot_edit_locked    User can not edit the post because it's locked
1953      * @var    bool    s_cannot_edit_time        User can not edit the post because edit_time has passed
1954      * @var    bool    force_delete_allowed        Allow the user to delete the post (all permissions and conditions are ignored)
1955      * @var    bool    s_cannot_delete                User can not delete the post because it's not his
1956      * @var    bool    s_cannot_delete_lastpost    User can not delete the post because it's not the last post of the topic
1957      * @var    bool    s_cannot_delete_locked        User can not delete the post because it's locked
1958      * @var    bool    s_cannot_delete_time        User can not delete the post because edit_time has passed
1959      * @var    bool    force_softdelete_allowed    Allow the user to ыoftdelete the post (all permissions and conditions are ignored)
1960      * @since 3.1.0-b4
1961      * @changed 3.1.11-RC1 Added force_softdelete_allowed var
1962      */
1963      $vars = array(
1964          'row',
1965          'topic_data',
1966          'force_edit_allowed',
1967          's_cannot_edit',
1968          's_cannot_edit_locked',
1969          's_cannot_edit_time',
1970          'force_delete_allowed',
1971          's_cannot_delete',
1972          's_cannot_delete_lastpost',
1973          's_cannot_delete_locked',
1974          's_cannot_delete_time',
1975          'force_softdelete_allowed',
1976      );
1977      extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_action_conditions', compact($vars)));
1978   
1979      $edit_allowed = $force_edit_allowed || ($user->data['is_registered'] && ($auth->acl_get('m_edit', $forum_id) || (
1980          !$s_cannot_edit &&
1981          !$s_cannot_edit_time &&
1982          !$s_cannot_edit_locked
1983      )));
1984   
1985      $quote_allowed = $auth->acl_get('m_edit', $forum_id) || ($topic_data['topic_status'] != ITEM_LOCKED &&
1986          ($user->data['user_id'] == ANONYMOUS || $auth->acl_get('f_reply', $forum_id))
1987      );
1988   
1989      // Only display the quote button if the post is quotable.  Posts not approved are not quotable.
1990      $quote_allowed = ($quote_allowed && $row['post_visibility'] == ITEM_APPROVED) ? true : false;
1991   
1992      $delete_allowed = $force_delete_allowed || ($user->data['is_registered'] && (
1993          ($auth->acl_get('m_delete', $forum_id) || ($auth->acl_get('m_softdelete', $forum_id) && $row['post_visibility'] != ITEM_DELETED)) ||
1994          (!$s_cannot_delete && !$s_cannot_delete_lastpost && !$s_cannot_delete_time && !$s_cannot_delete_locked)
1995      ));
1996   
1997      $softdelete_allowed = $force_softdelete_allowed || (($auth->acl_get('m_softdelete', $forum_id) ||
1998          ($auth->acl_get('f_softdelete', $forum_id) && $user->data['user_id'] == $poster_id)) && ($row['post_visibility'] != ITEM_DELETED));
1999   
2000      $permanent_delete_allowed = $force_delete_allowed || ($auth->acl_get('m_delete', $forum_id) ||
2001          ($auth->acl_get('f_delete', $forum_id) && $user->data['user_id'] == $poster_id));
2002   
2003      // Can this user receive a Private Message?
2004      $can_receive_pm = (
2005          // They must be a "normal" user
2006          $user_cache[$poster_id]['user_type'] != USER_IGNORE &&
2007   
2008          // They must not be deactivated by the administrator
2009          ($user_cache[$poster_id]['user_type'] != USER_INACTIVE || $user_cache[$poster_id]['user_inactive_reason'] != INACTIVE_MANUAL) &&
2010   
2011          // They must be able to read PMs
2012          in_array($poster_id, $can_receive_pm_list) &&
2013   
2014          // They must not be permanently banned
2015          !in_array($poster_id, $permanently_banned_users) &&
2016   
2017          // They must allow users to contact via PM
2018          (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $user_cache[$poster_id]['allow_pm'])
2019      );
2020   
2021      $u_pm = '';
2022   
2023      if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm)
2024      {
2025          $u_pm = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;mode=compose&amp;action=quotepost&amp;p=' . $row['post_id']);
2026      }
2027   
2028      //
2029      $post_row = array(
2030          'POST_AUTHOR_FULL'        => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_full'] : get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
2031          'POST_AUTHOR_COLOUR'    => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_colour'] : get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
2032          'POST_AUTHOR'            => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_username'] : get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
2033          'U_POST_AUTHOR'            => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_profile'] : get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
2034   
2035          'RANK_TITLE'        => $user_cache[$poster_id]['rank_title'],
2036          'RANK_IMG'            => $user_cache[$poster_id]['rank_image'],
2037          'RANK_IMG_SRC'        => $user_cache[$poster_id]['rank_image_src'],
2038          'POSTER_JOINED'        => $user_cache[$poster_id]['joined'],
2039          'POSTER_POSTS'        => $user_cache[$poster_id]['posts'],
2040          'POSTER_AVATAR'        => $user_cache[$poster_id]['avatar'],
2041          'POSTER_WARNINGS'    => $auth->acl_get('m_warn') ? $user_cache[$poster_id]['warnings'] : '',
2042          'POSTER_AGE'        => $user_cache[$poster_id]['age'],
2043          'CONTACT_USER'        => $user_cache[$poster_id]['contact_user'],
2044   
2045          'POST_DATE'            => $user->format_date($row['post_time'], false, ($view == 'print') ? true : false),
2046          'POST_DATE_RFC3339'    => gmdate(DATE_RFC3339, $row['post_time']),
2047          'POST_SUBJECT'        => $row['post_subject'],
2048          'MESSAGE'            => $message,
2049          'SIGNATURE'            => ($row['enable_sig']) ? $user_cache[$poster_id]['sig'] : '',
2050          'EDITED_MESSAGE'    => $l_edited_by,
2051          'EDIT_REASON'        => $row['post_edit_reason'],
2052          'DELETED_MESSAGE'    => $l_deleted_by,
2053          'DELETE_REASON'        => $row['post_delete_reason'],
2054          'BUMPED_MESSAGE'    => $l_bumped_by,
2055   
2056          'MINI_POST_IMG'            => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'),
2057          'POST_ICON_IMG'            => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['img'] : '',
2058          'POST_ICON_IMG_WIDTH'    => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['width'] : '',
2059          'POST_ICON_IMG_HEIGHT'    => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['height'] : '',
2060          'POST_ICON_IMG_ALT'     => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['alt'] : '',
2061          'ONLINE_IMG'            => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? '' : (($user_cache[$poster_id]['online']) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')),
2062          'S_ONLINE'                => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? false : (($user_cache[$poster_id]['online']) ? true : false),
2063   
2064          'U_EDIT'            => ($edit_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&amp;p={$row['post_id']}") : '',
2065          'U_QUOTE'            => ($quote_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=quote&amp;p={$row['post_id']}") : '',
2066          'U_INFO'            => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&amp;mode=post_details&amp;p=" . $row['post_id'], true, $user->session_id) : '',
2067          'U_DELETE'            => ($delete_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=' . (($softdelete_allowed) ? 'soft_delete' : 'delete') . "&amp;p={$row['post_id']}") : '',
2068   
2069          'U_SEARCH'        => $user_cache[$poster_id]['search'],
2070          'U_PM'            => $u_pm,
2071          'U_EMAIL'        => $user_cache[$poster_id]['email'],
2072          'U_JABBER'        => $user_cache[$poster_id]['jabber'],
2073   
2074          'U_APPROVE_ACTION'    => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&amp;p={$row['post_id']}&amp;f={$row['forum_id']}&amp;redirect=" . urlencode(str_replace('&amp;', '&', $viewtopic_url . '&amp;p=' . $row['post_id'] . '#p' . $row['post_id']))),
2075          'U_REPORT'            => ($auth->acl_get('f_report', $forum_id)) ? $phpbb_container->get('controller.helper')->route('phpbb_report_post_controller', array('id' => $row['post_id'])) : '',
2076          'U_MCP_REPORT'        => ($auth->acl_get('m_report', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=report_details&amp;p=' . $row['post_id'], true, $user->session_id) : '',
2077          'U_MCP_APPROVE'        => ($auth->acl_get('m_approve', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=approve_details&amp;p=' . $row['post_id'], true, $user->session_id) : '',
2078          'U_MCP_RESTORE'        => ($auth->acl_get('m_approve', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=' . (($topic_data['topic_visibility'] != ITEM_DELETED) ? 'deleted_posts' : 'deleted_topics') . '&amp;p=' . $row['post_id'], true, $user->session_id) : '',
2079          'U_MINI_POST'        => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'],
2080          'U_MINI_POST_VIEW'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '&amp;view=show#p' . $row['post_id'],
2081          'U_NEXT_POST_ID'    => ($i < $i_total && isset($rowset[$post_list[$i + 1]])) ? $rowset[$post_list[$i + 1]]['post_id'] : '',
2082          'U_PREV_POST_ID'    => $prev_post_id,
2083          'U_NOTES'            => ($auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&amp;mode=user_notes&amp;u=' . $poster_id, true, $user->session_id) : '',
2084          'U_WARN'            => ($auth->acl_get('m_warn') && $poster_id != $user->data['user_id'] && $poster_id != ANONYMOUS) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&amp;mode=warn_post&amp;p=' . $row['post_id'], true, $user->session_id) : '',
2085   
2086          'POST_ID'            => $row['post_id'],
2087          'POST_NUMBER'        => $i + $start + 1,
2088          'POSTER_ID'            => $poster_id,
2089          'MINI_POST'            => ($post_unread) ? $user->lang['UNREAD_POST'] : $user->lang['POST'],
2090   
2091   
2092          'S_HAS_ATTACHMENTS'    => (!empty($attachments[$row['post_id']])) ? true : false,
2093          'S_MULTIPLE_ATTACHMENTS'    => !empty($attachments[$row['post_id']]) && count($attachments[$row['post_id']]) > 1,
2094          'S_POST_UNAPPROVED'    => ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) ? true : false,
2095          'S_CAN_APPROVE'        => $auth->acl_get('m_approve', $forum_id),
2096          'S_POST_DELETED'    => ($row['post_visibility'] == ITEM_DELETED) ? true : false,
2097          'L_POST_DELETED_MESSAGE'    => $l_deleted_message,
2098          'S_POST_REPORTED'    => ($row['post_reported'] && $auth->acl_get('m_report', $forum_id)) ? true : false,
2099          'S_DISPLAY_NOTICE'    => $display_notice && $row['post_attachment'],
2100          'S_FRIEND'            => ($row['friend']) ? true : false,
2101          'S_UNREAD_POST'        => $post_unread,
2102          'S_FIRST_UNREAD'    => $s_first_unread,
2103          'S_CUSTOM_FIELDS'    => (isset($cp_row['row']) && count($cp_row['row'])) ? true : false,
2104          'S_TOPIC_POSTER'    => ($topic_data['topic_poster'] == $poster_id) ? true : false,
2105          'S_FIRST_POST'        => ($topic_data['topic_first_post_id'] == $row['post_id']) ? true : false,
2106   
2107          'S_IGNORE_POST'        => ($row['foe']) ? true : false,
2108          'L_IGNORE_POST'        => ($row['foe']) ? sprintf($user->lang['POST_BY_FOE'], get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '',
2109          'S_POST_HIDDEN'        => $row['hide_post'],
2110          'S_DELETE_PERMANENT'    => $permanent_delete_allowed,
2111      );
2112   
2113      $user_poster_data = $user_cache[$poster_id];
2114   
2115      $current_row_number = $i;
2116   
2117      /**
2118      * Modify the posts template block
2119      *
2120      * @event core.viewtopic_modify_post_row
2121      * @var    int        start                Start item of this page
2122      * @var    int        current_row_number    Number of the post on this page
2123      * @var    int        end                    Number of posts on this page
2124      * @var    int        total_posts            Total posts count
2125      * @var    int        poster_id            Post author id
2126      * @var    array    row                    Array with original post and user data
2127      * @var    array    cp_row                Custom profile field data of the poster
2128      * @var    array    attachments            List of attachments
2129      * @var    array    user_poster_data    Poster's data from user cache
2130      * @var    array    post_row            Template block array of the post
2131      * @var    array    topic_data            Array with topic data
2132      * @var    array    user_cache            Array with cached user data
2133      * @var    array    post_edit_list        Array with post edited list
2134      * @since 3.1.0-a1
2135      * @changed 3.1.0-a3 Added vars start, current_row_number, end, attachments
2136      * @changed 3.1.0-b3 Added topic_data array, total_posts
2137      * @changed 3.1.0-RC3 Added poster_id
2138      * @changed 3.2.2-RC1 Added user_cache and post_edit_list
2139      */
2140      $vars = array(
2141          'start',
2142          'current_row_number',
2143          'end',
2144          'total_posts',
2145          'poster_id',
2146          'row',
2147          'cp_row',
2148          'attachments',
2149          'user_poster_data',
2150          'post_row',
2151          'topic_data',
2152          'user_cache',
2153          'post_edit_list',
2154      );
2155      extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_row', compact($vars)));
2156   
2157      $i = $current_row_number;
2158   
2159      if (isset($cp_row['row']) && count($cp_row['row']))
2160      {
2161          $post_row = array_merge($post_row, $cp_row['row']);
2162      }
2163   
2164      // Dump vars into template
2165      $template->assign_block_vars('postrow', $post_row);
2166   
2167      $contact_fields = array(
2168          array(
2169              'ID'        => 'pm',
2170              'NAME'         => $user->lang['SEND_PRIVATE_MESSAGE'],
2171              'U_CONTACT'    => $post_row['U_PM'],
2172          ),
2173          array(
2174              'ID'        => 'email',
2175              'NAME'        => $user->lang['SEND_EMAIL'],
2176              'U_CONTACT'    => $user_cache[$poster_id]['email'],
2177          ),
2178          array(
2179              'ID'        => 'jabber',
2180              'NAME'        => $user->lang['JABBER'],
2181              'U_CONTACT'    => $user_cache[$poster_id]['jabber'],
2182          ),
2183      );
2184   
2185      foreach ($contact_fields as $field)
2186      {
2187          if ($field['U_CONTACT'])
2188          {
2189              $template->assign_block_vars('postrow.contact', $field);
2190          }
2191      }
2192   
2193      if (!empty($cp_row['blockrow']))
2194      {
2195          foreach ($cp_row['blockrow'] as $field_data)
2196          {
2197              $template->assign_block_vars('postrow.custom_fields', $field_data);
2198   
2199              if ($field_data['S_PROFILE_CONTACT'])
2200              {
2201                  $template->assign_block_vars('postrow.contact', array(
2202                      'ID'        => $field_data['PROFILE_FIELD_IDENT'],
2203                      'NAME'        => $field_data['PROFILE_FIELD_NAME'],
2204                      'U_CONTACT'    => $field_data['PROFILE_FIELD_CONTACT'],
2205                  ));
2206              }
2207          }
2208      }
2209   
2210      // Display not already displayed Attachments for this post, we already parsed them. ;)
2211      if (!empty($attachments[$row['post_id']]))
2212      {
2213          foreach ($attachments[$row['post_id']] as $attachment)
2214          {
2215              $template->assign_block_vars('postrow.attachment', array(
2216                  'DISPLAY_ATTACHMENT'    => $attachment)
2217              );
2218          }
2219      }
2220   
2221      $current_row_number = $i;
2222   
2223      /**
2224      * Event after the post data has been assigned to the template
2225      *
2226      * @event core.viewtopic_post_row_after
2227      * @var    int        start                Start item of this page
2228      * @var    int        current_row_number    Number of the post on this page
2229      * @var    int        end                    Number of posts on this page
2230      * @var    int        total_posts            Total posts count
2231      * @var    array    row                    Array with original post and user data
2232      * @var    array    cp_row                Custom profile field data of the poster
2233      * @var    array    attachments            List of attachments
2234      * @var    array    user_poster_data    Poster's data from user cache
2235      * @var    array    post_row            Template block array of the post
2236      * @var    array    topic_data            Array with topic data
2237      * @since 3.1.0-a3
2238      * @changed 3.1.0-b3 Added topic_data array, total_posts
2239      */
2240      $vars = array(
2241          'start',
2242          'current_row_number',
2243          'end',
2244          'total_posts',
2245          'row',
2246          'cp_row',
2247          'attachments',
2248          'user_poster_data',
2249          'post_row',
2250          'topic_data',
2251      );
2252      extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_row_after', compact($vars)));
2253   
2254      $i = $current_row_number;
2255   
2256      $prev_post_id = $row['post_id'];
2257   
2258      unset($rowset[$post_list[$i]]);
2259      unset($attachments[$row['post_id']]);
2260  }
2261  unset($rowset, $user_cache);
2262   
2263  // Update topic view and if necessary attachment view counters ... but only for humans and if this is the first 'page view'
2264  if (isset($user->data['session_page']) && !$user->data['is_bot'] && (strpos($user->data['session_page'], '&t=' . $topic_id) === false || isset($user->data['session_created'])))
2265  {
2266      $sql = 'UPDATE ' . TOPICS_TABLE . '
2267          SET topic_views = topic_views + 1, topic_last_view_time = ' . time() . "
2268          WHERE topic_id = $topic_id";
2269      $db->sql_query($sql);
2270   
2271      // Update the attachment download counts
2272      if (count($update_count))
2273      {
2274          $sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
2275              SET download_count = download_count + 1
2276              WHERE ' . $db->sql_in_set('attach_id', array_unique($update_count));
2277          $db->sql_query($sql);
2278      }
2279  }
2280   
2281  // Only mark topic if it's currently unread. Also make sure we do not set topic tracking back if earlier pages are viewed.
2282  if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id] && $max_post_time > $topic_tracking_info[$topic_id])
2283  {
2284      markread('topic', $forum_id, $topic_id, $max_post_time);
2285   
2286      // Update forum info
2287      $all_marked_read = update_forum_tracking_info($forum_id, $topic_data['forum_last_post_time'], (isset($topic_data['forum_mark_time'])) ? $topic_data['forum_mark_time'] : false, false);
2288  }
2289  else
2290  {
2291      $all_marked_read = true;
2292  }
2293   
2294  // If there are absolutely no more unread posts in this forum
2295  // and unread posts shown, we can safely show the #unread link
2296  if ($all_marked_read)
2297  {
2298      if ($post_unread)
2299      {
2300          $template->assign_vars(array(
2301              'U_VIEW_UNREAD_POST'    => '#unread',
2302          ));
2303      }
2304      else if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id])
2305      {
2306          $template->assign_vars(array(
2307              'U_VIEW_UNREAD_POST'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id&amp;view=unread") . '#unread',
2308          ));
2309      }
2310  }
2311  else if (!$all_marked_read)
2312  {
2313      $last_page = ((floor($start / $config['posts_per_page']) + 1) == max(ceil($total_posts / $config['posts_per_page']), 1)) ? true : false;
2314   
2315      // What can happen is that we are at the last displayed page. If so, we also display the #unread link based in $post_unread
2316      if ($last_page && $post_unread)
2317      {
2318          $template->assign_vars(array(
2319              'U_VIEW_UNREAD_POST'    => '#unread',
2320          ));
2321      }
2322      else if (!$last_page)
2323      {
2324          $template->assign_vars(array(
2325              'U_VIEW_UNREAD_POST'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id&amp;view=unread") . '#unread',
2326          ));
2327      }
2328  }
2329   
2330  // let's set up quick_reply
2331  $s_quick_reply = false;
2332  if ($user->data['is_registered'] && $config['allow_quick_reply'] && ($topic_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) && $auth->acl_get('f_reply', $forum_id))
2333  {
2334      // Quick reply enabled forum
2335      $s_quick_reply = (($topic_data['forum_status'] == ITEM_UNLOCKED && $topic_data['topic_status'] == ITEM_UNLOCKED) || $auth->acl_get('m_edit', $forum_id)) ? true : false;
2336  }
2337   
2338  if ($s_can_vote || $s_quick_reply)
2339  {
2340      add_form_key('posting');
2341   
2342      if ($s_quick_reply)
2343      {
2344          $s_attach_sig    = $config['allow_sig'] && $user->optionget('attachsig') && $auth->acl_get('f_sigs', $forum_id) && $auth->acl_get('u_sig');
2345          $s_smilies        = $config['allow_smilies'] && $user->optionget('smilies') && $auth->acl_get('f_smilies', $forum_id);
2346          $s_bbcode        = $config['allow_bbcode'] && $user->optionget('bbcode') && $auth->acl_get('f_bbcode', $forum_id);
2347          $s_notify        = $config['allow_topic_notify'] && ($user->data['user_notify'] || $s_watching_topic['is_watching']);
2348   
2349          $qr_hidden_fields = array(
2350              'topic_cur_post_id'        => (int) $topic_data['topic_last_post_id'],
2351              'topic_id'                => (int) $topic_data['topic_id'],
2352              'forum_id'                => (int) $forum_id,
2353          );
2354   
2355          // Originally we use checkboxes and check with isset(), so we only provide them if they would be checked
2356          (!$s_bbcode)                    ? $qr_hidden_fields['disable_bbcode'] = 1        : true;
2357          (!$s_smilies)                    ? $qr_hidden_fields['disable_smilies'] = 1        : true;
2358          (!$config['allow_post_links'])    ? $qr_hidden_fields['disable_magic_url'] = 1    : true;
2359          ($s_attach_sig)                    ? $qr_hidden_fields['attach_sig'] = 1            : true;
2360          ($s_notify)                        ? $qr_hidden_fields['notify'] = 1                : true;
2361          ($topic_data['topic_status'] == ITEM_LOCKED) ? $qr_hidden_fields['lock_topic'] = 1 : true;
2362   
2363          $tpl_ary = [
2364              'S_QUICK_REPLY'            => true,
2365              'U_QR_ACTION'            => append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&amp;t=$topic_id"),
2366              'QR_HIDDEN_FIELDS'        => build_hidden_fields($qr_hidden_fields),
2367              'SUBJECT'                => 'Re: ' . censor_text($topic_data['topic_title']),
2368          ];
2369   
2370          /**
2371          * Event after the quick-reply has been setup
2372          *
2373          * @event core.viewtopic_modify_quick_reply_template_vars
2374          * @var    array    tpl_ary            Array with template data
2375          * @var    array    topic_data        Array with topic data
2376          * @since 3.2.9-RC1
2377          */
2378          $vars = ['tpl_ary', 'topic_data'];
2379          extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_quick_reply_template_vars', compact($vars)));
2380   
2381          $template->assign_vars($tpl_ary);
2382      }
2383  }
2384  // now I have the urge to wash my hands :(
2385   
2386   
2387  // We overwrite $_REQUEST['f'] if there is no forum specified
2388  // to be able to display the correct online list.
2389  // One downside is that the user currently viewing this topic/post is not taken into account.
2390  if (!$request->variable('f', 0))
2391  {
2392      $request->overwrite('f', $forum_id);
2393  }
2394   
2395  // We need to do the same with the topic_id. See #53025.
2396  if (!$request->variable('t', 0) && !empty($topic_id))
2397  {
2398      $request->overwrite('t', $topic_id);
2399  }
2400   
2401  $page_title = $topic_data['topic_title'] . ($start ? ' - ' . sprintf($user->lang['PAGE_TITLE_NUMBER'], $pagination->get_on_page($config['posts_per_page'], $start)) : '');
2402   
2403  /**
2404  * You can use this event to modify the page title of the viewtopic page
2405  *
2406  * @event core.viewtopic_modify_page_title
2407  * @var    string    page_title        Title of the viewtopic page
2408  * @var    array    topic_data        Array with topic data
2409  * @var    int        forum_id        Forum ID of the topic
2410  * @var    int        start            Start offset used to calculate the page
2411  * @var    array    post_list        Array with post_ids we are going to display
2412  * @since 3.1.0-a1
2413  * @changed 3.1.0-RC4 Added post_list var
2414  */
2415  $vars = array('page_title', 'topic_data', 'forum_id', 'start', 'post_list');
2416  extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_page_title', compact($vars)));
2417   
2418  // Output the page
2419  page_header($page_title, true, $forum_id);
2420   
2421  $template->set_filenames(array(
2422      'body' => ($view == 'print') ? 'viewtopic_print.html' : 'viewtopic_body.html')
2423  );
2424  make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_id);
2425   
2426  page_footer();
2427