Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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