Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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