[ Index ]

PHP Cross Reference of phpBB-3.3.0-deutsch

title

Body

[close]

/ -> viewtopic.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  /**
  15  * @ignore
  16  */
  17  define('IN_PHPBB', true);
  18  $phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
  19  $phpEx = substr(strrchr(__FILE__, '.'), 1);
  20  include($phpbb_root_path . 'common.' . $phpEx);
  21  include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
  22  include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
  23  include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
  24  
  25  // Start session management
  26  $user->session_begin();
  27  $auth->acl($user->data);
  28  
  29  // Initial var setup
  30  $forum_id    = $request->variable('f', 0);
  31  $topic_id    = $request->variable('t', 0);
  32  $post_id    = $request->variable('p', 0);
  33  $voted_id    = $request->variable('vote_id', array('' => 0));
  34  
  35  $voted_id = (count($voted_id) > 1) ? array_unique($voted_id) : $voted_id;
  36  
  37  
  38  $start        = $request->variable('start', 0);
  39  $view        = $request->variable('view', '');
  40  
  41  $default_sort_days    = (!empty($user->data['user_post_show_days'])) ? $user->data['user_post_show_days'] : 0;
  42  $default_sort_key    = (!empty($user->data['user_post_sortby_type'])) ? $user->data['user_post_sortby_type'] : 't';
  43  $default_sort_dir    = (!empty($user->data['user_post_sortby_dir'])) ? $user->data['user_post_sortby_dir'] : 'a';
  44  
  45  $sort_days    = $request->variable('st', $default_sort_days);
  46  $sort_key    = $request->variable('sk', $default_sort_key);
  47  $sort_dir    = $request->variable('sd', $default_sort_dir);
  48  
  49  $update        = $request->variable('update', false);
  50  
  51  /* @var $pagination \phpbb\pagination */
  52  $pagination = $phpbb_container->get('pagination');
  53  
  54  $s_can_vote = false;
  55  /**
  56  * @todo normalize?
  57  */
  58  $hilit_words    = $request->variable('hilit', '', true);
  59  
  60  // Do we have a topic or post id?
  61  if (!$topic_id && !$post_id)
  62  {
  63      trigger_error('NO_TOPIC');
  64  }
  65  
  66  /* @var $phpbb_content_visibility \phpbb\content_visibility */
  67  $phpbb_content_visibility = $phpbb_container->get('content.visibility');
  68  
  69  // Find topic id if user requested a newer or older topic
  70  if ($view && !$post_id)
  71  {
  72      if (!$forum_id)
  73      {
  74          $sql = 'SELECT forum_id
  75              FROM ' . TOPICS_TABLE . "
  76              WHERE topic_id = $topic_id";
  77          $result = $db->sql_query($sql);
  78          $forum_id = (int) $db->sql_fetchfield('forum_id');
  79          $db->sql_freeresult($result);
  80  
  81          if (!$forum_id)
  82          {
  83              trigger_error('NO_TOPIC');
  84          }
  85      }
  86  
  87      if ($view == 'unread')
  88      {
  89          // Get topic tracking info
  90          $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id);
  91          $topic_last_read = (isset($topic_tracking_info[$topic_id])) ? $topic_tracking_info[$topic_id] : 0;
  92  
  93          $sql = 'SELECT post_id, topic_id, forum_id
  94              FROM ' . POSTS_TABLE . "
  95              WHERE topic_id = $topic_id
  96                  AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . "
  97                  AND post_time > $topic_last_read
  98                  AND forum_id = $forum_id
  99              ORDER BY post_time ASC, post_id ASC";
 100          $result = $db->sql_query_limit($sql, 1);
 101          $row = $db->sql_fetchrow($result);
 102          $db->sql_freeresult($result);
 103  
 104          if (!$row)
 105          {
 106              $sql = 'SELECT topic_last_post_id as post_id, topic_id, forum_id
 107                  FROM ' . TOPICS_TABLE . '
 108                  WHERE topic_id = ' . $topic_id;
 109              $result = $db->sql_query($sql);
 110              $row = $db->sql_fetchrow($result);
 111              $db->sql_freeresult($result);
 112          }
 113  
 114          if (!$row)
 115          {
 116              // Setup user environment so we can process lang string
 117              $user->setup('viewtopic');
 118  
 119              trigger_error('NO_TOPIC');
 120          }
 121  
 122          $post_id = $row['post_id'];
 123          $topic_id = $row['topic_id'];
 124      }
 125      else if ($view == 'next' || $view == 'previous')
 126      {
 127          $sql_condition = ($view == 'next') ? '>' : '<';
 128          $sql_ordering = ($view == 'next') ? 'ASC' : 'DESC';
 129  
 130          $sql = 'SELECT forum_id, topic_last_post_time
 131              FROM ' . TOPICS_TABLE . '
 132              WHERE topic_id = ' . $topic_id;
 133          $result = $db->sql_query($sql);
 134          $row = $db->sql_fetchrow($result);
 135          $db->sql_freeresult($result);
 136  
 137          if (!$row)
 138          {
 139              $user->setup('viewtopic');
 140              // OK, the topic doesn't exist. This error message is not helpful, but technically correct.
 141              trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS');
 142          }
 143          else
 144          {
 145              $sql = 'SELECT topic_id, forum_id
 146                  FROM ' . TOPICS_TABLE . '
 147                  WHERE forum_id = ' . $row['forum_id'] . "
 148                      AND topic_moved_id = 0
 149                      AND topic_last_post_time $sql_condition {$row['topic_last_post_time']}
 150                      AND " . $phpbb_content_visibility->get_visibility_sql('topic', $row['forum_id']) . "
 151                  ORDER BY topic_last_post_time $sql_ordering, topic_last_post_id $sql_ordering";
 152              $result = $db->sql_query_limit($sql, 1);
 153              $row = $db->sql_fetchrow($result);
 154              $db->sql_freeresult($result);
 155  
 156              if (!$row)
 157              {
 158                  $sql = 'SELECT forum_style
 159                      FROM ' . FORUMS_TABLE . "
 160                      WHERE forum_id = $forum_id";
 161                  $result = $db->sql_query($sql);
 162                  $forum_style = (int) $db->sql_fetchfield('forum_style');
 163                  $db->sql_freeresult($result);
 164  
 165                  $user->setup('viewtopic', $forum_style);
 166                  trigger_error(($view == 'next') ? 'NO_NEWER_TOPICS' : 'NO_OLDER_TOPICS');
 167              }
 168              else
 169              {
 170                  $topic_id = $row['topic_id'];
 171                  $forum_id = $row['forum_id'];
 172              }
 173          }
 174      }
 175  
 176      if (isset($row) && $row['forum_id'])
 177      {
 178          $forum_id = $row['forum_id'];
 179      }
 180  }
 181  
 182  // This rather complex gaggle of code handles querying for topics but
 183  // also allows for direct linking to a post (and the calculation of which
 184  // page the post is on and the correct display of viewtopic)
 185  $sql_array = array(
 186      'SELECT'    => 't.*, f.*',
 187  
 188      'FROM'        => array(FORUMS_TABLE => 'f'),
 189  );
 190  
 191  // The FROM-Order is quite important here, else t.* columns can not be correctly bound.
 192  if ($post_id)
 193  {
 194      $sql_array['SELECT'] .= ', p.post_visibility, p.post_time, p.post_id';
 195      $sql_array['FROM'][POSTS_TABLE] = 'p';
 196  }
 197  
 198  // Topics table need to be the last in the chain
 199  $sql_array['FROM'][TOPICS_TABLE] = 't';
 200  
 201  if ($user->data['is_registered'])
 202  {
 203      $sql_array['SELECT'] .= ', tw.notify_status';
 204      $sql_array['LEFT_JOIN'] = array();
 205  
 206      $sql_array['LEFT_JOIN'][] = array(
 207          'FROM'    => array(TOPICS_WATCH_TABLE => 'tw'),
 208          'ON'    => 'tw.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tw.topic_id'
 209      );
 210  
 211      if ($config['allow_bookmarks'])
 212      {
 213          $sql_array['SELECT'] .= ', bm.topic_id as bookmarked';
 214          $sql_array['LEFT_JOIN'][] = array(
 215              'FROM'    => array(BOOKMARKS_TABLE => 'bm'),
 216              'ON'    => 'bm.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = bm.topic_id'
 217          );
 218      }
 219  
 220      if ($config['load_db_lastread'])
 221      {
 222          $sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time';
 223  
 224          $sql_array['LEFT_JOIN'][] = array(
 225              'FROM'    => array(TOPICS_TRACK_TABLE => 'tt'),
 226              'ON'    => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id'
 227          );
 228  
 229          $sql_array['LEFT_JOIN'][] = array(
 230              'FROM'    => array(FORUMS_TRACK_TABLE => 'ft'),
 231              'ON'    => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id'
 232          );
 233      }
 234  }
 235  
 236  if (!$post_id)
 237  {
 238      $sql_array['WHERE'] = "t.topic_id = $topic_id";
 239  }
 240  else
 241  {
 242      $sql_array['WHERE'] = "p.post_id = $post_id AND t.topic_id = p.topic_id";
 243  }
 244  
 245  $sql_array['WHERE'] .= ' AND f.forum_id = t.forum_id';
 246  
 247  $sql = $db->sql_build_query('SELECT', $sql_array);
 248  $result = $db->sql_query($sql);
 249  $topic_data = $db->sql_fetchrow($result);
 250  $db->sql_freeresult($result);
 251  
 252  // link to unapproved post or incorrect link
 253  if (!$topic_data)
 254  {
 255      // If post_id was submitted, we try at least to display the topic as a last resort...
 256      if ($post_id && $topic_id)
 257      {
 258          redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&amp;f=$forum_id" : '')));
 259      }
 260  
 261      trigger_error('NO_TOPIC');
 262  }
 263  
 264  $forum_id = (int) $topic_data['forum_id'];
 265  
 266  /**
 267   * Modify the forum ID to handle the correct display of viewtopic if needed
 268   *
 269   * @event core.viewtopic_modify_forum_id
 270   * @var string    forum_id        forum ID
 271   * @var array    topic_data        array of topic's data
 272   * @since 3.2.5-RC1
 273   */
 274  $vars = array(
 275      'forum_id',
 276      'topic_data',
 277  );
 278  extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_forum_id', compact($vars)));
 279  
 280  // If the request is missing the f parameter, the forum id in the user session data is 0 at the moment.
 281  // Let's fix that now so that the user can't hide from the forum's Who Is Online list.
 282  $user->page['forum'] = $forum_id;
 283  
 284  // Now we know the forum_id and can check the permissions
 285  if (!$phpbb_content_visibility->is_visible('topic', $forum_id, $topic_data))
 286  {
 287      trigger_error('NO_TOPIC');
 288  }
 289  
 290  // This is for determining where we are (page)
 291  if ($post_id)
 292  {
 293      // are we where we are supposed to be?
 294      if (($topic_data['post_visibility'] == ITEM_UNAPPROVED || $topic_data['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $topic_data['forum_id']))
 295      {
 296          // If post_id was submitted, we try at least to display the topic as a last resort...
 297          if ($topic_id)
 298          {
 299              redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&amp;f=$forum_id" : '')));
 300          }
 301  
 302          trigger_error('NO_TOPIC');
 303      }
 304      if ($post_id == $topic_data['topic_first_post_id'] || $post_id == $topic_data['topic_last_post_id'])
 305      {
 306          $check_sort = ($post_id == $topic_data['topic_first_post_id']) ? 'd' : 'a';
 307  
 308          if ($sort_dir == $check_sort)
 309          {
 310              $topic_data['prev_posts'] = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1;
 311          }
 312          else
 313          {
 314              $topic_data['prev_posts'] = 0;
 315          }
 316      }
 317      else
 318      {
 319          $sql = 'SELECT COUNT(p.post_id) AS prev_posts
 320              FROM ' . POSTS_TABLE . " p
 321              WHERE p.topic_id = {$topic_data['topic_id']}
 322                  AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.');
 323  
 324          if ($sort_dir == 'd')
 325          {
 326              $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']}))";
 327          }
 328          else
 329          {
 330              $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']}))";
 331          }
 332  
 333          $result = $db->sql_query($sql);
 334          $row = $db->sql_fetchrow($result);
 335          $db->sql_freeresult($result);
 336  
 337          $topic_data['prev_posts'] = $row['prev_posts'] - 1;
 338      }
 339  }
 340  
 341  $topic_id = (int) $topic_data['topic_id'];
 342  $topic_replies = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1;
 343  
 344  // Check sticky/announcement/global  time limit
 345  if (($topic_data['topic_type'] != POST_NORMAL) && $topic_data['topic_time_limit'] && ($topic_data['topic_time'] + $topic_data['topic_time_limit']) < time())
 346  {
 347      $sql = 'UPDATE ' . TOPICS_TABLE . '
 348          SET topic_type = ' . POST_NORMAL . ', topic_time_limit = 0
 349          WHERE topic_id = ' . $topic_id;
 350      $db->sql_query($sql);
 351  
 352      $topic_data['topic_type'] = POST_NORMAL;
 353      $topic_data['topic_time_limit'] = 0;
 354  }
 355  
 356  // Setup look and feel
 357  $user->setup('viewtopic', $topic_data['forum_style']);
 358  
 359  if ($view == 'print' && !$auth->acl_get('f_print', $forum_id))
 360  {
 361      send_status_line(403, 'Forbidden');
 362      trigger_error('NO_AUTH_PRINT_TOPIC');
 363  }
 364  
 365  $overrides_f_read_check = false;
 366  $overrides_forum_password_check = false;
 367  $topic_tracking_info = isset($topic_tracking_info) ? $topic_tracking_info : null;
 368  
 369  /**
 370  * Event to apply extra permissions and to override original phpBB's f_read permission and forum password check
 371  * on viewtopic access
 372  *
 373  * @event core.viewtopic_before_f_read_check
 374  * @var    int        forum_id                        The forum id from where the topic belongs
 375  * @var    int        topic_id                        The id of the topic the user tries to access
 376  * @var    int        post_id                            The id of the post the user tries to start viewing at.
 377  *                                                It may be 0 for none given.
 378  * @var    array    topic_data                        All the information from the topic and forum tables for this topic
 379  *                                                 It includes posts information if post_id is not 0
 380  * @var    bool    overrides_f_read_check            Set true to remove f_read check afterwards
 381  * @var    bool    overrides_forum_password_check    Set true to remove forum_password check afterwards
 382  * @var    array    topic_tracking_info                Information upon calling get_topic_tracking()
 383  *                                                Set it to NULL to allow auto-filling later.
 384  *                                                Set it to an array to override original data.
 385  * @since 3.1.3-RC1
 386  */
 387  $vars = array(
 388      'forum_id',
 389      'topic_id',
 390      'post_id',
 391      'topic_data',
 392      'overrides_f_read_check',
 393      'overrides_forum_password_check',
 394      'topic_tracking_info',
 395  );
 396  extract($phpbb_dispatcher->trigger_event('core.viewtopic_before_f_read_check', compact($vars)));
 397  
 398  // Start auth check
 399  if (!$overrides_f_read_check && !$auth->acl_get('f_read', $forum_id))
 400  {
 401      if ($user->data['user_id'] != ANONYMOUS)
 402      {
 403          send_status_line(403, 'Forbidden');
 404          trigger_error('SORRY_AUTH_READ');
 405      }
 406  
 407      login_box('', $user->lang['LOGIN_VIEWFORUM']);
 408  }
 409  
 410  // Forum is passworded ... check whether access has been granted to this
 411  // user this session, if not show login box
 412  if (!$overrides_forum_password_check && $topic_data['forum_password'])
 413  {
 414      login_forum_box($topic_data);
 415  }
 416  
 417  // Redirect to login upon emailed notification links if user is not logged in.
 418  if (isset($_GET['e']) && $user->data['user_id'] == ANONYMOUS)
 419  {
 420      login_box(build_url('e') . '#unread', $user->lang['LOGIN_NOTIFY_TOPIC']);
 421  }
 422  
 423  // What is start equal to?
 424  if ($post_id)
 425  {
 426      $start = floor(($topic_data['prev_posts']) / $config['posts_per_page']) * $config['posts_per_page'];
 427  }
 428  
 429  // Get topic tracking info
 430  if (!isset($topic_tracking_info))
 431  {
 432      $topic_tracking_info = array();
 433  
 434      // Get topic tracking info
 435      if ($config['load_db_lastread'] && $user->data['is_registered'])
 436      {
 437          $tmp_topic_data = array($topic_id => $topic_data);
 438          $topic_tracking_info = get_topic_tracking($forum_id, $topic_id, $tmp_topic_data, array($forum_id => $topic_data['forum_mark_time']));
 439          unset($tmp_topic_data);
 440      }
 441      else if ($config['load_anon_lastread'] || $user->data['is_registered'])
 442      {
 443          $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_id);
 444      }
 445  }
 446  
 447  // Post ordering options
 448  $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']);
 449  
 450  $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']);
 451  $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'));
 452  $join_user_sql = array('a' => true, 't' => false, 's' => false);
 453  
 454  $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
 455  
 456  /**
 457  * Event to add new sorting options
 458  *
 459  * @event core.viewtopic_gen_sort_selects_before
 460  * @var    array    limit_days        Limit results by time
 461  * @var    array    sort_by_text    Language strings for sorting options
 462  * @var    array    sort_by_sql        SQL conditions for sorting options
 463  * @var    array    join_user_sql    SQL joins required for sorting options
 464  * @var    int        sort_days        User selected sort days
 465  * @var    string    sort_key        User selected sort key
 466  * @var    string    sort_dir        User selected sort direction
 467  * @var    string    s_limit_days    Initial value of limit days selectbox
 468  * @var    string    s_sort_key        Initial value of sort key selectbox
 469  * @var    string    s_sort_dir        Initial value of sort direction selectbox
 470  * @var    string    u_sort_param    Initial value of sorting form action
 471  * @since 3.2.8-RC1
 472  */
 473  $vars = array(
 474      'limit_days',
 475      'sort_by_text',
 476      'sort_by_sql',
 477      'join_user_sql',
 478      'sort_days',
 479      'sort_key',
 480      'sort_dir',
 481      's_limit_days',
 482      's_sort_key',
 483      's_sort_dir',
 484      'u_sort_param',
 485  );
 486  extract($phpbb_dispatcher->trigger_event('core.viewtopic_gen_sort_selects_before', compact($vars)));
 487  
 488  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);
 489  
 490  // Obtain correct post count and ordering SQL if user has
 491  // requested anything different
 492  if ($sort_days)
 493  {
 494      $min_post_time = time() - ($sort_days * 86400);
 495  
 496      $sql = 'SELECT COUNT(post_id) AS num_posts
 497          FROM ' . POSTS_TABLE . "
 498          WHERE topic_id = $topic_id
 499              AND post_time >= $min_post_time
 500                  AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id);
 501      $result = $db->sql_query($sql);
 502      $total_posts = (int) $db->sql_fetchfield('num_posts');
 503      $db->sql_freeresult($result);
 504  
 505      $limit_posts_time = "AND p.post_time >= $min_post_time ";
 506  
 507      if (isset($_POST['sort']))
 508      {
 509          $start = 0;
 510      }
 511  }
 512  else
 513  {
 514      $total_posts = $topic_replies + 1;
 515      $limit_posts_time = '';
 516  }
 517  
 518  // Was a highlight request part of the URI?
 519  $highlight_match = $highlight = '';
 520  if ($hilit_words)
 521  {
 522      $highlight_match = phpbb_clean_search_string($hilit_words);
 523      $highlight = urlencode($highlight_match);
 524      $highlight_match = str_replace('\*', '\w+?', preg_quote($highlight_match, '#'));
 525      $highlight_match = preg_replace('#(?<=^|\s)\\\\w\*\?(?=\s|$)#', '\w+?', $highlight_match);
 526      $highlight_match = str_replace(' ', '|', $highlight_match);
 527  }
 528  
 529  // Make sure $start is set to the last page if it exceeds the amount
 530  $start = $pagination->validate_start($start, $config['posts_per_page'], $total_posts);
 531  
 532  // General Viewtopic URL for return links
 533  $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" : ''));
 534  
 535  // Are we watching this topic?
 536  $s_watching_topic = array(
 537      'link'            => '',
 538      'link_toggle'    => '',
 539      'title'            => '',
 540      'title_toggle'    => '',
 541      'is_watching'    => false,
 542  );
 543  
 544  if ($config['allow_topic_notify'])
 545  {
 546      $notify_status = (isset($topic_data['notify_status'])) ? $topic_data['notify_status'] : null;
 547      watch_topic_forum('topic', $s_watching_topic, $user->data['user_id'], $forum_id, $topic_id, $notify_status, $start, $topic_data['topic_title']);
 548  
 549      // Reset forum notification if forum notify is set
 550      if ($config['allow_forum_notify'] && $auth->acl_get('f_subscribe', $forum_id))
 551      {
 552          $s_watching_forum = $s_watching_topic;
 553          watch_topic_forum('forum', $s_watching_forum, $user->data['user_id'], $forum_id, 0);
 554      }
 555  }
 556  
 557  /**
 558  * Event to modify highlight.
 559  *
 560  * @event core.viewtopic_highlight_modify
 561  * @var    string    highlight            String to be highlighted
 562  * @var    string    highlight_match        Highlight string to be used in preg_replace
 563  * @var    array    topic_data            Topic data
 564  * @var    int        start                Pagination start
 565  * @var    int        total_posts            Number of posts
 566  * @var    string    viewtopic_url        Current viewtopic URL
 567  * @since 3.1.11-RC1
 568  */
 569  $vars = array(
 570      'highlight',
 571      'highlight_match',
 572      'topic_data',
 573      'start',
 574      'total_posts',
 575      'viewtopic_url',
 576  );
 577  extract($phpbb_dispatcher->trigger_event('core.viewtopic_highlight_modify', compact($vars)));
 578  
 579  // Bookmarks
 580  if ($config['allow_bookmarks'] && $user->data['is_registered'] && $request->variable('bookmark', 0))
 581  {
 582      if (check_link_hash($request->variable('hash', ''), "topic_$topic_id"))
 583      {
 584          if (!$topic_data['bookmarked'])
 585          {
 586              $sql = 'INSERT INTO ' . BOOKMARKS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
 587                  'user_id'    => $user->data['user_id'],
 588                  'topic_id'    => $topic_id,
 589              ));
 590              $db->sql_query($sql);
 591          }
 592          else
 593          {
 594              $sql = 'DELETE FROM ' . BOOKMARKS_TABLE . "
 595                  WHERE user_id = {$user->data['user_id']}
 596                      AND topic_id = $topic_id";
 597              $db->sql_query($sql);
 598          }
 599          $message = (($topic_data['bookmarked']) ? $user->lang['BOOKMARK_REMOVED'] : $user->lang['BOOKMARK_ADDED']);
 600  
 601          if (!$request->is_ajax())
 602          {
 603              $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $viewtopic_url . '">', '</a>');
 604          }
 605      }
 606      else
 607      {
 608          $message = $user->lang['BOOKMARK_ERR'];
 609  
 610          if (!$request->is_ajax())
 611          {
 612              $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $viewtopic_url . '">', '</a>');
 613          }
 614      }
 615      meta_refresh(3, $viewtopic_url);
 616  
 617      trigger_error($message);
 618  }
 619  
 620  // Grab ranks
 621  $ranks = $cache->obtain_ranks();
 622  
 623  // Grab icons
 624  $icons = $cache->obtain_icons();
 625  
 626  // Grab extensions
 627  $extensions = array();
 628  if ($topic_data['topic_attachment'])
 629  {
 630      $extensions = $cache->obtain_attach_extensions($forum_id);
 631  }
 632  
 633  // Forum rules listing
 634  $s_forum_rules = '';
 635  gen_forum_auth_level('topic', $forum_id, $topic_data['forum_status']);
 636  
 637  // Quick mod tools
 638  $allow_change_type = ($auth->acl_get('m_', $forum_id) || ($user->data['is_registered'] && $user->data['user_id'] == $topic_data['topic_poster'])) ? true : false;
 639  
 640  $s_quickmod_action = append_sid(
 641      "{$phpbb_root_path}mcp.$phpEx",
 642      array(
 643          'f'    => $forum_id,
 644          't'    => $topic_id,
 645          'start'        => $start,
 646          'quickmod'    => 1,
 647          'redirect'    => urlencode(str_replace('&amp;', '&', $viewtopic_url)),
 648      ),
 649      true,
 650      $user->session_id
 651  );
 652  
 653  $quickmod_array = array(
 654  //    'key'            => array('LANG_KEY', $userHasPermissions),
 655  
 656      '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']))),
 657      'unlock'                => array('UNLOCK_TOPIC', ($topic_data['topic_status'] != ITEM_UNLOCKED) && ($auth->acl_get('m_lock', $forum_id))),
 658      '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)))),
 659      'restore_topic'        => array('RESTORE_TOPIC', (($topic_data['topic_visibility'] == ITEM_DELETED) && $auth->acl_get('m_approve', $forum_id))),
 660      'move'                    => array('MOVE_TOPIC', $auth->acl_get('m_move', $forum_id) && $topic_data['topic_status'] != ITEM_MOVED),
 661      'split'                    => array('SPLIT_TOPIC', $auth->acl_get('m_split', $forum_id)),
 662      'merge'                    => array('MERGE_POSTS', $auth->acl_get('m_merge', $forum_id)),
 663      'merge_topic'        => array('MERGE_TOPIC', $auth->acl_get('m_merge', $forum_id)),
 664      'fork'                    => array('FORK_TOPIC', $auth->acl_get('m_move', $forum_id)),
 665      'make_normal'        => array('MAKE_NORMAL', ($allow_change_type && $auth->acl_gets('f_sticky', 'f_announce', 'f_announce_global', $forum_id) && $topic_data['topic_type'] != POST_NORMAL)),
 666      'make_sticky'        => array('MAKE_STICKY', ($allow_change_type && $auth->acl_get('f_sticky', $forum_id) && $topic_data['topic_type'] != POST_STICKY)),
 667      'make_announce'    => array('MAKE_ANNOUNCE', ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_ANNOUNCE)),
 668      'make_global'        => array('MAKE_GLOBAL', ($allow_change_type && $auth->acl_get('f_announce_global', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL)),
 669      'topic_logs'            => array('VIEW_TOPIC_LOGS', $auth->acl_get('m_', $forum_id)),
 670  );
 671  
 672  /**
 673  * Event to modify data in the quickmod_array before it gets sent to the
 674  * phpbb_add_quickmod_option function.
 675  *
 676  * @event core.viewtopic_add_quickmod_option_before
 677  * @var    int                forum_id                Forum ID
 678  * @var    int                post_id                    Post ID
 679  * @var    array            quickmod_array            Array with quick moderation options data
 680  * @var    array            topic_data                Array with topic data
 681  * @var    int                topic_id                Topic ID
 682  * @var    array            topic_tracking_info        Array with topic tracking data
 683  * @var    string            viewtopic_url            URL to the topic page
 684  * @var    bool            allow_change_type        Topic change permissions check
 685  * @since 3.1.9-RC1
 686  */
 687  $vars = array(
 688      'forum_id',
 689      'post_id',
 690      'quickmod_array',
 691      'topic_data',
 692      'topic_id',
 693      'topic_tracking_info',
 694      'viewtopic_url',
 695      'allow_change_type',
 696  );
 697  extract($phpbb_dispatcher->trigger_event('core.viewtopic_add_quickmod_option_before', compact($vars)));
 698  
 699  foreach ($quickmod_array as $option => $qm_ary)
 700  {
 701      if (!empty($qm_ary[1]))
 702      {
 703          phpbb_add_quickmod_option($s_quickmod_action, $option, $qm_ary[0]);
 704      }
 705  }
 706  
 707  // Navigation links
 708  generate_forum_nav($topic_data);
 709  
 710  // Forum Rules
 711  generate_forum_rules($topic_data);
 712  
 713  // Moderators
 714  $forum_moderators = array();
 715  if ($config['load_moderators'])
 716  {
 717      get_moderators($forum_moderators, $forum_id);
 718  }
 719  
 720  // This is only used for print view so ...
 721  $server_path = (!$view) ? $phpbb_root_path : generate_board_url() . '/';
 722  
 723  // Replace naughty words in title
 724  $topic_data['topic_title'] = censor_text($topic_data['topic_title']);
 725  
 726  $s_search_hidden_fields = array(
 727      't' => $topic_id,
 728      'sf' => 'msgonly',
 729  );
 730  if ($_SID)
 731  {
 732      $s_search_hidden_fields['sid'] = $_SID;
 733  }
 734  
 735  if (!empty($_EXTRA_URL))
 736  {
 737      foreach ($_EXTRA_URL as $url_param)
 738      {
 739          $url_param = explode('=', $url_param, 2);
 740          $s_search_hidden_fields[$url_param[0]] = $url_param[1];
 741      }
 742  }
 743  
 744  // If we've got a hightlight set pass it on to pagination.
 745  $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" : ''));
 746  
 747  /**
 748  * Event to modify data before template variables are being assigned
 749  *
 750  * @event core.viewtopic_assign_template_vars_before
 751  * @var    string    base_url            URL to be passed to generate pagination
 752  * @var    int        forum_id            Forum ID
 753  * @var    int        post_id                Post ID
 754  * @var    array    quickmod_array        Array with quick moderation options data
 755  * @var    int        start                Pagination information
 756  * @var    array    topic_data            Array with topic data
 757  * @var    int        topic_id            Topic ID
 758  * @var    array    topic_tracking_info    Array with topic tracking data
 759  * @var    int        total_posts            Topic total posts count
 760  * @var    string    viewtopic_url        URL to the topic page
 761  * @since 3.1.0-RC4
 762  * @changed 3.1.2-RC1 Added viewtopic_url
 763  */
 764  $vars = array(
 765      'base_url',
 766      'forum_id',
 767      'post_id',
 768      'quickmod_array',
 769      'start',
 770      'topic_data',
 771      'topic_id',
 772      'topic_tracking_info',
 773      'total_posts',
 774      'viewtopic_url',
 775  );
 776  extract($phpbb_dispatcher->trigger_event('core.viewtopic_assign_template_vars_before', compact($vars)));
 777  
 778  $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_posts, $config['posts_per_page'], $start);
 779  
 780  // Send vars to template
 781  $template->assign_vars(array(
 782      'FORUM_ID'         => $forum_id,
 783      'FORUM_NAME'     => $topic_data['forum_name'],
 784      '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']),
 785      'TOPIC_ID'         => $topic_id,
 786      'TOPIC_TITLE'     => $topic_data['topic_title'],
 787      'TOPIC_POSTER'    => $topic_data['topic_poster'],
 788  
 789      'TOPIC_AUTHOR_FULL'        => get_username_string('full', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
 790      'TOPIC_AUTHOR_COLOUR'    => get_username_string('colour', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
 791      'TOPIC_AUTHOR'            => get_username_string('username', $topic_data['topic_poster'], $topic_data['topic_first_poster_name'], $topic_data['topic_first_poster_colour']),
 792  
 793      'TOTAL_POSTS'    => $user->lang('VIEW_TOPIC_POSTS', (int) $total_posts),
 794      '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) : '',
 795      'MODERATORS'    => (isset($forum_moderators[$forum_id]) && count($forum_moderators[$forum_id])) ? implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]) : '',
 796  
 797      'POST_IMG'             => ($topic_data['forum_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'FORUM_LOCKED') : $user->img('button_topic_new', 'POST_NEW_TOPIC'),
 798      'QUOTE_IMG'         => $user->img('icon_post_quote', 'REPLY_WITH_QUOTE'),
 799      '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'),
 800      'EDIT_IMG'             => $user->img('icon_post_edit', 'EDIT_POST'),
 801      'DELETE_IMG'         => $user->img('icon_post_delete', 'DELETE_POST'),
 802      'DELETED_IMG'        => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'),
 803      'INFO_IMG'             => $user->img('icon_post_info', 'VIEW_INFO'),
 804      'PROFILE_IMG'        => $user->img('icon_user_profile', 'READ_PROFILE'),
 805      'SEARCH_IMG'         => $user->img('icon_user_search', 'SEARCH_USER_POSTS'),
 806      'PM_IMG'             => $user->img('icon_contact_pm', 'SEND_PRIVATE_MESSAGE'),
 807      'EMAIL_IMG'         => $user->img('icon_contact_email', 'SEND_EMAIL'),
 808      'JABBER_IMG'        => $user->img('icon_contact_jabber', 'JABBER') ,
 809      'REPORT_IMG'        => $user->img('icon_post_report', 'REPORT_POST'),
 810      'REPORTED_IMG'        => $user->img('icon_topic_reported', 'POST_REPORTED'),
 811      'UNAPPROVED_IMG'    => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'),
 812      'WARN_IMG'            => $user->img('icon_user_warn', 'WARN_USER'),
 813  
 814      'S_IS_LOCKED'            => ($topic_data['topic_status'] == ITEM_UNLOCKED && $topic_data['forum_status'] == ITEM_UNLOCKED) ? false : true,
 815      'S_SELECT_SORT_DIR'     => $s_sort_dir,
 816      'S_SELECT_SORT_KEY'     => $s_sort_key,
 817      'S_SELECT_SORT_DAYS'     => $s_limit_days,
 818      'S_SINGLE_MODERATOR'    => (!empty($forum_moderators[$forum_id]) && count($forum_moderators[$forum_id]) > 1) ? false : true,
 819      'S_TOPIC_ACTION'         => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start")),
 820      'S_MOD_ACTION'             => $s_quickmod_action,
 821  
 822      'L_RETURN_TO_FORUM'        => $user->lang('RETURN_TO', $topic_data['forum_name']),
 823      'S_VIEWTOPIC'            => true,
 824      'S_UNREAD_VIEW'            => $view == 'unread',
 825      'S_DISPLAY_SEARCHBOX'    => ($auth->acl_get('u_search') && $auth->acl_get('f_search', $forum_id) && $config['load_search']) ? true : false,
 826      'S_SEARCHBOX_ACTION'    => append_sid("{$phpbb_root_path}search.$phpEx"),
 827      'S_SEARCH_LOCAL_HIDDEN_FIELDS'    => build_hidden_fields($s_search_hidden_fields),
 828  
 829      'S_DISPLAY_POST_INFO'    => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false,
 830      'S_DISPLAY_REPLY_INFO'    => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false,
 831      'S_ENABLE_FEEDS_TOPIC'    => ($config['feed_topic'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $topic_data['forum_options'])) ? true : false,
 832  
 833      'U_TOPIC'                => "{$server_path}viewtopic.$phpEx?f=$forum_id&amp;t=$topic_id",
 834      'U_FORUM'                => $server_path,
 835      'U_VIEW_TOPIC'             => 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" : '')),
 836      'U_CANONICAL'            => generate_board_url() . '/' . append_sid("viewtopic.$phpEx", "t=$topic_id" . (($start) ? "&amp;start=$start" : ''), true, ''),
 837      'U_VIEW_FORUM'             => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id),
 838      'U_VIEW_OLDER_TOPIC'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;view=previous"),
 839      'U_VIEW_NEWER_TOPIC'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;view=next"),
 840      'U_PRINT_TOPIC'            => ($auth->acl_get('f_print', $forum_id)) ? $viewtopic_url . '&amp;view=print' : '',
 841      '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") : '',
 842  
 843      'U_WATCH_TOPIC'            => $s_watching_topic['link'],
 844      'U_WATCH_TOPIC_TOGGLE'    => $s_watching_topic['link_toggle'],
 845      'S_WATCH_TOPIC_TITLE'    => $s_watching_topic['title'],
 846      'S_WATCH_TOPIC_TOGGLE'    => $s_watching_topic['title_toggle'],
 847      'S_WATCHING_TOPIC'        => $s_watching_topic['is_watching'],
 848  
 849      'U_BOOKMARK_TOPIC'        => ($user->data['is_registered'] && $config['allow_bookmarks']) ? $viewtopic_url . '&amp;bookmark=1&amp;hash=' . generate_link_hash("topic_$topic_id") : '',
 850      'S_BOOKMARK_TOPIC'        => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'],
 851      'S_BOOKMARK_TOGGLE'        => (!$user->data['is_registered'] || !$config['allow_bookmarks'] || !$topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'],
 852      'S_BOOKMARKED_TOPIC'    => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? true : false,
 853  
 854      '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") : '',
 855      '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") : '',
 856      '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")) : '')
 857  );
 858  
 859  // Does this topic contain a poll?
 860  if (!empty($topic_data['poll_start']))
 861  {
 862      $sql = 'SELECT o.*, p.bbcode_bitfield, p.bbcode_uid
 863          FROM ' . POLL_OPTIONS_TABLE . ' o, ' . POSTS_TABLE . " p
 864          WHERE o.topic_id = $topic_id
 865              AND p.post_id = {$topic_data['topic_first_post_id']}
 866              AND p.topic_id = o.topic_id
 867          ORDER BY o.poll_option_id";
 868      $result = $db->sql_query($sql);
 869  
 870      $poll_info = $vote_counts = array();
 871      while ($row = $db->sql_fetchrow($result))
 872      {
 873          $poll_info[] = $row;
 874          $option_id = (int) $row['poll_option_id'];
 875          $vote_counts[$option_id] = (int) $row['poll_option_total'];
 876      }
 877      $db->sql_freeresult($result);
 878  
 879      $cur_voted_id = array();
 880      if ($user->data['is_registered'])
 881      {
 882          $sql = 'SELECT poll_option_id
 883              FROM ' . POLL_VOTES_TABLE . '
 884              WHERE topic_id = ' . $topic_id . '
 885                  AND vote_user_id = ' . $user->data['user_id'];
 886          $result = $db->sql_query($sql);
 887  
 888          while ($row = $db->sql_fetchrow($result))
 889          {
 890              $cur_voted_id[] = $row['poll_option_id'];
 891          }
 892          $db->sql_freeresult($result);
 893      }
 894      else
 895      {
 896          // Cookie based guest tracking ... I don't like this but hum ho
 897          // it's oft requested. This relies on "nice" users who don't feel
 898          // the need to delete cookies to mess with results.
 899          if ($request->is_set($config['cookie_name'] . '_poll_' . $topic_id, \phpbb\request\request_interface::COOKIE))
 900          {
 901              $cur_voted_id = explode(',', $request->variable($config['cookie_name'] . '_poll_' . $topic_id, '', true, \phpbb\request\request_interface::COOKIE));
 902              $cur_voted_id = array_map('intval', $cur_voted_id);
 903          }
 904      }
 905  
 906      // Can not vote at all if no vote permission
 907      $s_can_vote = ($auth->acl_get('f_vote', $forum_id) &&
 908          (($topic_data['poll_length'] != 0 && $topic_data['poll_start'] + $topic_data['poll_length'] > time()) || $topic_data['poll_length'] == 0) &&
 909          $topic_data['topic_status'] != ITEM_LOCKED &&
 910          $topic_data['forum_status'] != ITEM_LOCKED &&
 911          (!count($cur_voted_id) ||
 912          ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']))) ? true : false;
 913      $s_display_results = (!$s_can_vote || ($s_can_vote && count($cur_voted_id)) || $view == 'viewpoll') ? true : false;
 914  
 915      /**
 916      * Event to manipulate the poll data
 917      *
 918      * @event core.viewtopic_modify_poll_data
 919      * @var    array    cur_voted_id                Array with options' IDs current user has voted for
 920      * @var    int        forum_id                    The topic's forum id
 921      * @var    array    poll_info                    Array with the poll information
 922      * @var    bool    s_can_vote                    Flag indicating if a user can vote
 923      * @var    bool    s_display_results            Flag indicating if results or poll options should be displayed
 924      * @var    int        topic_id                    The id of the topic the user tries to access
 925      * @var    array    topic_data                    All the information from the topic and forum tables for this topic
 926      * @var    string    viewtopic_url                URL to the topic page
 927      * @var    array    vote_counts                    Array with the vote counts for every poll option
 928      * @var    array    voted_id                    Array with updated options' IDs current user is voting for
 929      * @since 3.1.5-RC1
 930      */
 931      $vars = array(
 932          'cur_voted_id',
 933          'forum_id',
 934          'poll_info',
 935          's_can_vote',
 936          's_display_results',
 937          'topic_id',
 938          'topic_data',
 939          'viewtopic_url',
 940          'vote_counts',
 941          'voted_id',
 942      );
 943      extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_data', compact($vars)));
 944  
 945      if ($update && $s_can_vote)
 946      {
 947  
 948          if (!count($voted_id) || count($voted_id) > $topic_data['poll_max_options'] || in_array(VOTE_CONVERTED, $cur_voted_id) || !check_form_key('posting'))
 949          {
 950              $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start"));
 951  
 952              meta_refresh(5, $redirect_url);
 953              if (!count($voted_id))
 954              {
 955                  $message = 'NO_VOTE_OPTION';
 956              }
 957              else if (count($voted_id) > $topic_data['poll_max_options'])
 958              {
 959                  $message = 'TOO_MANY_VOTE_OPTIONS';
 960              }
 961              else if (in_array(VOTE_CONVERTED, $cur_voted_id))
 962              {
 963                  $message = 'VOTE_CONVERTED';
 964              }
 965              else
 966              {
 967                  $message = 'FORM_INVALID';
 968              }
 969  
 970              $message = $user->lang[$message] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>');
 971              trigger_error($message);
 972          }
 973  
 974          foreach ($voted_id as $option)
 975          {
 976              if (in_array($option, $cur_voted_id))
 977              {
 978                  continue;
 979              }
 980  
 981              $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . '
 982                  SET poll_option_total = poll_option_total + 1
 983                  WHERE poll_option_id = ' . (int) $option . '
 984                      AND topic_id = ' . (int) $topic_id;
 985              $db->sql_query($sql);
 986  
 987              $vote_counts[$option]++;
 988  
 989              if ($user->data['is_registered'])
 990              {
 991                  $sql_ary = array(
 992                      'topic_id'            => (int) $topic_id,
 993                      'poll_option_id'    => (int) $option,
 994                      'vote_user_id'        => (int) $user->data['user_id'],
 995                      'vote_user_ip'        => (string) $user->ip,
 996                  );
 997  
 998                  $sql = 'INSERT INTO ' . POLL_VOTES_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
 999                  $db->sql_query($sql);
1000              }
1001          }
1002  
1003          foreach ($cur_voted_id as $option)
1004          {
1005              if (!in_array($option, $voted_id))
1006              {
1007                  $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . '
1008                      SET poll_option_total = poll_option_total - 1
1009                      WHERE poll_option_id = ' . (int) $option . '
1010                          AND topic_id = ' . (int) $topic_id;
1011                  $db->sql_query($sql);
1012  
1013                  $vote_counts[$option]--;
1014  
1015                  if ($user->data['is_registered'])
1016                  {
1017                      $sql = 'DELETE FROM ' . POLL_VOTES_TABLE . '
1018                          WHERE topic_id = ' . (int) $topic_id . '
1019                              AND poll_option_id = ' . (int) $option . '
1020                              AND vote_user_id = ' . (int) $user->data['user_id'];
1021                      $db->sql_query($sql);
1022                  }
1023              }
1024          }
1025  
1026          if ($user->data['user_id'] == ANONYMOUS && !$user->data['is_bot'])
1027          {
1028              $user->set_cookie('poll_' . $topic_id, implode(',', $voted_id), time() + 31536000);
1029          }
1030  
1031          $sql = 'UPDATE ' . TOPICS_TABLE . '
1032              SET poll_last_vote = ' . time() . "
1033              WHERE topic_id = $topic_id";
1034          //, topic_last_post_time = ' . time() . " -- for bumping topics with new votes, ignore for now
1035          $db->sql_query($sql);
1036  
1037          $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start"));
1038          $message = $user->lang['VOTE_SUBMITTED'] . '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>');
1039  
1040          if ($request->is_ajax())
1041          {
1042              // Filter out invalid options
1043              $valid_user_votes = array_intersect(array_keys($vote_counts), $voted_id);
1044  
1045              $data = array(
1046                  'NO_VOTES'            => $user->lang['NO_VOTES'],
1047                  'success'            => true,
1048                  'user_votes'        => array_flip($valid_user_votes),
1049                  'vote_counts'        => $vote_counts,
1050                  'total_votes'        => array_sum($vote_counts),
1051                  'can_vote'            => !count($valid_user_votes) || ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']),
1052              );
1053  
1054              /**
1055              * Event to manipulate the poll data sent by AJAX response
1056              *
1057              * @event core.viewtopic_modify_poll_ajax_data
1058              * @var    array    data                JSON response data
1059              * @var    array    valid_user_votes    Valid user votes
1060              * @var    array    vote_counts            Vote counts
1061              * @var    int        forum_id            Forum ID
1062              * @var    array    topic_data            Topic data
1063              * @var    array    poll_info            Array with the poll information
1064              * @since 3.2.4-RC1
1065              */
1066              $vars = array(
1067                  'data',
1068                  'valid_user_votes',
1069                  'vote_counts',
1070                  'forum_id',
1071                  'topic_data',
1072                  'poll_info',
1073              );
1074              extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_ajax_data', compact($vars)));
1075  
1076              $json_response = new \phpbb\json_response();
1077              $json_response->send($data);
1078          }
1079  
1080          meta_refresh(5, $redirect_url);
1081          trigger_error($message);
1082      }
1083  
1084      $poll_total = 0;
1085      $poll_most = 0;
1086      foreach ($poll_info as $poll_option)
1087      {
1088          $poll_total += $poll_option['poll_option_total'];
1089          $poll_most = ($poll_option['poll_option_total'] >= $poll_most) ? $poll_option['poll_option_total'] : $poll_most;
1090      }
1091  
1092      $parse_flags = ($poll_info[0]['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
1093  
1094      for ($i = 0, $size = count($poll_info); $i < $size; $i++)
1095      {
1096          $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);
1097      }
1098  
1099      $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);
1100  
1101      $poll_template_data = $poll_options_template_data = array();
1102      foreach ($poll_info as $poll_option)
1103      {
1104          $option_pct = ($poll_total > 0) ? $poll_option['poll_option_total'] / $poll_total : 0;
1105          $option_pct_txt = sprintf("%.1d%%", round($option_pct * 100));
1106          $option_pct_rel = ($poll_most > 0) ? $poll_option['poll_option_total'] / $poll_most : 0;
1107          $option_pct_rel_txt = sprintf("%.1d%%", round($option_pct_rel * 100));
1108          $option_most_votes = ($poll_option['poll_option_total'] > 0 && $poll_option['poll_option_total'] == $poll_most) ? true : false;
1109  
1110          $poll_options_template_data[] = array(
1111              'POLL_OPTION_ID'             => $poll_option['poll_option_id'],
1112              'POLL_OPTION_CAPTION'         => $poll_option['poll_option_text'],
1113              'POLL_OPTION_RESULT'         => $poll_option['poll_option_total'],
1114              'POLL_OPTION_PERCENT'         => $option_pct_txt,
1115              'POLL_OPTION_PERCENT_REL'     => $option_pct_rel_txt,
1116              'POLL_OPTION_PCT'            => round($option_pct * 100),
1117              'POLL_OPTION_WIDTH'         => round($option_pct * 250),
1118              'POLL_OPTION_VOTED'            => (in_array($poll_option['poll_option_id'], $cur_voted_id)) ? true : false,
1119              'POLL_OPTION_MOST_VOTES'    => $option_most_votes,
1120          );
1121      }
1122  
1123      $poll_end = $topic_data['poll_length'] + $topic_data['poll_start'];
1124  
1125      $poll_template_data = array(
1126          'POLL_QUESTION'        => $topic_data['poll_title'],
1127          'TOTAL_VOTES'         => $poll_total,
1128          'POLL_LEFT_CAP_IMG'    => $user->img('poll_left'),
1129          'POLL_RIGHT_CAP_IMG'=> $user->img('poll_right'),
1130  
1131          'L_MAX_VOTES'        => $user->lang('MAX_OPTIONS_SELECT', (int) $topic_data['poll_max_options']),
1132          'L_POLL_LENGTH'        => ($topic_data['poll_length']) ? sprintf($user->lang[($poll_end > time()) ? 'POLL_RUN_TILL' : 'POLL_ENDED_AT'], $user->format_date($poll_end)) : '',
1133  
1134          'S_HAS_POLL'        => true,
1135          'S_CAN_VOTE'        => $s_can_vote,
1136          'S_DISPLAY_RESULTS'    => $s_display_results,
1137          'S_IS_MULTI_CHOICE'    => ($topic_data['poll_max_options'] > 1) ? true : false,
1138          'S_POLL_ACTION'        => $viewtopic_url,
1139  
1140          'U_VIEW_RESULTS'    => $viewtopic_url . '&amp;view=viewpoll',
1141      );
1142  
1143      /**
1144      * Event to add/modify poll template data
1145      *
1146      * @event core.viewtopic_modify_poll_template_data
1147      * @var    array    cur_voted_id                    Array with options' IDs current user has voted for
1148      * @var    int        poll_end                        The poll end time
1149      * @var    array    poll_info                        Array with the poll information
1150      * @var    array    poll_options_template_data        Array with the poll options template data
1151      * @var    array    poll_template_data                Array with the common poll template data
1152      * @var    int        poll_total                        Total poll votes count
1153      * @var    int        poll_most                        Mostly voted option votes count
1154      * @var    array    topic_data                        All the information from the topic and forum tables for this topic
1155      * @var    string    viewtopic_url                    URL to the topic page
1156      * @var    array    vote_counts                        Array with the vote counts for every poll option
1157      * @var    array    voted_id                        Array with updated options' IDs current user is voting for
1158      * @since 3.1.5-RC1
1159      */
1160      $vars = array(
1161          'cur_voted_id',
1162          'poll_end',
1163          'poll_info',
1164          'poll_options_template_data',
1165          'poll_template_data',
1166          'poll_total',
1167          'poll_most',
1168          'topic_data',
1169          'viewtopic_url',
1170          'vote_counts',
1171          'voted_id',
1172      );
1173      extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_template_data', compact($vars)));
1174  
1175      $template->assign_block_vars_array('poll_option', $poll_options_template_data);
1176  
1177      $template->assign_vars($poll_template_data);
1178  
1179      unset($poll_end, $poll_info, $poll_options_template_data, $poll_template_data, $voted_id);
1180  }
1181  
1182  // If the user is trying to reach the second half of the topic, fetch it starting from the end
1183  $store_reverse = false;
1184  $sql_limit = $config['posts_per_page'];
1185  $sql_sort_order = $direction = '';
1186  
1187  if ($start > $total_posts / 2)
1188  {
1189      $store_reverse = true;
1190  
1191      // Select the sort order
1192      $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC');
1193  
1194      $sql_limit = $pagination->reverse_limit($start, $sql_limit, $total_posts);
1195      $sql_start = $pagination->reverse_start($start, $sql_limit, $total_posts);
1196  }
1197  else
1198  {
1199      // Select the sort order
1200      $direction = (($sort_dir == 'd') ? 'DESC' : 'ASC');
1201      $sql_start = $start;
1202  }
1203  
1204  if (is_array($sort_by_sql[$sort_key]))
1205  {
1206      $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction;
1207  }
1208  else
1209  {
1210      $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction;
1211  }
1212  
1213  // Container for user details, only process once
1214  $post_list = $user_cache = $id_cache = $attachments = $attach_list = $rowset = $update_count = $post_edit_list = $post_delete_list = array();
1215  $has_unapproved_attachments = $has_approved_attachments = $display_notice = false;
1216  $i = $i_total = 0;
1217  
1218  // Go ahead and pull all data for this topic
1219  $sql = 'SELECT p.post_id
1220      FROM ' . POSTS_TABLE . ' p' . (($join_user_sql[$sort_key]) ? ', ' . USERS_TABLE . ' u': '') . "
1221      WHERE p.topic_id = $topic_id
1222          AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . "
1223          " . (($join_user_sql[$sort_key]) ? 'AND u.user_id = p.poster_id': '') . "
1224          $limit_posts_time
1225      ORDER BY $sql_sort_order";
1226  
1227  /**
1228  * Event to modify the SQL query that gets post_list
1229  *
1230  * @event core.viewtopic_modify_post_list_sql
1231  * @var    string    sql            The SQL query to generate the post_list
1232  * @var    int        sql_limit    The number of posts the query fetches
1233  * @var    int        sql_start    The index the query starts to fetch from
1234  * @var    string    sort_key    Key the posts are sorted by
1235  * @var    string    sort_days    Display posts of previous x days
1236  * @var    int        forum_id    Forum ID
1237  * @since 3.2.4-RC1
1238  */
1239  $vars = array(
1240      'sql',
1241      'sql_limit',
1242      'sql_start',
1243      'sort_key',
1244      'sort_days',
1245      'forum_id',
1246  );
1247  extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_list_sql', compact($vars)));
1248  
1249  $result = $db->sql_query_limit($sql, $sql_limit, $sql_start);
1250  
1251  $i = ($store_reverse) ? $sql_limit - 1 : 0;
1252  while ($row = $db->sql_fetchrow($result))
1253  {
1254      $post_list[$i] = (int) $row['post_id'];
1255      ($store_reverse) ? $i-- : $i++;
1256  }
1257  $db->sql_freeresult($result);
1258  
1259  if (!count($post_list))
1260  {
1261      if ($sort_days)
1262      {
1263          trigger_error('NO_POSTS_TIME_FRAME');
1264      }
1265      else
1266      {
1267          trigger_error('NO_TOPIC');
1268      }
1269  }
1270  
1271  // Holding maximum post time for marking topic read
1272  // We need to grab it because we do reverse ordering sometimes
1273  $max_post_time = 0;
1274  
1275  $sql_ary = array(
1276      'SELECT'    => 'u.*, z.friend, z.foe, p.*',
1277  
1278      'FROM'        => array(
1279          USERS_TABLE        => 'u',
1280          POSTS_TABLE        => 'p',
1281      ),
1282  
1283      'LEFT_JOIN'    => array(
1284          array(
1285              'FROM'    => array(ZEBRA_TABLE => 'z'),
1286              'ON'    => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id',
1287          ),
1288      ),
1289  
1290      'WHERE'        => $db->sql_in_set('p.post_id', $post_list) . '
1291          AND u.user_id = p.poster_id',
1292  );
1293  
1294  /**
1295  * Event to modify the SQL query before the post and poster data is retrieved
1296  *
1297  * @event core.viewtopic_get_post_data
1298  * @var    int        forum_id    Forum ID
1299  * @var    int        topic_id    Topic ID
1300  * @var    array    topic_data    Array with topic data
1301  * @var    array    post_list    Array with post_ids we are going to retrieve
1302  * @var    int        sort_days    Display posts of previous x days
1303  * @var    string    sort_key    Key the posts are sorted by
1304  * @var    string    sort_dir    Direction the posts are sorted by
1305  * @var    int        start        Pagination information
1306  * @var    array    sql_ary        The SQL array to get the data of posts and posters
1307  * @since 3.1.0-a1
1308  * @changed 3.1.0-a2 Added vars forum_id, topic_id, topic_data, post_list, sort_days, sort_key, sort_dir, start
1309  */
1310  $vars = array(
1311      'forum_id',
1312      'topic_id',
1313      'topic_data',
1314      'post_list',
1315      'sort_days',
1316      'sort_key',
1317      'sort_dir',
1318      'start',
1319      'sql_ary',
1320  );
1321  extract($phpbb_dispatcher->trigger_event('core.viewtopic_get_post_data', compact($vars)));
1322  
1323  $sql = $db->sql_build_query('SELECT', $sql_ary);
1324  $result = $db->sql_query($sql);
1325  
1326  $now = $user->create_datetime();
1327  $now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset());
1328  
1329  // Posts are stored in the $rowset array while $attach_list, $user_cache
1330  // and the global bbcode_bitfield are built
1331  while ($row = $db->sql_fetchrow($result))
1332  {
1333      // Set max_post_time
1334      if ($row['post_time'] > $max_post_time)
1335      {
1336          $max_post_time = $row['post_time'];
1337      }
1338  
1339      $poster_id = (int) $row['poster_id'];
1340  
1341      // Does post have an attachment? If so, add it to the list
1342      if ($row['post_attachment'] && $config['allow_attachments'])
1343      {
1344          $attach_list[] = (int) $row['post_id'];
1345  
1346          if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE)
1347          {
1348              $has_unapproved_attachments = true;
1349          }
1350          else if ($row['post_visibility'] == ITEM_APPROVED)
1351          {
1352              $has_approved_attachments = true;
1353          }
1354      }
1355  
1356      $rowset_data = array(
1357          'hide_post'            => (($row['foe'] || $row['post_visibility'] == ITEM_DELETED) && ($view != 'show' || $post_id != $row['post_id'])) ? true : false,
1358  
1359          'post_id'            => $row['post_id'],
1360          'post_time'            => $row['post_time'],
1361          'user_id'            => $row['user_id'],
1362          'username'            => $row['username'],
1363          'user_colour'        => $row['user_colour'],
1364          'topic_id'            => $row['topic_id'],
1365          'forum_id'            => $row['forum_id'],
1366          'post_subject'        => $row['post_subject'],
1367          'post_edit_count'    => $row['post_edit_count'],
1368          'post_edit_time'    => $row['post_edit_time'],
1369          'post_edit_reason'    => $row['post_edit_reason'],
1370          'post_edit_user'    => $row['post_edit_user'],
1371          'post_edit_locked'    => $row['post_edit_locked'],
1372          'post_delete_time'    => $row['post_delete_time'],
1373          'post_delete_reason'=> $row['post_delete_reason'],
1374          'post_delete_user'    => $row['post_delete_user'],
1375  
1376          // Make sure the icon actually exists
1377          'icon_id'            => (isset($icons[$row['icon_id']]['img'], $icons[$row['icon_id']]['height'], $icons[$row['icon_id']]['width'])) ? $row['icon_id'] : 0,
1378          'post_attachment'    => $row['post_attachment'],
1379          'post_visibility'    => $row['post_visibility'],
1380          'post_reported'        => $row['post_reported'],
1381          'post_username'        => $row['post_username'],
1382          'post_text'            => $row['post_text'],
1383          'bbcode_uid'        => $row['bbcode_uid'],
1384          'bbcode_bitfield'    => $row['bbcode_bitfield'],
1385          'enable_smilies'    => $row['enable_smilies'],
1386          'enable_sig'        => $row['enable_sig'],
1387          'friend'            => $row['friend'],
1388          'foe'                => $row['foe'],
1389      );
1390  
1391      /**
1392      * Modify the post rowset containing data to be displayed with posts
1393      *
1394      * @event core.viewtopic_post_rowset_data
1395      * @var    array    rowset_data    Array with the rowset data for this post
1396      * @var    array    row            Array with original user and post data
1397      * @since 3.1.0-a1
1398      */
1399      $vars = array('rowset_data', 'row');
1400      extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_rowset_data', compact($vars)));
1401  
1402      $rowset[$row['post_id']] = $rowset_data;
1403  
1404      // Cache various user specific data ... so we don't have to recompute
1405      // this each time the same user appears on this page
1406      if (!isset($user_cache[$poster_id]))
1407      {
1408          if ($poster_id == ANONYMOUS)
1409          {
1410              $user_cache_data = array(
1411                  'user_type'        => USER_IGNORE,
1412                  'joined'        => '',
1413                  'posts'            => '',
1414  
1415                  'sig'                    => '',
1416                  'sig_bbcode_uid'        => '',
1417                  'sig_bbcode_bitfield'    => '',
1418  
1419                  'online'            => false,
1420                  'avatar'            => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '',
1421                  'rank_title'        => '',
1422                  'rank_image'        => '',
1423                  'rank_image_src'    => '',
1424                  'pm'                => '',
1425                  'email'                => '',
1426                  'jabber'            => '',
1427                  'search'            => '',
1428                  'age'                => '',
1429  
1430                  'username'            => $row['username'],
1431                  'user_colour'        => $row['user_colour'],
1432                  'contact_user'        => '',
1433  
1434                  'warnings'            => 0,
1435                  'allow_pm'            => 0,
1436              );
1437  
1438              /**
1439              * Modify the guest user's data displayed with the posts
1440              *
1441              * @event core.viewtopic_cache_guest_data
1442              * @var    array    user_cache_data    Array with the user's data
1443              * @var    int        poster_id        Poster's user id
1444              * @var    array    row                Array with original user and post data
1445              * @since 3.1.0-a1
1446              */
1447              $vars = array('user_cache_data', 'poster_id', 'row');
1448              extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_guest_data', compact($vars)));
1449  
1450              $user_cache[$poster_id] = $user_cache_data;
1451  
1452              $user_rank_data = phpbb_get_user_rank($row, false);
1453              $user_cache[$poster_id]['rank_title'] = $user_rank_data['title'];
1454              $user_cache[$poster_id]['rank_image'] = $user_rank_data['img'];
1455              $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src'];
1456          }
1457          else
1458          {
1459              $user_sig = '';
1460  
1461              // We add the signature to every posters entry because enable_sig is post dependent
1462              if ($row['user_sig'] && $config['allow_sig'] && $user->optionget('viewsigs'))
1463              {
1464                  $user_sig = $row['user_sig'];
1465              }
1466  
1467              $id_cache[] = $poster_id;
1468  
1469              $user_cache_data = array(
1470                  'user_type'                    => $row['user_type'],
1471                  'user_inactive_reason'        => $row['user_inactive_reason'],
1472  
1473                  'joined'        => $user->format_date($row['user_regdate']),
1474                  'posts'            => $row['user_posts'],
1475                  'warnings'        => (isset($row['user_warnings'])) ? $row['user_warnings'] : 0,
1476  
1477                  'sig'                    => $user_sig,
1478                  'sig_bbcode_uid'        => (!empty($row['user_sig_bbcode_uid'])) ? $row['user_sig_bbcode_uid'] : '',
1479                  'sig_bbcode_bitfield'    => (!empty($row['user_sig_bbcode_bitfield'])) ? $row['user_sig_bbcode_bitfield'] : '',
1480  
1481                  'viewonline'    => $row['user_allow_viewonline'],
1482                  'allow_pm'        => $row['user_allow_pm'],
1483  
1484                  'avatar'        => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '',
1485                  'age'            => '',
1486  
1487                  'rank_title'        => '',
1488                  'rank_image'        => '',
1489                  'rank_image_src'    => '',
1490  
1491                  'username'            => $row['username'],
1492                  'user_colour'        => $row['user_colour'],
1493                  'contact_user'         => $user->lang('CONTACT_USER', get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['username'])),
1494  
1495                  'online'        => false,
1496                  'jabber'        => ($config['jab_enable'] && $row['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&amp;action=jabber&amp;u=$poster_id") : '',
1497                  'search'        => ($config['load_search'] && $auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$poster_id&amp;sr=posts") : '',
1498  
1499                  'author_full'        => get_username_string('full', $poster_id, $row['username'], $row['user_colour']),
1500                  'author_colour'        => get_username_string('colour', $poster_id, $row['username'], $row['user_colour']),
1501                  'author_username'    => get_username_string('username', $poster_id, $row['username'], $row['user_colour']),
1502                  'author_profile'    => get_username_string('profile', $poster_id, $row['username'], $row['user_colour']),
1503              );
1504  
1505              /**
1506              * Modify the users' data displayed with their posts
1507              *
1508              * @event core.viewtopic_cache_user_data
1509              * @var    array    user_cache_data    Array with the user's data
1510              * @var    int        poster_id        Poster's user id
1511              * @var    array    row                Array with original user and post data
1512              * @since 3.1.0-a1
1513              */
1514              $vars = array('user_cache_data', 'poster_id', 'row');
1515              extract($phpbb_dispatcher->trigger_event('core.viewtopic_cache_user_data', compact($vars)));
1516  
1517              $user_cache[$poster_id] = $user_cache_data;
1518  
1519              $user_rank_data = phpbb_get_user_rank($row, $row['user_posts']);
1520              $user_cache[$poster_id]['rank_title'] = $user_rank_data['title'];
1521              $user_cache[$poster_id]['rank_image'] = $user_rank_data['img'];
1522              $user_cache[$poster_id]['rank_image_src'] = $user_rank_data['img_src'];
1523  
1524              if ((!empty($row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email'))
1525              {
1526                  $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']);
1527              }
1528              else
1529              {
1530                  $user_cache[$poster_id]['email'] = '';
1531              }
1532  
1533              if ($config['allow_birthdays'] && !empty($row['user_birthday']))
1534              {
1535                  list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $row['user_birthday']));
1536  
1537                  if ($bday_year)
1538                  {
1539                      $diff = $now['mon'] - $bday_month;
1540                      if ($diff == 0)
1541                      {
1542                          $diff = ($now['mday'] - $bday_day < 0) ? 1 : 0;
1543                      }
1544                      else
1545                      {
1546                          $diff = ($diff < 0) ? 1 : 0;
1547                      }
1548  
1549                      $user_cache[$poster_id]['age'] = (int) ($now['year'] - $bday_year - $diff);
1550                  }
1551              }
1552          }
1553      }
1554  }
1555  $db->sql_freeresult($result);
1556  
1557  // Load custom profile fields
1558  if ($config['load_cpf_viewtopic'])
1559  {
1560      /* @var $cp \phpbb\profilefields\manager */
1561      $cp = $phpbb_container->get('profilefields.manager');
1562  
1563      // Grab all profile fields from users in id cache for later use - similar to the poster cache
1564      $profile_fields_tmp = $cp->grab_profile_fields_data($id_cache);
1565  
1566      // filter out fields not to be displayed on viewtopic. Yes, it's a hack, but this shouldn't break any MODs.
1567      $profile_fields_cache = array();
1568      foreach ($profile_fields_tmp as $profile_user_id => $profile_fields)
1569      {
1570          $profile_fields_cache[$profile_user_id] = array();
1571          foreach ($profile_fields as $used_ident => $profile_field)
1572          {
1573              if ($profile_field['data']['field_show_on_vt'])
1574              {
1575                  $profile_fields_cache[$profile_user_id][$used_ident] = $profile_field;
1576              }
1577          }
1578      }
1579      unset($profile_fields_tmp);
1580  }
1581  
1582  // Generate online information for user
1583  if ($config['load_onlinetrack'] && count($id_cache))
1584  {
1585      $sql = 'SELECT session_user_id, MAX(session_time) as online_time, MIN(session_viewonline) AS viewonline
1586          FROM ' . SESSIONS_TABLE . '
1587          WHERE ' . $db->sql_in_set('session_user_id', $id_cache) . '
1588          GROUP BY session_user_id';
1589      $result = $db->sql_query($sql);
1590  
1591      $update_time = $config['load_online_time'] * 60;
1592      while ($row = $db->sql_fetchrow($result))
1593      {
1594          $user_cache[$row['session_user_id']]['online'] = (time() - $update_time < $row['online_time'] && (($row['viewonline']) || $auth->acl_get('u_viewonline'))) ? true : false;
1595      }
1596      $db->sql_freeresult($result);
1597  }
1598  unset($id_cache);
1599  
1600  // Pull attachment data
1601  if (count($attach_list))
1602  {
1603      if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
1604      {
1605          $sql = 'SELECT *
1606              FROM ' . ATTACHMENTS_TABLE . '
1607              WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . '
1608                  AND in_message = 0
1609              ORDER BY attach_id DESC, post_msg_id ASC';
1610          $result = $db->sql_query($sql);
1611  
1612          while ($row = $db->sql_fetchrow($result))
1613          {
1614              $attachments[$row['post_msg_id']][] = $row;
1615          }
1616          $db->sql_freeresult($result);
1617  
1618          // No attachments exist, but post table thinks they do so go ahead and reset post_attach flags
1619          if (!count($attachments))
1620          {
1621              $sql = 'UPDATE ' . POSTS_TABLE . '
1622                  SET post_attachment = 0
1623                  WHERE ' . $db->sql_in_set('post_id', $attach_list);
1624              $db->sql_query($sql);
1625  
1626              // We need to update the topic indicator too if the complete topic is now without an attachment
1627              if (count($rowset) != $total_posts)
1628              {
1629                  // Not all posts are displayed so we query the db to find if there's any attachment for this topic
1630                  $sql = 'SELECT a.post_msg_id as post_id
1631                      FROM ' . ATTACHMENTS_TABLE . ' a, ' . POSTS_TABLE . " p
1632                      WHERE p.topic_id = $topic_id
1633                          AND p.post_visibility = " . ITEM_APPROVED . '
1634                          AND p.topic_id = a.topic_id';
1635                  $result = $db->sql_query_limit($sql, 1);
1636                  $row = $db->sql_fetchrow($result);
1637                  $db->sql_freeresult($result);
1638  
1639                  if (!$row)
1640                  {
1641                      $sql = 'UPDATE ' . TOPICS_TABLE . "
1642                          SET topic_attachment = 0
1643                          WHERE topic_id = $topic_id";
1644                      $db->sql_query($sql);
1645                  }
1646              }
1647              else
1648              {
1649                  $sql = 'UPDATE ' . TOPICS_TABLE . "
1650                      SET topic_attachment = 0
1651                      WHERE topic_id = $topic_id";
1652                  $db->sql_query($sql);
1653              }
1654          }
1655          else if ($has_approved_attachments && !$topic_data['topic_attachment'])
1656          {
1657              // Topic has approved attachments but its flag is wrong
1658              $sql = 'UPDATE ' . TOPICS_TABLE . "
1659                  SET topic_attachment = 1
1660                  WHERE topic_id = $topic_id";
1661              $db->sql_query($sql);
1662  
1663              $topic_data['topic_attachment'] = 1;
1664          }
1665          else if ($has_unapproved_attachments && !$topic_data['topic_attachment'])
1666          {
1667              // Topic has only unapproved attachments but we have the right to see and download them
1668              $topic_data['topic_attachment'] = 1;
1669          }
1670      }
1671      else
1672      {
1673          $display_notice = true;
1674      }
1675  }
1676  
1677  if ($config['enable_accurate_pm_button'])
1678  {
1679      // Get the list of users who can receive private messages
1680      $can_receive_pm_list = $auth->acl_get_list(array_keys($user_cache), 'u_readpm');
1681      $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'];
1682  
1683      // Get the list of permanently banned users
1684      $permanently_banned_users = phpbb_get_banned_user_ids(array_keys($user_cache), false);
1685  }
1686  else
1687  {
1688      $can_receive_pm_list = array_keys($user_cache);
1689      $permanently_banned_users = [];
1690  }
1691  
1692  $i_total = count($rowset) - 1;
1693  $prev_post_id = '';
1694  
1695  $template->assign_vars(array(
1696      'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'],
1697      'S_NUM_POSTS' => count($post_list))
1698  );
1699  
1700  /**
1701  * Event to modify the post, poster and attachment data before assigning the posts
1702  *
1703  * @event core.viewtopic_modify_post_data
1704  * @var    int        forum_id    Forum ID
1705  * @var    int        topic_id    Topic ID
1706  * @var    array    topic_data    Array with topic data
1707  * @var    array    post_list    Array with post_ids we are going to display
1708  * @var    array    rowset        Array with post_id => post data
1709  * @var    array    user_cache    Array with prepared user data
1710  * @var    int        start        Pagination information
1711  * @var    int        sort_days    Display posts of previous x days
1712  * @var    string    sort_key    Key the posts are sorted by
1713  * @var    string    sort_dir    Direction the posts are sorted by
1714  * @var    bool    display_notice                Shall we display a notice instead of attachments
1715  * @var    bool    has_approved_attachments    Does the topic have approved attachments
1716  * @var    array    attachments                    List of attachments post_id => array of attachments
1717  * @var    array    permanently_banned_users    List of permanently banned users
1718  * @var    array    can_receive_pm_list            Array with posters that can receive pms
1719  * @since 3.1.0-RC3
1720  */
1721  $vars = array(
1722      'forum_id',
1723      'topic_id',
1724      'topic_data',
1725      'post_list',
1726      'rowset',
1727      'user_cache',
1728      'sort_days',
1729      'sort_key',
1730      'sort_dir',
1731      'start',
1732      'permanently_banned_users',
1733      'can_receive_pm_list',
1734      'display_notice',
1735      'has_approved_attachments',
1736      'attachments',
1737  );
1738  extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_data', compact($vars)));
1739  
1740  // Output the posts
1741  $first_unread = $post_unread = false;
1742  for ($i = 0, $end = count($post_list); $i < $end; ++$i)
1743  {
1744      // A non-existing rowset only happens if there was no user present for the entered poster_id
1745      // This could be a broken posts table.
1746      if (!isset($rowset[$post_list[$i]]))
1747      {
1748          continue;
1749      }
1750  
1751      $row = $rowset[$post_list[$i]];
1752      $poster_id = $row['user_id'];
1753  
1754      // End signature parsing, only if needed
1755      if ($user_cache[$poster_id]['sig'] && $row['enable_sig'] && empty($user_cache[$poster_id]['sig_parsed']))
1756      {
1757          $parse_flags = ($user_cache[$poster_id]['sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
1758          $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);
1759          $user_cache[$poster_id]['sig_parsed'] = true;
1760      }
1761  
1762      // Parse the message and subject
1763      $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
1764      $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true);
1765  
1766      if (!empty($attachments[$row['post_id']]))
1767      {
1768          parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count);
1769      }
1770  
1771      // Replace naughty words such as farty pants
1772      $row['post_subject'] = censor_text($row['post_subject']);
1773  
1774      // Highlight active words (primarily for search)
1775      if ($highlight_match)
1776      {
1777          $message = preg_replace('#(?!<.*)(?<!\w)(' . $highlight_match . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#is', '<span class="posthilit">\1</span>', $message);
1778          $row['post_subject'] = preg_replace('#(?!<.*)(?<!\w)(' . $highlight_match . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#is', '<span class="posthilit">\1</span>', $row['post_subject']);
1779      }
1780  
1781      // Editing information
1782      if (($row['post_edit_count'] && $config['display_last_edited']) || $row['post_edit_reason'])
1783      {
1784          // Get usernames for all following posts if not already stored
1785          if (!count($post_edit_list) && ($row['post_edit_reason'] || ($row['post_edit_user'] && !isset($user_cache[$row['post_edit_user']]))))
1786          {
1787              // Remove all post_ids already parsed (we do not have to check them)
1788              $post_storage_list = (!$store_reverse) ? array_slice($post_list, $i) : array_slice(array_reverse($post_list), $i);
1789  
1790              $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour
1791                  FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1792                  WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . '
1793                      AND p.post_edit_count <> 0
1794                      AND p.post_edit_user <> 0
1795                      AND p.post_edit_user = u.user_id';
1796              $result2 = $db->sql_query($sql);
1797              while ($user_edit_row = $db->sql_fetchrow($result2))
1798              {
1799                  $post_edit_list[$user_edit_row['user_id']] = $user_edit_row;
1800              }
1801              $db->sql_freeresult($result2);
1802  
1803              unset($post_storage_list);
1804          }
1805  
1806          if ($row['post_edit_reason'])
1807          {
1808              // User having edited the post also being the post author?
1809              if (!$row['post_edit_user'] || $row['post_edit_user'] == $poster_id)
1810              {
1811                  $display_username = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']);
1812              }
1813              else
1814              {
1815                  $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']);
1816              }
1817  
1818              $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true));
1819          }
1820          else
1821          {
1822              if ($row['post_edit_user'] && !isset($user_cache[$row['post_edit_user']]))
1823              {
1824                  $user_cache[$row['post_edit_user']] = $post_edit_list[$row['post_edit_user']];
1825              }
1826  
1827              // User having edited the post also being the post author?
1828              if (!$row['post_edit_user'] || $row['post_edit_user'] == $poster_id)
1829              {
1830                  $display_username = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']);
1831              }
1832              else
1833              {
1834                  $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']);
1835              }
1836  
1837              $l_edited_by = $user->lang('EDITED_TIMES_TOTAL', (int) $row['post_edit_count'], $display_username, $user->format_date($row['post_edit_time'], false, true));
1838          }
1839      }
1840      else
1841      {
1842          $l_edited_by = '';
1843      }
1844  
1845      // Deleting information
1846      if ($row['post_visibility'] == ITEM_DELETED && $row['post_delete_user'])
1847      {
1848          // Get usernames for all following posts if not already stored
1849          if (!count($post_delete_list) && ($row['post_delete_reason'] || ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']]))))
1850          {
1851              // Remove all post_ids already parsed (we do not have to check them)
1852              $post_storage_list = (!$store_reverse) ? array_slice($post_list, $i) : array_slice(array_reverse($post_list), $i);
1853  
1854              $sql = 'SELECT DISTINCT u.user_id, u.username, u.user_colour
1855                  FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1856                  WHERE ' . $db->sql_in_set('p.post_id', $post_storage_list) . '
1857                      AND p.post_delete_user <> 0
1858                      AND p.post_delete_user = u.user_id';
1859              $result2 = $db->sql_query($sql);
1860              while ($user_delete_row = $db->sql_fetchrow($result2))
1861              {
1862                  $post_delete_list[$user_delete_row['user_id']] = $user_delete_row;
1863              }
1864              $db->sql_freeresult($result2);
1865  
1866              unset($post_storage_list);
1867          }
1868  
1869          if ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']]))
1870          {
1871              $user_cache[$row['post_delete_user']] = $post_delete_list[$row['post_delete_user']];
1872          }
1873  
1874          $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']);
1875  
1876          // User having deleted the post also being the post author?
1877          if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id)
1878          {
1879              $display_username = $display_postername;
1880          }
1881          else
1882          {
1883              $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']);
1884          }
1885  
1886          if ($row['post_delete_reason'])
1887          {
1888              $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']);
1889          }
1890          else
1891          {
1892              $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true));
1893          }
1894          $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($row['post_delete_time'], false, true));
1895      }
1896      else
1897      {
1898          $l_deleted_by = $l_deleted_message = '';
1899      }
1900  
1901      // Bump information
1902      if ($topic_data['topic_bumped'] && $row['post_id'] == $topic_data['topic_last_post_id'] && isset($user_cache[$topic_data['topic_bumper']]) )
1903      {
1904          // It is safe to grab the username from the user cache array, we are at the last
1905          // post and only the topic poster and last poster are allowed to bump.
1906          // Admins and mods are bound to the above rules too...
1907          $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));
1908      }
1909      else
1910      {
1911          $l_bumped_by = '';
1912      }
1913  
1914      $cp_row = array();
1915  
1916      //
1917      if ($config['load_cpf_viewtopic'])
1918      {
1919          $cp_row = (isset($profile_fields_cache[$poster_id])) ? $cp->generate_profile_fields_template_data($profile_fields_cache[$poster_id]) : array();
1920      }
1921  
1922      $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false;
1923  
1924      $s_first_unread = false;
1925      if (!$first_unread && $post_unread)
1926      {
1927          $s_first_unread = $first_unread = true;
1928      }
1929  
1930      $force_edit_allowed = $force_delete_allowed = $force_softdelete_allowed = false;
1931  
1932      $s_cannot_edit = !$auth->acl_get('f_edit', $forum_id) || $user->data['user_id'] != $poster_id;
1933      $s_cannot_edit_time = $config['edit_time'] && $row['post_time'] <= time() - ($config['edit_time'] * 60);
1934      $s_cannot_edit_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked'];
1935  
1936      $s_cannot_delete = $user->data['user_id'] != $poster_id || (
1937              !$auth->acl_get('f_delete', $forum_id) &&
1938              (!$auth->acl_get('f_softdelete', $forum_id) || $row['post_visibility'] == ITEM_DELETED)
1939      );
1940      $s_cannot_delete_lastpost = $topic_data['topic_last_post_id'] != $row['post_id'];
1941      $s_cannot_delete_time = $config['delete_time'] && $row['post_time'] <= time() - ($config['delete_time'] * 60);
1942      // we do not want to allow removal of the last post if a moderator locked it!
1943      $s_cannot_delete_locked = $topic_data['topic_status'] == ITEM_LOCKED || $row['post_edit_locked'];
1944  
1945      /**
1946      * This event allows you to modify the conditions for the "can edit post" and "can delete post" checks
1947      *
1948      * @event core.viewtopic_modify_post_action_conditions
1949      * @var    array    row            Array with post data
1950      * @var    array    topic_data    Array with topic data
1951      * @var    bool    force_edit_allowed        Allow the user to edit the post (all permissions and conditions are ignored)
1952      * @var    bool    s_cannot_edit            User can not edit the post because it's not his
1953      * @var    bool    s_cannot_edit_locked    User can not edit the post because it's locked
1954      * @var    bool    s_cannot_edit_time        User can not edit the post because edit_time has passed
1955      * @var    bool    force_delete_allowed        Allow the user to delete the post (all permissions and conditions are ignored)
1956      * @var    bool    s_cannot_delete                User can not delete the post because it's not his
1957      * @var    bool    s_cannot_delete_lastpost    User can not delete the post because it's not the last post of the topic
1958      * @var    bool    s_cannot_delete_locked        User can not delete the post because it's locked
1959      * @var    bool    s_cannot_delete_time        User can not delete the post because edit_time has passed
1960      * @var    bool    force_softdelete_allowed    Allow the user to —čoftdelete the post (all permissions and conditions are ignored)
1961      * @since 3.1.0-b4
1962      * @changed 3.1.11-RC1 Added force_softdelete_allowed var
1963      */
1964      $vars = array(
1965          'row',
1966          'topic_data',
1967          'force_edit_allowed',
1968          's_cannot_edit',
1969          's_cannot_edit_locked',
1970          's_cannot_edit_time',
1971          'force_delete_allowed',
1972          's_cannot_delete',
1973          's_cannot_delete_lastpost',
1974          's_cannot_delete_locked',
1975          's_cannot_delete_time',
1976          'force_softdelete_allowed',
1977      );
1978      extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_action_conditions', compact($vars)));
1979  
1980      $edit_allowed = $force_edit_allowed || ($user->data['is_registered'] && ($auth->acl_get('m_edit', $forum_id) || (
1981          !$s_cannot_edit &&
1982          !$s_cannot_edit_time &&
1983          !$s_cannot_edit_locked
1984      )));
1985  
1986      $quote_allowed = $auth->acl_get('m_edit', $forum_id) || ($topic_data['topic_status'] != ITEM_LOCKED &&
1987          ($user->data['user_id'] == ANONYMOUS || $auth->acl_get('f_reply', $forum_id))
1988      );
1989  
1990      // Only display the quote button if the post is quotable.  Posts not approved are not quotable.
1991      $quote_allowed = ($quote_allowed && $row['post_visibility'] == ITEM_APPROVED) ? true : false;
1992  
1993      $delete_allowed = $force_delete_allowed || ($user->data['is_registered'] && (
1994          ($auth->acl_get('m_delete', $forum_id) || ($auth->acl_get('m_softdelete', $forum_id) && $row['post_visibility'] != ITEM_DELETED)) ||
1995          (!$s_cannot_delete && !$s_cannot_delete_lastpost && !$s_cannot_delete_time && !$s_cannot_delete_locked)
1996      ));
1997  
1998      $softdelete_allowed = $force_softdelete_allowed || (($auth->acl_get('m_softdelete', $forum_id) ||
1999          ($auth->acl_get('f_softdelete', $forum_id) && $user->data['user_id'] == $poster_id)) && ($row['post_visibility'] != ITEM_DELETED));
2000  
2001      $permanent_delete_allowed = $force_delete_allowed || ($auth->acl_get('m_delete', $forum_id) ||
2002          ($auth->acl_get('f_delete', $forum_id) && $user->data['user_id'] == $poster_id));
2003  
2004      // Can this user receive a Private Message?
2005      $can_receive_pm = (
2006          // They must be a "normal" user
2007          $user_cache[$poster_id]['user_type'] != USER_IGNORE &&
2008  
2009          // They must not be deactivated by the administrator
2010          ($user_cache[$poster_id]['user_type'] != USER_INACTIVE || $user_cache[$poster_id]['user_inactive_reason'] != INACTIVE_MANUAL) &&
2011  
2012          // They must be able to read PMs
2013          in_array($poster_id, $can_receive_pm_list) &&
2014  
2015          // They must not be permanently banned
2016          !in_array($poster_id, $permanently_banned_users) &&
2017  
2018          // They must allow users to contact via PM
2019          (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $user_cache[$poster_id]['allow_pm'])
2020      );
2021  
2022      $u_pm = '';
2023  
2024      if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm)
2025      {
2026          $u_pm = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;mode=compose&amp;action=quotepost&amp;p=' . $row['post_id']);
2027      }
2028  
2029      //
2030      $post_row = array(
2031          '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']),
2032          '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']),
2033          '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']),
2034          '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']),
2035  
2036          'RANK_TITLE'        => $user_cache[$poster_id]['rank_title'],
2037          'RANK_IMG'            => $user_cache[$poster_id]['rank_image'],
2038          'RANK_IMG_SRC'        => $user_cache[$poster_id]['rank_image_src'],
2039          'POSTER_JOINED'        => $user_cache[$poster_id]['joined'],
2040          'POSTER_POSTS'        => $user_cache[$poster_id]['posts'],
2041          'POSTER_AVATAR'        => $user_cache[$poster_id]['avatar'],
2042          'POSTER_WARNINGS'    => $auth->acl_get('m_warn') ? $user_cache[$poster_id]['warnings'] : '',
2043          'POSTER_AGE'        => $user_cache[$poster_id]['age'],
2044          'CONTACT_USER'        => $user_cache[$poster_id]['contact_user'],
2045  
2046          'POST_DATE'            => $user->format_date($row['post_time'], false, ($view == 'print') ? true : false),
2047          'POST_DATE_RFC3339'    => gmdate(DATE_RFC3339, $row['post_time']),
2048          'POST_SUBJECT'        => $row['post_subject'],
2049          'MESSAGE'            => $message,
2050          'SIGNATURE'            => ($row['enable_sig']) ? $user_cache[$poster_id]['sig'] : '',
2051          'EDITED_MESSAGE'    => $l_edited_by,
2052          'EDIT_REASON'        => $row['post_edit_reason'],
2053          'DELETED_MESSAGE'    => $l_deleted_by,
2054          'DELETE_REASON'        => $row['post_delete_reason'],
2055          'BUMPED_MESSAGE'    => $l_bumped_by,
2056  
2057          'MINI_POST_IMG'            => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'),
2058          'POST_ICON_IMG'            => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['img'] : '',
2059          'POST_ICON_IMG_WIDTH'    => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['width'] : '',
2060          'POST_ICON_IMG_HEIGHT'    => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['height'] : '',
2061          'POST_ICON_IMG_ALT'     => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['alt'] : '',
2062          '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')),
2063          'S_ONLINE'                => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? false : (($user_cache[$poster_id]['online']) ? true : false),
2064  
2065          'U_EDIT'            => ($edit_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&amp;f=$forum_id&amp;p={$row['post_id']}") : '',
2066          'U_QUOTE'            => ($quote_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=quote&amp;f=$forum_id&amp;p={$row['post_id']}") : '',
2067          '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) : '',
2068          'U_DELETE'            => ($delete_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=' . (($softdelete_allowed) ? 'soft_delete' : 'delete') . "&amp;f=$forum_id&amp;p={$row['post_id']}") : '',
2069  
2070          'U_SEARCH'        => $user_cache[$poster_id]['search'],
2071          'U_PM'            => $u_pm,
2072          'U_EMAIL'        => $user_cache[$poster_id]['email'],
2073          'U_JABBER'        => $user_cache[$poster_id]['jabber'],
2074  
2075          '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']))),
2076          'U_REPORT'            => ($auth->acl_get('f_report', $forum_id)) ? $phpbb_container->get('controller.helper')->route('phpbb_report_post_controller', array('id' => $row['post_id'])) : '',
2077          '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) : '',
2078          '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) : '',
2079          '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) : '',
2080          'U_MINI_POST'        => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'],
2081          'U_NEXT_POST_ID'    => ($i < $i_total && isset($rowset[$post_list[$i + 1]])) ? $rowset[$post_list[$i + 1]]['post_id'] : '',
2082          'U_PREV_POST_ID'    => $prev_post_id,
2083          'U_NOTES'            => ($auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&amp;mode=user_notes&amp;u=' . $poster_id, true, $user->session_id) : '',
2084          'U_WARN'            => ($auth->acl_get('m_warn') && $poster_id != $user->data['user_id'] && $poster_id != ANONYMOUS) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&amp;mode=warn_post&amp;f=' . $forum_id . '&amp;p=' . $row['post_id'], true, $user->session_id) : '',
2085  
2086          'POST_ID'            => $row['post_id'],
2087          'POST_NUMBER'        => $i + $start + 1,
2088          'POSTER_ID'            => $poster_id,
2089          'MINI_POST'            => ($post_unread) ? $user->lang['UNREAD_POST'] : $user->lang['POST'],
2090  
2091  
2092          'S_HAS_ATTACHMENTS'    => (!empty($attachments[$row['post_id']])) ? true : false,
2093          'S_MULTIPLE_ATTACHMENTS'    => !empty($attachments[$row['post_id']]) && count($attachments[$row['post_id']]) > 1,
2094          'S_POST_UNAPPROVED'    => ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) ? true : false,
2095          'S_CAN_APPROVE'        => $auth->acl_get('m_approve', $forum_id),
2096          'S_POST_DELETED'    => ($row['post_visibility'] == ITEM_DELETED) ? true : false,
2097          'L_POST_DELETED_MESSAGE'    => $l_deleted_message,
2098          'S_POST_REPORTED'    => ($row['post_reported'] && $auth->acl_get('m_report', $forum_id)) ? true : false,
2099          'S_DISPLAY_NOTICE'    => $display_notice && $row['post_attachment'],
2100          'S_FRIEND'            => ($row['friend']) ? true : false,
2101          'S_UNREAD_POST'        => $post_unread,
2102          'S_FIRST_UNREAD'    => $s_first_unread,
2103          'S_CUSTOM_FIELDS'    => (isset($cp_row['row']) && count($cp_row['row'])) ? true : false,
2104          'S_TOPIC_POSTER'    => ($topic_data['topic_poster'] == $poster_id) ? true : false,
2105          'S_FIRST_POST'        => ($topic_data['topic_first_post_id'] == $row['post_id']) ? true : false,
2106  
2107          'S_IGNORE_POST'        => ($row['foe']) ? true : false,
2108          'L_IGNORE_POST'        => ($row['foe']) ? sprintf($user->lang['POST_BY_FOE'], get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '',
2109          'S_POST_HIDDEN'        => $row['hide_post'],
2110          '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>') : '',
2111          'S_DELETE_PERMANENT'    => $permanent_delete_allowed,
2112      );
2113  
2114      $user_poster_data = $user_cache[$poster_id];
2115  
2116      $current_row_number = $i;
2117  
2118      /**
2119      * Modify the posts template block
2120      *
2121      * @event core.viewtopic_modify_post_row
2122      * @var    int        start                Start item of this page
2123      * @var    int        current_row_number    Number of the post on this page
2124      * @var    int        end                    Number of posts on this page
2125      * @var    int        total_posts            Total posts count
2126      * @var    int        poster_id            Post author id
2127      * @var    array    row                    Array with original post and user data
2128      * @var    array    cp_row                Custom profile field data of the poster
2129      * @var    array    attachments            List of attachments
2130      * @var    array    user_poster_data    Poster's data from user cache
2131      * @var    array    post_row            Template block array of the post
2132      * @var    array    topic_data            Array with topic data
2133      * @var    array    user_cache            Array with cached user data
2134      * @var    array    post_edit_list        Array with post edited list
2135      * @since 3.1.0-a1
2136      * @changed 3.1.0-a3 Added vars start, current_row_number, end, attachments
2137      * @changed 3.1.0-b3 Added topic_data array, total_posts
2138      * @changed 3.1.0-RC3 Added poster_id
2139      * @changed 3.2.2-RC1 Added user_cache and post_edit_list
2140      */
2141      $vars = array(
2142          'start',
2143          'current_row_number',
2144          'end',
2145          'total_posts',
2146          'poster_id',
2147          'row',
2148          'cp_row',
2149          'attachments',
2150          'user_poster_data',
2151          'post_row',
2152          'topic_data',
2153          'user_cache',
2154          'post_edit_list',
2155      );
2156      extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_row', compact($vars)));
2157  
2158      $i = $current_row_number;
2159  
2160      if (isset($cp_row['row']) && count($cp_row['row']))
2161      {
2162          $post_row = array_merge($post_row, $cp_row['row']);
2163      }
2164  
2165      // Dump vars into template
2166      $template->assign_block_vars('postrow', $post_row);
2167  
2168      $contact_fields = array(
2169          array(
2170              'ID'        => 'pm',
2171              'NAME'         => $user->lang['SEND_PRIVATE_MESSAGE'],
2172              'U_CONTACT'    => $post_row['U_PM'],
2173          ),
2174          array(
2175              'ID'        => 'email',
2176              'NAME'        => $user->lang['SEND_EMAIL'],
2177              'U_CONTACT'    => $user_cache[$poster_id]['email'],
2178          ),
2179          array(
2180              'ID'        => 'jabber',
2181              'NAME'        => $user->lang['JABBER'],
2182              'U_CONTACT'    => $user_cache[$poster_id]['jabber'],
2183          ),
2184      );
2185  
2186      foreach ($contact_fields as $field)
2187      {
2188          if ($field['U_CONTACT'])
2189          {
2190              $template->assign_block_vars('postrow.contact', $field);
2191          }
2192      }
2193  
2194      if (!empty($cp_row['blockrow']))
2195      {
2196          foreach ($cp_row['blockrow'] as $field_data)
2197          {
2198              $template->assign_block_vars('postrow.custom_fields', $field_data);
2199  
2200              if ($field_data['S_PROFILE_CONTACT'])
2201              {
2202                  $template->assign_block_vars('postrow.contact', array(
2203                      'ID'        => $field_data['PROFILE_FIELD_IDENT'],
2204                      'NAME'        => $field_data['PROFILE_FIELD_NAME'],
2205                      'U_CONTACT'    => $field_data['PROFILE_FIELD_CONTACT'],
2206                  ));
2207              }
2208          }
2209      }
2210  
2211      // Display not already displayed Attachments for this post, we already parsed them. ;)
2212      if (!empty($attachments[$row['post_id']]))
2213      {
2214          foreach ($attachments[$row['post_id']] as $attachment)
2215          {
2216              $template->assign_block_vars('postrow.attachment', array(
2217                  'DISPLAY_ATTACHMENT'    => $attachment)
2218              );
2219          }
2220      }
2221  
2222      $current_row_number = $i;
2223  
2224      /**
2225      * Event after the post data has been assigned to the template
2226      *
2227      * @event core.viewtopic_post_row_after
2228      * @var    int        start                Start item of this page
2229      * @var    int        current_row_number    Number of the post on this page
2230      * @var    int        end                    Number of posts on this page
2231      * @var    int        total_posts            Total posts count
2232      * @var    array    row                    Array with original post and user data
2233      * @var    array    cp_row                Custom profile field data of the poster
2234      * @var    array    attachments            List of attachments
2235      * @var    array    user_poster_data    Poster's data from user cache
2236      * @var    array    post_row            Template block array of the post
2237      * @var    array    topic_data            Array with topic data
2238      * @since 3.1.0-a3
2239      * @changed 3.1.0-b3 Added topic_data array, total_posts
2240      */
2241      $vars = array(
2242          'start',
2243          'current_row_number',
2244          'end',
2245          'total_posts',
2246          'row',
2247          'cp_row',
2248          'attachments',
2249          'user_poster_data',
2250          'post_row',
2251          'topic_data',
2252      );
2253      extract($phpbb_dispatcher->trigger_event('core.viewtopic_post_row_after', compact($vars)));
2254  
2255      $i = $current_row_number;
2256  
2257      $prev_post_id = $row['post_id'];
2258  
2259      unset($rowset[$post_list[$i]]);
2260      unset($attachments[$row['post_id']]);
2261  }
2262  unset($rowset, $user_cache);
2263  
2264  // Update topic view and if necessary attachment view counters ... but only for humans and if this is the first 'page view'
2265  if (isset($user->data['session_page']) && !$user->data['is_bot'] && (strpos($user->data['session_page'], '&t=' . $topic_id) === false || isset($user->data['session_created'])))
2266  {
2267      $sql = 'UPDATE ' . TOPICS_TABLE . '
2268          SET topic_views = topic_views + 1, topic_last_view_time = ' . time() . "
2269          WHERE topic_id = $topic_id";
2270      $db->sql_query($sql);
2271  
2272      // Update the attachment download counts
2273      if (count($update_count))
2274      {
2275          $sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
2276              SET download_count = download_count + 1
2277              WHERE ' . $db->sql_in_set('attach_id', array_unique($update_count));
2278          $db->sql_query($sql);
2279      }
2280  }
2281  
2282  // Only mark topic if it's currently unread. Also make sure we do not set topic tracking back if earlier pages are viewed.
2283  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])
2284  {
2285      markread('topic', $forum_id, $topic_id, $max_post_time);
2286  
2287      // Update forum info
2288      $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);
2289  }
2290  else
2291  {
2292      $all_marked_read = true;
2293  }
2294  
2295  // If there are absolutely no more unread posts in this forum
2296  // and unread posts shown, we can safely show the #unread link
2297  if ($all_marked_read)
2298  {
2299      if ($post_unread)
2300      {
2301          $template->assign_vars(array(
2302              'U_VIEW_UNREAD_POST'    => '#unread',
2303          ));
2304      }
2305      else if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id])
2306      {
2307          $template->assign_vars(array(
2308              'U_VIEW_UNREAD_POST'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;view=unread") . '#unread',
2309          ));
2310      }
2311  }
2312  else if (!$all_marked_read)
2313  {
2314      $last_page = ((floor($start / $config['posts_per_page']) + 1) == max(ceil($total_posts / $config['posts_per_page']), 1)) ? true : false;
2315  
2316      // What can happen is that we are at the last displayed page. If so, we also display the #unread link based in $post_unread
2317      if ($last_page && $post_unread)
2318      {
2319          $template->assign_vars(array(
2320              'U_VIEW_UNREAD_POST'    => '#unread',
2321          ));
2322      }
2323      else if (!$last_page)
2324      {
2325          $template->assign_vars(array(
2326              'U_VIEW_UNREAD_POST'    => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;view=unread") . '#unread',
2327          ));
2328      }
2329  }
2330  
2331  // let's set up quick_reply
2332  $s_quick_reply = false;
2333  if ($user->data['is_registered'] && $config['allow_quick_reply'] && ($topic_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) && $auth->acl_get('f_reply', $forum_id))
2334  {
2335      // Quick reply enabled forum
2336      $s_quick_reply = (($topic_data['forum_status'] == ITEM_UNLOCKED && $topic_data['topic_status'] == ITEM_UNLOCKED) || $auth->acl_get('m_edit', $forum_id)) ? true : false;
2337  }
2338  
2339  if ($s_can_vote || $s_quick_reply)
2340  {
2341      add_form_key('posting');
2342  
2343      if ($s_quick_reply)
2344      {
2345          $s_attach_sig    = $config['allow_sig'] && $user->optionget('attachsig') && $auth->acl_get('f_sigs', $forum_id) && $auth->acl_get('u_sig');
2346          $s_smilies        = $config['allow_smilies'] && $user->optionget('smilies') && $auth->acl_get('f_smilies', $forum_id);
2347          $s_bbcode        = $config['allow_bbcode'] && $user->optionget('bbcode') && $auth->acl_get('f_bbcode', $forum_id);
2348          $s_notify        = $config['allow_topic_notify'] && ($user->data['user_notify'] || $s_watching_topic['is_watching']);
2349  
2350          $qr_hidden_fields = array(
2351              'topic_cur_post_id'        => (int) $topic_data['topic_last_post_id'],
2352              'topic_id'                => (int) $topic_data['topic_id'],
2353              'forum_id'                => (int) $forum_id,
2354          );
2355  
2356          // Originally we use checkboxes and check with isset(), so we only provide them if they would be checked
2357          (!$s_bbcode)                    ? $qr_hidden_fields['disable_bbcode'] = 1        : true;
2358          (!$s_smilies)                    ? $qr_hidden_fields['disable_smilies'] = 1        : true;
2359          (!$config['allow_post_links'])    ? $qr_hidden_fields['disable_magic_url'] = 1    : true;
2360          ($s_attach_sig)                    ? $qr_hidden_fields['attach_sig'] = 1            : true;
2361          ($s_notify)                        ? $qr_hidden_fields['notify'] = 1                : true;
2362          ($topic_data['topic_status'] == ITEM_LOCKED) ? $qr_hidden_fields['lock_topic'] = 1 : true;
2363  
2364          $tpl_ary = [
2365              'S_QUICK_REPLY'            => true,
2366              'U_QR_ACTION'            => append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&amp;f=$forum_id&amp;t=$topic_id"),
2367              'QR_HIDDEN_FIELDS'        => build_hidden_fields($qr_hidden_fields),
2368              'SUBJECT'                => 'Re: ' . censor_text($topic_data['topic_title']),
2369          ];
2370  
2371          /**
2372          * Event after the quick-reply has been setup
2373          *
2374          * @event core.viewtopic_modify_quick_reply_template_vars
2375          * @var    array    tpl_ary            Array with template data
2376          * @var    array    topic_data        Array with topic data
2377          * @since 3.2.9-RC1
2378          */
2379          $vars = ['tpl_ary', 'topic_data'];
2380          extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_quick_reply_template_vars', compact($vars)));
2381  
2382          $template->assign_vars($tpl_ary);
2383      }
2384  }
2385  // now I have the urge to wash my hands :(
2386  
2387  
2388  // We overwrite $_REQUEST['f'] if there is no forum specified
2389  // to be able to display the correct online list.
2390  // One downside is that the user currently viewing this topic/post is not taken into account.
2391  if (!$request->variable('f', 0))
2392  {
2393      $request->overwrite('f', $forum_id);
2394  }
2395  
2396  // We need to do the same with the topic_id. See #53025.
2397  if (!$request->variable('t', 0) && !empty($topic_id))
2398  {
2399      $request->overwrite('t', $topic_id);
2400  }
2401  
2402  $page_title = $topic_data['topic_title'] . ($start ? ' - ' . sprintf($user->lang['PAGE_TITLE_NUMBER'], $pagination->get_on_page($config['posts_per_page'], $start)) : '');
2403  
2404  /**
2405  * You can use this event to modify the page title of the viewtopic page
2406  *
2407  * @event core.viewtopic_modify_page_title
2408  * @var    string    page_title        Title of the viewtopic page
2409  * @var    array    topic_data        Array with topic data
2410  * @var    int        forum_id        Forum ID of the topic
2411  * @var    int        start            Start offset used to calculate the page
2412  * @var    array    post_list        Array with post_ids we are going to display
2413  * @since 3.1.0-a1
2414  * @changed 3.1.0-RC4 Added post_list var
2415  */
2416  $vars = array('page_title', 'topic_data', 'forum_id', 'start', 'post_list');
2417  extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_page_title', compact($vars)));
2418  
2419  // Output the page
2420  page_header($page_title, true, $forum_id);
2421  
2422  $template->set_filenames(array(
2423      'body' => ($view == 'print') ? 'viewtopic_print.html' : 'viewtopic_body.html')
2424  );
2425  make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_id);
2426  
2427  page_footer();


Generated: Tue Apr 7 19:44:41 2020 Cross-referenced by PHPXref 0.7.1